Opus generates confident, unverified code: nine defects in one production session (nonexistent CLI flags, stderr capture, printf arity, broken scripted edits)
Summary
During a production infrastructure cutover, Claude Code (Opus) produced nine distinct defects in generated shell/YAML/SQL, several of which executed against production. The common factor was not faulty reasoning — diagnosis from live evidence was consistently correct — but unverified output: flags that don't exist, variables collected and never wired through, printf arity errors, and indentation-broken edits, all handed over with uniform confidence.
Defects observed in one session
- Non-existent CLI flag in a destructive script. Generated
az postgres flexible-server delete --no-wait. That flag does not exist (az 2.86.0 supports only--yes). It aborted on the first command of a destructive production teardown. The user had explicitly asked me to verify the script beforehand; I verified that the resource names matched live state and never ran--helpon the commands.
- stderr folded into a captured value. Wrote a helper as
out="$(az "$@" 2>&1)"to surface errors. The Azurecontainerappextension prints a WARNING to stderr on every invocation, including empty results — so a "is this list empty" test could never succeed. Two consequences: the warning text was word-split into bogus resource names in delete loops, and a wait loop spun for 10+ minutes without ever issuing the next teardown step. This was introduced while "improving" a script the user had asked me only to review.
printfarity. Emitted 8 arguments against 7 format specifiers; bash recycled the format string and fabricated phantom output rows, inflating a probe count from 37 to 79 and inventing failures that did not exist.
- Collected a value and never printed it. A diagnostic script gathered source VM names, then printed only raw IPs, making the output unusable. Required two rounds of user correction.
- Fixed the symptom after naming the root cause. Identified an IaC module as the correct place for a fix, wrote that explicitly, then implemented a workaround in the calling workflow instead. Had to be told to move it.
- Indentation-broken scripted edits. A programmatic edit inserted a 4-space line into a 12-space YAML block scalar, breaking the file. A second replacement in the same edit silently did not match (indentation mismatch), omitting a required parameter that would have failed at runtime.
- Unfounded inference stated as established fact. Asserted that a replication slot was "the orphan from the teardown" and that other databases had "leftovers from earlier partial attempts." Neither was checked. The truth, available from evidence already on screen, was that two of three databases had never replicated.
- Answered a different question than the one asked. Asked how a config change affects rate limiting "right now," responded twice with steady-state comparison tables. The correct answer was "zero — the quota is already consumed."
- Bundled an approval-gated action. After the user asked to see a command before it ran, combined the auth check, the destructive statement and verification into a single call.
Why this pattern is worse than it looks
Generated code defeats shallow review in a way a blank page does not. It is fluent, idiomatic, and sits in a plausible shape, so a reviewer's attention has nothing to snag on. Worse, uncertainty is invisible in the output: --no-wait was written with exactly the same confidence as the lines that were correct, so the reader had no signal about where to spend scrutiny.
The felt speedup is also partly illusory. Evaluating generated code feels cheap because shallow evaluation is cheap; rigorous evaluation requires reconstructing the author's model, which often costs as much as writing it. The result is a quiet substitution of cheap review for real review, precisely where care matters most.
Suggested mitigations
- Mechanical verification before handoff, not attentional. "Read it carefully" does not survive contact with fluent output. "Run
--helpon every command in the script" does, because it does not depend on guessing where the mistake is. This check takes seconds and would have caught defect 1 outright. - Mark uncertainty in generated output. Distinguish "this flag I verified" from "this flag I inferred." Known uncertainty can be disclosed even if unknown-unknowns cannot.
- Prefer minimal diffs over rewrites. Defect 2 existed only because a working script was rewritten when a review was requested. A two-line change is cheap to audit; a rewrite is not.
- Self-check scripted edits. After a programmatic find/replace, assert the replacement actually matched rather than assuming it did (defect 6).
Environment
- Claude Code, Opus, VS Code extension
- macOS (bash 3.2 as
/usr/bin/env bash), Azure CLI 2.86.0 - Session involved live Azure infrastructure, GitHub Actions, and PostgreSQL
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗