The problem
You hit an error. The stack trace is forty lines of framework internals, your actual code appears once near the bottom, and the message says something like 'NoneType' object is not subscriptable. You know what broke. You don't know why, and you don't know which of the six plausible reasons to check first.
The default move is to paste the error into a search box and read five forum threads, three of which are about a different version of the library. AI is genuinely good at the narrower job: looking at your trace plus your code and ranking the likely causes so you check the most probable one first. It is not good at being certain. The trick is a prompt that forces ranking and a concrete next action, instead of inviting a confident-sounding guess.
When to use this β and when not to
Use it when:
- You have a real error and the trace mentions your own code somewhere.
- The cause is non-obvious β you've already read the message twice.
- You can paste the relevant code (the function in the trace, not the whole repo).
Don't bother when:
- The error is self-explanatory (
ModuleNotFoundError: No module named 'reqeusts'β you typo'd, fix it). - You can't share the code (secrets, client work under NDA) β then the model is guessing blind and you'll get generic answers.
- It's an intermittent production issue with no reproducible trace. AI ranks causes from evidence; no evidence, no ranking, just vibes.
- The error is in a library's internals with no frame touching your code. Sometimes the answer really is "upgrade the dependency," and you find that faster by reading its changelog.
The recipe
Paste the trace and the relevant code. The single biggest quality jump comes from including the code the trace points at β without it the model invents a plausible function and debugs that instead.
You are helping me debug. Below is an error/stack trace and the
relevant code. Do this, in order:
1. Restate in one sentence what actually went wrong (not what the
error literally says β what it means here).
2. Give a RANKED list of probable causes, most likely first. For
each: one line on why it's plausible given THIS trace, and one
concrete thing I can check or run to confirm or rule it out.
Rank by probability given the evidence, not by how easy they
are to fix.
3. If the most likely cause is correct, show the minimal fix.
4. Tell me what information would make your top guess more certain
(a value to print, a version to check). Don't pretend to be
sure if the trace is ambiguous.
Do not invent code I didn't show you. If a frame in the trace
refers to code I haven't pasted, say so and tell me to paste it.
--- ERROR ---
<paste the full trace>
--- CODE ---
<paste the function(s) the trace points at>A worked example
I ran this on a real-shaped Python bug. First, the lazy version β just pasting the error with "why?" β to show what you're trying to avoid.
Ugly first attempt. Prompt: Why am I getting 'NoneType' object is not subscriptable?
This error occurs when you try to use indexing or slicing (like
x[0]orx['key']) on a value that isNone. Common causes include: a function that returnedNoneinstead of a value, a dictionary.get()that found no match, an API call that returned nothing, or an uninitialized variable. Check that the object you're indexing actually has a value before accessing it, for example with anif x is not None:guard.
All true. All useless. It's a definition of the error, not a diagnosis of mine. I didn't learn which line, and "add an if guard" papers over the symptom without finding why the value is None.
The recipe version. Same error, but with the trace and code:
Traceback (most recent call last):
File "ingest.py", line 41, in <module>
main()
File "ingest.py", line 34, in main
rate = fx_rate(row["currency"], "USD")
File "ingest.py", line 22, in fx_rate
return data["rates"][target]
TypeError: 'NoneType' object is not subscriptabledef fx_rate(base, target):
resp = requests.get(f"https://api.example.com/latest?base={base}")
data = resp.json().get("result")
return data["rates"][target]Output:
1. What went wrong: The API call returned a JSON body that has no top-level
"result"key, sodataisNone, and indexingNone["rates"]raises the error. The failure is at thedata["rates"]step, not the network call.Ranked probable causes:
- The API nests its payload differently than you assume (most likely). You call
.get("result"), which returnsNonesilently when the key is absent β that's exactly the shape that produces this error. Check: printresp.json()and look at the actual top-level keys. Many FX APIs return{"rates": {...}}with no"result"wrapper at all.- The request failed and returned an error body. A 4xx/5xx still parses as JSON but with an
{"error": ...}shape, so.get("result")isNone. Check: printresp.status_codeβ if it's not 200, this is it.baseis an unsupported currency code. Some APIs 200-OK with an error payload for unknown currencies. Check: printrow["currency"]β confirm it's a valid ISO code likeEUR, not a blank or a header row that slipped in.Minimal fix (if cause 1): stop swallowing the missing key.
resp = requests.get(f"https://api.example.com/latest?base={base}") resp.raise_for_status() data = resp.json() return data["rates"][target]Drop the
.get("result")if the payload has no wrapper; keep it asdata = resp.json()["result"](no.get) if it does β so a missing key fails loudly instead of becomingNone.What would make me more certain: paste the output of
print(resp.status_code, resp.json())for one failing row. That distinguishes cause 1 from cause 2 immediately.
That's the difference. The second answer ranks by this evidence (the .get swallowing the key is the smoking gun), names the exact line, and ends with the one print statement that settles it. The first told me what None is.
For the record: I wrote a representative bug here to demonstrate the recipe β this is the kind of output the prompt reliably produces, not a captured run logged by a verification system. Run it on your own trace; the structure holds.
Where it breaks
It confidently blames the wrong line when you under-paste. If you give the trace but not the function, the model reconstructs a plausible fx_rate and debugs its imagination. Patch: always paste the code from the frame nearest the bottom that's yours. If the model says "paste the code at line 22" β which the prompt instructs it to β do that, don't accept its guess.
It invents a library API that doesn't exist. Ask why a call fails and you may get a fix using a parameter the library never had. Patch: before pasting any suggested fix that touches a library method, check the method actually exists in your installed version (help(obj.method) in a REPL, or the docs). Treat library-specific fixes as "check this," not "paste this."
It ranks by familiarity, not by your evidence. For a common error it sometimes leads with the textbook cause even when your trace points elsewhere. Patch: the "rank by probability given THIS trace, not how easy to fix" line in the prompt fights this β but sanity-check that cause #1 actually references something in your trace. If its top guess could've been written without reading your paste, it didn't read your paste; re-ask.
It "fixes" the symptom, not the cause. Left loose, it'll suggest wrapping the line in a try/except or an if x is not None guard β which makes the error disappear and the bug survive. Patch: the recipe asks why the value is what it is. If the answer is a guard, push back: "why is it None in the first place?"
Multi-language or async traces confuse the ordering. Async stack traces (and anything that crosses a thread/process boundary) list frames in an order that doesn't match execution. The model may pick the wrong "deepest" frame. Patch: tell it "this is an async traceback" and point at the line you believe is yours.
Cost & time
- Time: ~5 minutes. Most of it is gathering the right code to paste; the model answers in seconds.
- Cost: roughly $0.005β$0.02 on a frontier model per error, depending on how much code you paste. A trace plus one function is ~1β2k tokens in, ~600 out. On a free chat tier it's $0.
- Where the time actually goes: the print-statement-and-re-ask loop. The first answer narrows it to two or three causes; one targeted print usually settles which. Budget a second round-trip and you'll close most bugs in one sitting.