The error-pasting guide: what to include so AI nails it first try
Every time you summarize an error for AI, you choose which clues to delete, and you make that choice with the same blind spot that produced the bug. I build Settl, an expense-splitting app, solo with Claude, and my first-try fix rate roughly doubled when I stopped narrating errors and started pasting them raw. Here is exactly what to paste.
Why summaries fail
Write "it throws a connection error when I save" and you have just stripped:
- The exact file and line where it blew up.
- The nested causes: the
caused bychain that names the real culprit sitting under the generic wrapper error. - The error class or code: ECONNREFUSED and ETIMEDOUT are different diagnoses with different fixes, and your summary collapsed them into "connection error."
- The weird detail: port 5433 instead of 5432, a path containing
dist/while you are running the dev build, a timestamp from the wrong timezone.
The weird detail is usually the one that cracks the case, and by definition you do not know in advance which detail is weird. Summarizing an error is tampering with the evidence, with good intentions.
The 4 things every error report needs
1. The full trace, raw
Copy from the first line of the error to the last line of the stack. Do not trim the
node_modules frames: they show which library boundary the call crossed. Do not stop at
the first caused by. Do not retype anything, because a typo in a retyped error sends the
whole investigation in the wrong direction.
2. The trigger action
One sentence about what you did: "Clicked Save on the profile page." "Ran npm run build." "Sent POST /api/orders with the payload below." The trace says where it died. The
trigger says how it got there.
3. Expected vs actual
One line each. "Expected: redirect to /dashboard. Actual: 500 and the trace above." This kills a whole class of bad fix: the one that makes the error disappear by making the feature disappear.
4. Recent changes
What changed since it last worked: "started after I upgraded Express," "new since I added the caching layer," or "no idea, it worked yesterday." Even "nothing that I know of" is signal. It points away from your diff and toward the environment.
A complete report is short. Four lines of yours, then the paste:
Clicked Save on /settings/profile.
Expected: success toast, redirect to /dashboard. Actual: spinner forever, 500.
Started after I added avatar upload yesterday.
POST /api/profile 500 (Internal Server Error)
Error: ENOENT: no such file or directory, open '/app/uploads/tmp/av-19d2.png'
at Object.openSync (node:fs:596:3)
at writeAvatar (src/api/profile/avatar.ts:41:19)
at updateProfile (src/api/profile/index.ts:88:11)
at handle (node_modules/express/lib/router/layer.js:95:5)
Logs or trace? When to include which
- Crash with an exception: the trace is mandatory, logs are optional.
- Wrong behavior with no exception (silent failure, wrong value, nothing happens): logs are the evidence. Paste the window around the action, roughly 20 lines before and after.
- A trace that looks impossible: include both. Impossible traces are usually downstream of earlier bad state, and the bad state is in the logs, often disguised as an innocent-looking warning a few seconds earlier.
- Frontend errors: paste the browser console error AND the status of the failing request
from the network tab. A 401 in the network tab explains a cryptic
undefinedin the console.
Multi-error triage: paste all of them
When the console is a waterfall of red, do not pick your favorite. The error you noticed first is often cascade, not cause. Paste all of them, in the order they appeared, and ask:
"Which of these is the root cause and which are cascade failures? Explain the chain before proposing any fix."
Making the model commit to a causal chain first prevents the classic waste: a session spent fixing error 3, which only existed because of error 1.
What raw actually means
- Keep timestamps. They prove ordering, and ordering is causation's fingerprint.
- Keep duplicates, or summarize them honestly: an error firing 40 times in one second is a different bug than the same error firing once.
- If the trace is enormous, paste the head, every
caused bysection, and note "the middle 400 frames repeat." That is compression, not summarizing. - Secrets are the one legitimate edit. Redact tokens and passwords visibly, like
Authorization: Bearer [REDACTED], and say you redacted, so a missing value is not mistaken for the bug.
Try it right now
Save this template somewhere close. Next error, fill in the brackets and paste:
Here is a bug report. Diagnose the root cause before proposing any fix.
TRIGGER: [one sentence: the exact action, e.g. "clicked Save on /settings"]
EXPECTED: [what should have happened]
ACTUAL: [what happened instead]
RECENT CHANGES: [what changed since it last worked, or "unknown"]
FULL ERROR, UNEDITED (secrets redacted):
[paste the entire error and stack trace, plus about 20 log lines before it]
If there is more than one error above, identify which is the root cause and
which are cascade failures, and explain the chain before you touch any code.
Start HTTP debugging with the first digit
The status code is not the diagnosis, but it chooses the first room to search.
| Status | First check |
|---|---|
| 400 | Request shape, content type, parsing, and required fields |
| 401 | Missing, expired, or invalid authentication |
| 403 | Identity is known but lacks permission |
| 404 | URL, route version, resource ID, and deliberate not-found masking |
| 409 | Duplicate, stale version, or state conflict |
| 422 | Syntactically valid request that fails domain validation |
| 429 | Rate-limit headers, retry timing, and caller identity |
| 500-599 | Server trace, dependency status, deployment, and correlation ID |
Four means inspect what the client sent. Five means inspect what the server did while handling it. There are exceptions, but this split stops you debugging a button for an exception already sitting in the server log.
Capture method, full URL without secrets, status, response body, request ID, browser network
headers, server trace, and timestamps. Do not retry a permanent 4xx in a loop. For 429 and transient
5xx responses, honor Retry-After when present and keep retries bounded.