Claude Code Error Diagnosis: From Logs to Regression Tests
A practical Claude Code workflow for error diagnosis, log triage, minimal repros, regression tests, and verification.
Error diagnosis is not guessing from the red line at the bottom of a terminal. It is the work of turning a failure into evidence that another person, test runner, or Claude Code session can reproduce.
Three words matter first. A log is the record emitted by a command or application. A stack trace is the path of function calls that led to the error. A minimal reproduction is the smallest example that still fails after unrelated UI, data, and configuration are removed.
Claude Code works best when you do not just ask it to “fix this.” Give it the failed command, the first failing line, a small hypothesis set, and the command that must pass after the fix. This article turns that into a beginner-friendly but practical workflow.
For related reading, use the Claude Code build error triage loop, the Claude Code error message decoder, and the Claude Code bug report template.
The Diagnosis Flow
flowchart LR
A["Save failing command"] --> B["Find first failing line"]
B --> C["Limit to three hypotheses"]
C --> D["Create minimal repro"]
D --> E["Add regression test"]
E --> F["Apply smallest fix"]
F --> G["Verify with same command"]
G --> H["Write handoff note"]
This order prevents a common failure mode: editing first and proving later. Claude Code can read a lot of files, so vague instructions can lead to broad cleanup. The target is not more change. The target is a narrower cause.
Start by collecting four facts.
| Evidence | Why it matters | Example to give Claude Code |
|---|---|---|
| Failed command | Freezes the reproduction | npm run build, node --test |
| First failing line | Avoids tail-log noise | TypeError, ERR_MODULE_NOT_FOUND |
| Runtime context | Separates environment bugs | Node.js version, OS, CI provider |
| Expected behavior | Defines the correct fix | Null becomes empty array, 404 is not retried |
For JavaScript error names, the MDN JavaScript error reference is a useful baseline. For Node.js, the Node.js Errors documentation is especially important because stable diagnosis should prefer error.code over fragile message text when possible. For end-to-end tests, Playwright debugging docs explain Inspector, Trace Viewer, and VS Code debugging so you are not relying on logs alone.
A Practical Claude Code Workflow
Use this as the standard prompt for a real failure.
claude -p "
Diagnose the following error.
1. Confirm the failing command
2. Separate the first failure from unrelated log noise
3. List up to three root-cause hypotheses
4. Create a minimal reproduction
5. Add a regression test
6. Apply the smallest fix
7. Verify with the same command and write a handoff note
Constraints:
- Do not perform unrelated refactors
- Explain any public API change before making it
- Do not call the fix complete if verification still fails
"
“Up to three” is deliberate. Ten hypotheses create confusion. For Cannot read properties of undefined, three useful hypotheses are enough: the API shape changed, the initial value is missing, or the component renders before async data is ready.
Use Case 1: React Undefined Errors
A common React failure happens when an API returns null and the UI calls users.map(...). The error looks like a rendering problem, but the root cause is usually a data-shape contract.
// user-list.mjs
export function names(users) {
if (!Array.isArray(users)) {
return [];
}
return users.map((user) => user.name ?? "(no name)");
}
// user-list.test.mjs
import assert from "node:assert/strict";
import test from "node:test";
import { names } from "./user-list.mjs";
test("names returns an empty array when the API returns null", () => {
assert.deepEqual(names(null), []);
});
test("names keeps valid user names", () => {
assert.deepEqual(names([{ name: "Masa" }]), ["Masa"]);
});
node --test user-list.test.mjs
If the old implementation was only return users.map(...), the first test fails. Ask Claude Code to add the failing test first, then make the smallest fix. A guard inside the normalization function is usually safer than rewriting state management.
Use Case 2: Node.js ENOENT and Import Failures
ENOENT usually means a file or directory was not found. The trap is that config/local.json may exist on your laptop but not inside CI or a Docker image.
Inspect the failed command, error.code, error.path, Dockerfile COPY, .gitignore, and the CI working directory. Prompt Claude Code like this.
claude -p "
Diagnose this Node.js ENOENT failure.
Inspect error.code, error.path, current working directory, Dockerfile, and CI config.
Suggest only fixes that do not depend on a local-only file.
"
Do not stop at “create the missing file.” If the configuration is required, fail early with a clear message. If it is optional, provide a default. If CI needs a sample, copy a checked-in sample file during setup.
Use Case 3: Playwright Tests That Fail Only in CI
Playwright timeouts mix several causes: an application bug, a bad wait condition, slower CI, expired auth, or a network difference. Fixing the symptom by increasing timeouts often hides the real issue.
Keep traces on failure.
// playwright.config.ts
import { defineConfig } from "@playwright/test";
export default defineConfig({
use: {
screenshot: "only-on-failure",
trace: "retain-on-failure",
video: "retain-on-failure",
},
});
Give Claude Code the failing spec, locator, expected screen state, trace location, and CI command. The instruction should be: “Before increasing timeouts, separate UI state, API response, authentication, and locator problems.” Pairing that with Playwright’s official debugging workflow makes the diagnosis much less speculative.
Use Case 4: Cascading TypeScript Errors
Twenty TypeScript errors often look like twenty bugs. In practice, one API type changed and the rest are downstream failures.
npx tsc --noEmit --pretty false 2>&1 | tee tsc.log
claude -p "
Read tsc.log and choose the first type error to fix.
Separate derived errors from the likely root cause.
After the fix, verify with npx tsc --noEmit --pretty false.
"
The trick is not to fix everything at once. Fix the root type, rerun the same command, and inspect only the remaining errors. That loop prevents unnecessary as any patches.
Classify Logs Before Reading Everything
This small script is intentionally simple. It gives you a first bucket before asking Claude Code for deeper analysis.
// triage-log.mjs
import fs from "node:fs";
const sample = `
TypeError: Cannot read properties of undefined (reading 'map')
at ProductList (src/ProductList.tsx:42:18)
`;
const input = process.argv[2]
? fs.readFileSync(process.argv[2], "utf8")
: sample;
const rules = [
[/ERR_MODULE_NOT_FOUND|Cannot find module/i, "dependency or import path"],
[/ENOENT/i, "file path or working directory"],
[/TypeError:.*undefined|Cannot read properties/i, "data shape or initial value"],
[/Timeout.*expect|locator/i, "E2E wait condition or screen state"],
[/TS\d{4}/, "TypeScript type error"],
];
const matches = rules
.filter(([pattern]) => pattern.test(input))
.map(([, label]) => label);
console.log(matches.length ? matches.join("\n") : "Unclassified: inspect first failure");
node triage-log.mjs
node triage-log.mjs tsc.log
The script is not a replacement for diagnosis. Its job is to separate dependency failures, file-path failures, data-shape failures, E2E waiting failures, and TypeScript errors before the conversation gets noisy.
A Reproducible Bug Report Template
Before asking Claude Code to investigate, reshape the bug into this format. If you use GitHub Issues, the official GitHub issue forms syntax can turn the same fields into a form.
## Summary
Describe the broken behavior in one sentence.
## Failed command
`npm run build`
## Expected result
The build succeeds and creates `dist/`.
## Actual result
The command fails with `TypeError: Cannot read properties of undefined`.
## First failing line
`src/components/ProductList.tsx:42:18`
## Reproduction steps
1. `npm ci`
2. `npm run build`
## Environment
- Node.js: 22.x
- OS: Windows 11 / GitHub Actions ubuntu-latest
- Branch: feature/product-list
## Already tried
- Regenerated lockfile
- Checked API response fixture
## Verification after fix
- `node --test`
- `npm run build`
The key sentence is not “something is broken.” The key sentence is “these steps reproduce the same failure.”
Common Pitfalls
First, pasting only the final log line. The last line is where the process stopped, not necessarily where the bug began. Keep the first failure and the surrounding lines.
Second, branching on error-message text. In Node.js, prefer stable properties such as error.code or name when available.
Third, skipping the minimal reproduction. Debugging inside a full page or full production config makes it hard to know whether the fix addressed the cause or only changed timing.
Fourth, fixing without a regression test. Without a test, the same bug can return during the next refactor.
Fifth, giving Claude Code too much scope. Ask for the smallest change that makes the specific failure pass. For team review boundaries, see the Claude Code review workflow checklist.
Write the Handoff Note
Once the verification command passes, leave a short note for reviewers and your future self.
## Diagnosis note
- Failure: `npm run build`
- Cause: `users.map` was called when the API returned null
- Fix: Normalize non-array input to an empty array in `names()`
- Regression test: `node --test user-list.test.mjs`
- Verification: `npm run build` passed
- Remaining risk: Confirm separately whether API null is intentional
Ask Claude Code to produce it explicitly.
claude -p "
Write a Markdown diagnosis note for this fix.
Include cause, changed files, regression test, verification command,
and remaining risk. Keep it short enough for a reviewer to read in five minutes.
"
Templates and Consultation
For solo work, copying the commands and templates in this article is enough to start. For teams, decide which logs may be shared, which secrets must never be pasted into Claude Code, where minimal reproductions live, which CI artifacts are required, and what proof reviewers expect.
ClaudeCodeLab provides Claude Code products and templates plus Claude Code training and consultation for teams that want bug report forms, CI triage prompts, regression-test patterns, and handoff notes instead of one-off debugging.
After applying this workflow in ClaudeCodeLab maintenance, Masa found the biggest improvement came from fixing three habits: preserve the first failing line, create a minimal reproduction, and rerun the same command after the fix. Claude Code became easier to trust because every suggestion had evidence, a hypothesis, a test, and a verification result attached.
Free PDF: Claude Code Cheatsheet
Enter your email and download the one-page Claude Code cheatsheet for commands, review habits, and safe workflows.
We handle your data with care and never send spam.
Level up your Claude Code workflow
Start with the free PDF, use Gumroad guides when you need repeatable workflows, and book consultation when rollout or revenue paths need human judgment.
About the Author
Masa
Engineer focused on practical Claude Code workflows. Runs claudecode-lab.com, a 10-language technical media site.
Related Posts
Claude Code Permission Safety Ladder: Expand Access Without Losing Control
A beginner-friendly ladder for moving Claude Code from read-only to limited edits, proof commands, and deploy checks.
Claude Code Small PR Proof Pack: Make Tiny Changes Reviewable
A practical proof pack for Claude Code PRs: diff, checks, public URL, CTA path, and rollback note.
Claude Code Review Gate Before Commit: Diff, Tests, Public URL, and CTA Checks
A commit-time review gate for Claude Code work: diff scope, build, public URL, revenue CTA links, missing tests, and unrelated files.
Related Products
50 Battle-Tested Claude Code Prompt Templates
Copy, paste, ship. 50 production-ready prompts.
Use proven prompts for code review, refactoring, testing, documentation, debugging, architecture, and incident response.
Claude Code Quick Reference Cheatsheet
A free one-page reference for daily Claude Code work.
Keep the essential commands, file-reference patterns, CLAUDE.md reminders, prompting habits, review cues, and debugging workflow notes next to your editor.