The LLM Detective: DevTools Prompts That Reproduce Bugs, Read Stack Traces and Set Breakpoints Instead of Guessing

Asking a model "why doesn't my code work" and pasting a snippet is not debugging — it's a coin flip. Without a reproduction, a stack trace, network logs and a minimal example, the LLM fills the gaps with plausible fiction. And plausible fiction is worse than "I don't know", because it sounds confident.

Debugging is a loop: reproduce → narrow → test a hypothesis → confirm the fix. Every step has its own prompt. Below are the ones I actually run in the browser console and DevTools, with the failure modes they cover.

Step 1. Turn the error into a context package

1. Stack trace interpreter

A raw stack trace is noise. Ask the model to walk it frame by frame and separate your code from library code.

Here is a stack trace from Chrome DevTools. Do not guess the fix yet.
1) Split frames into my code (/src/**) and node_modules.
2) For the top frame in my code, name the file, function and the line that threw.
3) State which of these is most likely: my logic, a contract violation (wrong argument type), or async timing.
4) List the exact data you need from me to confirm (variable values, the call site).

<trace>
TypeError: Cannot read properties of undefined (reading 'id')
    at renderRow (src/table.js:42:18)
    at Array.map (<anonymous>)
    at Table (src/table.js:31:9)
</trace>

The payoff is that the model asks for rows[0] and the actual argument passed into .map, not for the whole file.

Key distinction A stack trace tells you where it broke. It never tells you why — that lives in the data one frame up.

2. Minimal reproduction from a bug report

"It breaks sometimes" is not a bug report. Make the model extract the reproduction conditions before theorizing.

Here is a vague bug report. Before any diagnosis, output a table:
| Condition | Known? | Value | Missing? |
Cover: browser and version, route, user state, data payload, network status, time zone.
Then write the shortest numbered click-path that would reproduce it, and mark which steps you cannot fill without me.

Step 2. Narrow the search space

3. Bisection over commits

Git bisect is mechanical; the prompt is about choosing the test.

I have 40 commits between a working and a broken build. The symptom: the cart total renders as NaN.
Suggest a single fast check that distinguishes good from bad commit at each step, runnable in the browser without a full test suite. Then give me the git bisect commands, including how to mark a commit as skipped if the build fails.

4. Network tab forensics

Most "frontend bugs" are contract bugs. Paste the request/response pair and ask for the mismatch.

Here is a fetch call and its response from the Network tab (status, headers, body).
Compare what the code expects against what arrived. Flag: field name mismatches, null vs missing, string vs number, pagination shape, and CORS or preflight failures.
Output a diff-style list: expected → actual → where it will throw.
Where people go wrong They paste the response body but not the status code and request headers. A 200 with an error envelope and a 500 with valid JSON look identical in the body alone.

Step 3. Confirm a hypothesis with breakpoints

5. Conditional breakpoint generator

Instead of stopping on every iteration, stop only where the bug lives.

Loop over 5,000 items; the bug appears for one specific record. Write a DevTools conditional breakpoint expression that pauses only when the record id equals the broken one, and a logpoint expression that prints index, id and computed total without pausing. Explain why a logpoint beats console.log here.

6. Watch expressions for state drift

I suspect a variable changes unexpectedly between two functions. Give me three DevTools watch expressions that reveal the mutation: the current value, its type, and a snapshot copy (structuredClone) so I can compare before and after.

7. Race condition hypothesis test

Symptom: the UI shows stale data after fast tab switching, no error thrown.
List the async ordering hypotheses (out-of-order responses, missing abort, shared mutable state).
For each, give a DevTools check: what to log, what to break on, and what result would confirm or kill the hypothesis.

Step 4. Verify the fix, not the theory

8. Fix verifier

Here is the proposed patch. Do not praise it. Answer: which line in the original stack trace does it change the outcome for? What input would still reproduce the bug? What new failure mode does it introduce (null handling, extra render, broken memoization)?

The trade-off worth naming

Feeding a model full context costs time upfront and returns precise answers. Feeding it a snippet is fast and returns confident guesses you then debug anyway. The break-even is roughly the second wrong guess: past that, building the context package is cheaper.

A related discipline — catching defects before merge — is covered in Your Second Reviewer Never Sleeps, and for the async side see Golang from Scratch.

The non-obvious insight: the most valuable prompt is not the one that finds the bug, but the one that makes the model tell you what it doesn't know. A detective who admits the missing evidence beats one who invents a confession.

← All posts

Ask AI about this article

Ask a question about this article — ASI Biont will answer based on its text.