Agentic Ai
Paste Error, Zero Learning (Anti-pattern)
Reading level
Fix without understanding is future debt
You see "TypeError: Cannot read properties of undefined (reading 'map')." You paste it into the AI chat. It says add ?.map or default to []. You do it. The error is gone. An hour later: same error, different component. You paste it again. Same answer. A week later: you can't explain to your team why five components use optional chaining in the same spot.
The error wasn't the bug — undefined data during loading was the bug. Each patch hid a symptom without addressing the root cause. You got faster at applying band-aids and slower at diagnosing wounds.
AI accelerates your existing workflow. If your workflow is "see error → get fix → ship it," AI makes you faster at that workflow. But the workflow is wrong. The correct workflow is "see error → read it → form a hypothesis → ask a targeted question → understand the answer → apply and verify." AI accelerates the middle steps; the diagnosis and verification are yours.
This is a cognitive dependency risk, not an AI problem specifically. Cargo-culting from StackOverflow predates LLMs by a decade. AI makes the copy-paste loop faster and frictionless — which amplifies both the good (faster iteration on understood problems) and the bad (faster accumulation of poorly-understood patches). The defense is deliberate comprehension, not avoidance of AI.
The diagnosis-first pattern
Before pasting an error into AI, write one sentence: what you think is wrong. That's it. One sentence forces your brain to engage with the error message instead of treating it as a black box to hand off.
// ❌ Paste-without-diagnosis
"TypeError: Cannot read properties of undefined (reading 'map')
[stack trace]
fix this"
// ✅ Diagnosis-first
"Getting 'Cannot read properties of undefined (reading map)' at line 47.
I think products is undefined on the first render because the React Query
hook hasn't resolved yet. Is that right? And if so, why doesn't the
component wait for isLoading before rendering?"
The second prompt gets you a teaching answer. The first gets you a patch.
The rubber duck pattern: describe the problem to yourself before describing it to the model. The description forces a hypothesis. Then use AI to validate or refute it:
- "I think [X] is causing [Y] because [Z]. Is that right?" — validates your reasoning
- "I expected [A] but got [B]. What am I missing about how [concept] works?" — fills knowledge gaps
- "The fix is [patch]. But is this addressing the root cause or just the symptom?" — catches shallow fixes
When the model answers, verify the explanation makes sense. If you can't explain the fix to a colleague in two sentences, you don't understand it yet.
The professional concern: shallow fixes compound into systemic problems. A codebase where null checks, optional chaining, and ?? [] defaults are scattered because each was a copilot suggestion masks data-layer invariant violations. The type system should catch undefined data, not runtime guards applied at every consumer.
When reviewing AI-assisted code, ask not "does this fix the symptom?" but "does this fix the system?" Patches that survive PR review because they're small and correct locally accumulate into an unmaintainable codebase.
The agent that burned its own context window
An agentic coding loop was tasked with migrating a TypeScript codebase to strict mode. On its third iteration, it hit a compilation error. The agent's next turn included the full raw output of tsc --strict — 214 lines of interleaved diagnostics from 19 different files. The model read all 214 lines, identified two errors, attempted fixes, and ran tsc again. The new output was 198 lines. It pasted all 198 lines into the next turn.
Four turns later, the context window was 78% consumed by raw compiler output. The agent had fixed 3 of the 19 errors. At turn six, it began confabulating fixes for errors it could no longer see in full, introducing new type errors while patching old ones. The loop had to be restarted from scratch.
The failure mode was not that the agent used AI — it was that the agent's error-handling strategy was "include everything and let the model sort it out." For a 214-line compiler output, that strategy consumed roughly 4,000 tokens per turn, 24,000 tokens across six turns, just in error text. A structured parser that extracted the first diagnostic per file (file path, line, error code, message) would have produced a 19-line summary: around 400 tokens, leaving the context window for actual code fixes.
The error digest pattern
The fix was a structured error parser inserted between the compilation step and the agent's next turn. Rather than passing the raw output, the parser extracted: error code, file path, line number, and the single-sentence diagnostic message — one entry per unique error. If the same error code appeared multiple times in the same file, it was grouped as "TS2345 at src/api.ts (3 occurrences)" rather than listed three times.
The agent's context now received a clean digest: "19 errors across 8 files. Priority: TS2345 at src/api.ts:42 — Argument of type string not assignable to number. TS7006 at src/utils.ts:18 — Parameter implicitly has any type." The model immediately identified the correct fix for each, applied them in priority order, and completed the migration in two turns.
The structural principle: an AI agent's effectiveness is bounded by the signal-to-noise ratio of its inputs. Raw tool outputs — compiler errors, test failures, linter results, stack traces — are high-noise. The agent's job is not to parse noise; it is to reason about signal. The pipeline stage that runs the tool should also produce a structured summary of the result. This is not a limitation of AI — it is good engineering practice for any automated system that processes tool output.
Pattern at a glance
// ❌ 214 lines of raw tsc output as agent input
const agentInput = `
src/api.ts(42,14): error TS2345: Argument of type 'string' is not
assignable to parameter of type 'number'.
src/api.ts(43,8): error TS2345: Argument of type 'string | undefined'
is not assignable to parameter of type 'string'.
src/utils.ts(18,11): error TS7006: Parameter 'x' implicitly has an
'any' type.
... [211 more lines]
`;
// Context budget: ~4,000 tokens for errors alone, per turn
// ✅ Structured digest — ~400 tokens for the same 19 errors
function parseTscOutput(rawOutput) {
const lines = rawOutput.split('\n');
const seen = new Set();
const digest = [];
for (const line of lines) {
const m = line.match(/^(.+)\((\d+),\d+\): error (TS\d+): (.+)$/);
if (!m) continue;
const key = `${m[3]}:${m[1]}`;
if (seen.has(key)) continue;
seen.add(key);
digest.push(`${m[3]} at ${m[1]}:${m[2]} — ${m[4]}`);
}
return `${digest.length} errors:\n${digest.join('\n')}`;
}
// Agent input: "19 errors:\nTS2345 at src/api.ts:42 — ..."
Try it: paste vs diagnose
"Paste" mode shows a raw error being sent to AI — watch the generic fix it gets back. "Diagnose" mode shows the same error with a one-sentence hypothesis — watch the teaching answer that explains root cause and prevention.
In diagnose mode, the AI asks a follow-up question. That's the signal you entered a diagnostic conversation rather than a vending-machine fix loop. Follow-up questions mean the model has enough context to be specific.
In the paste mode, the suggested fix adds ?.map() — which hides the undefined rather than preventing it. The diagnose mode identifies the missing loading guard and the type annotation that should have caught this at compile time.
Showing: Diagnose — hypothesis first
Implementation depth
Error summarisation in agentic loops should be a first-class pipeline stage, not an afterthought. For TypeScript specifically, tsc --noEmit --pretty false produces machine-parseable output without ANSI escape codes. Pipe it through a digest function before the output reaches the agent's next prompt. For test runners, most support --reporter json or --reporter tap — structured output that can be summarised without regex.
// Agentic loop: run tool, summarise, pass digest to model
async function runWithDigest(command) {
const { stdout, stderr } = await exec(command);
const raw = stdout + stderr;
if (command.startsWith('tsc')) {
return parseTscOutput(raw); // ~400 tokens
}
if (command.startsWith('jest') || command.startsWith('vitest')) {
return parseTestOutput(raw); // failed tests only, summary counts
}
// Fallback: first 50 lines + line count
const lines = raw.split('\n');
const head = lines.slice(0, 50).join('\n');
return lines.length > 50
? `${head}\n... (${lines.length - 50} more lines truncated)`
: head;
}
Context budget management principles for agentic loops:
- Budget tool outputs explicitly — define a maximum token budget per tool result (e.g., 500 tokens). Any output exceeding this must be summarised before inclusion. Enforce this at the pipeline level, not the model level.
- Deduplicate repeated errors — the same error code at the same location appearing in multiple output lines should be counted, not repeated. One entry with an occurrence count is clearer and cheaper.
- Prioritise by error code — TS errors with "implicit any" (TS7006) or "type mismatch" (TS2345) are actionable; "module not found" (TS2307) may indicate a missing dependency that blocks all downstream errors. Show blocking errors first.
- Retry strategy — if the same error appears across three consecutive turns without progress, surface it to the operator rather than continuing to loop. Infinite retry on an unresolvable error is a common failure mode in agentic systems.
References
Remember
Key takeaways
-
Before pasting an error, write one sentence about what you think is wrong. This single step changes "give me a fix" into a learning conversation.The paste-fix-repeat loop builds speed at symptom-patching. The diagnosis-first pattern builds understanding of root causes. AI amplifies whichever workflow you use.AI-assisted shallow fixes compound: scattered null guards, untyped assertions, and suppressed warnings accumulate because each fix was individually small. Review for root cause, not just symptom resolution.
-
If you can't explain a fix to a colleague in two sentences, you don't understand it yet. Understanding is the check, not "did the error go away."Use AI to validate hypotheses ("I think X is happening because Y — is that right?") rather than to generate fixes from blank context. You get better answers and you learn faster.The systemic fix: tighten the type system so these errors can't happen at runtime. Optional chaining at every consumer is a symptom of missing type guarantees at the data layer.
Keep going
Finish this takeaway, then continue the track — Casey saved your spot locally.
Sign in with email to sync progress across devices (beta).
Inside the Casebook
New cases every few weeks — patterns from production UI engineering. Double opt-in, easy unsubscribe.
No spam. Unsubscribe anytime. Emails sent via Buttondown.
RSS feed