Not Every Bug Deserves a Guard

Every program has infinite bugs. Newer coding agents treat that infinity as a dare and try to guard against all of it. The result is code wrapped in so many null checks, try-catches, and silent defaults that the real logic disappears behind the scaffolding. Defensive programming used to be a discipline. Agents turned it into a compulsion.


A lone engineer standing in a corridor of glowing shields and barriers that stretch endlessly into the distance, each one guarding a trivial edge case

The Hardening Trap

Every program has infinite bugs. The corollary is worse: every program has infinite surfaces to defend. The set of things a sum(a, b) does not handle is literally unbounded. Overflow, doubles, NaN, null, negative infinity, localized number formats, thread safety, audit logging. Keep going until you get bored. The function still has gaps.

Golden-path code that ignores edges is negligent. It ships systems that break on the first unexpected input. Nobody argues for zero defense.

But the opposite extreme is just as broken. GitClear’s 2026 research across 623 million code changes found error-masking constructs up 47%, code duplication up 81%, and two-week churn up 15%. The throughput is real. So is the debt.

Agents are not stupid. They are incentivized. There is no training penalty for verbosity. There is a massive penalty for a traceback. So they wrap every path in try-catch, invent defaults for required fields, and stack validation on top of schemas that already did the work. The code “succeeds.” Bugs hide for months.

Paranoia Code

I call this pattern Paranoia Code. Not the null-check kind. Null checks are cheap and mostly fine. The real pattern is structural: solving problems that categorically do not exist for your domain, your scale, or your context.

An internal dashboard at a twelve-person company gets rate limiting, circuit breakers, and exponential backoff. A notification service for nice-to-have alerts gets escalating retry logic with dead-letter queues. A user table needs one Google SSO login, and the agent builds a many-to-many junction table between users and auth providers because someday you might add Apple Sign-In. You will not add Apple Sign-In.

The agent treats every system like it runs at Google scale because its training data is dominated by Google-scale codebases. Anthropic’s own documentation confirms Claude “has a tendency to overengineer by creating extra files, adding unnecessary abstractions, or building in flexibility that wasn’t requested.” GPT-5.6 Sol is worse. One Codex user filed a bug fix; Sol expanded it into terminal session evidence requirements, dedicated-server save checkpoints, strict build identity validation, and PowerShell analyzer runs. Another user asked Opus 5 to fix a sitemap. The model rebuilt the entire site, changed the color scheme, broke animations, and deleted the only backup.

Four signatures of Paranoia Code:

  1. Solving for combinatorials that do not exist. The business needs one address per user. The agent builds a junction table with soft deletes because users “might” need more. They will not.
  2. Infrastructure for non-critical paths. Escalating retry with dead-letter queues for a “someone liked your post” notification. If one in a million drops, nobody notices.
  3. Enterprise patterns at startup scale. Repository layers wrapping direct database calls. Factory patterns for objects constructed once. Abstract classes with exactly one implementation, forever. Event buses with one subscriber.
  4. Re-solving what the platform already solved. AWS and GCP already handle connection pooling, TLS termination, request parsing, and container orchestration. The agent adds a second layer because it cannot see the trust boundary.

Paranoia Code looks thorough. That is the hardening trap. The reviewer sees enterprise patterns and assumes the system earned them. Nobody asks whether a twelve-person team’s internal tool needs circuit breakers.

The real price is not verbosity. It is complexity. Every unnecessary abstraction is a layer to maintain, a concept to explain to the next hire, a test to mock, and a file to touch when the business logic changes. A twelve-file auth framework has twelve failure points. A two-table hexagonal architecture requires editing four layers to add a column. Forward flow drowns in layers that exist to serve a scale you will never reach.

The Threshold That Matters

Infographic: spectrum from Golden Path (negligence) through Calibrated Defense (pragmatic middle) to Paranoia Code, with gauge bar from zero guards to infinite guards

Not all bugs carry the same blast radius. A dropped message in a logging pipeline, one in a million, is a rounding error. A dropped transaction in a payment system is a lawsuit.

Defense depth is a function of two variables: impact and likelihood.

  Low Impact High Impact
High Likelihood Fix it cheaply Guard and test it
Low Likelihood Ignore it Guard, test, and monitor it

A sum() that overflows past MAX_SAFE_INTEGER sits in the bottom-left for a dashboard app. Move it to a payment ledger and it jumps to the bottom-right.

Medical device firmware? Top-right on nearly everything. The blast radius of a bad default is a dead patient. Buy every guard you can afford.

A SaaS chart renderer? Most failure modes are top-left. Fix the common ones cheaply. Let the long-tail cases crash visibly instead of silently inventing data. The seven aspects of software quality still give you the vocabulary for ranking which aspect of a given change actually matters.

This is not new. The Pragmatic Programmers called it “pragmatic paranoia” two decades ago. Design by Contract said it formally: validate at the trust boundary, assert internally, crash when invariants break. What changed is that agents made the wrong choice free. Hardening used to cost hours, so teams weighed it against the risk. When the agent adds a guard in ten seconds, every imaginary edge case looks “free.” It is not free. The human still reads it, reviews it, maintains it, and debugs it when the silent default masks the real problem.

Calibrate, Don’t Maximize

A recent study on prompt-induced waste in coding agents found that instructions demanding maximum certainty triggered 18x token cost with zero improvement in success rate. The agent re-reads files it already read, re-runs tests it already passed, and generates redundant assertions. Correctness theater on a running meter.

The fix is the same one that works for code review triage, enforceable architecture, and bearing off before perfecting: make the rules deterministic and testable. Do not ask the agent to “be careful.” Tell it the contract.

Practically:

  1. Validate once, at the trust boundary. HTTP body, file parse, third-party webhook, user input. After that, types and invariants hold.
  2. Assert internally, do not guard. If a private function receives a null the caller already checked, that is a broken invariant. Crash loud. Do not invent a default.
  3. Let the blast radius decide. Financial, medical, weapons systems: guard aggressively. Dashboard rendering: crash visibly and fix it when someone reports it.
  4. Encode the policy as a gate. A linter rejecting empty catch blocks outperforms a prose rule in AGENTS.md every time. Architecture rules need teeth.
  5. Set a defense budget. When the defensive code in a module outweighs the logic, the defense is the problem.

You get the AI you ask for. Ask it to “handle every edge case” and it will defend against infinity, forever. Ask it to “validate at the trust boundary and crash on broken invariants” and it writes code you can read.

The Practicing Engineer’s Stance

Golden-path code is negligence. Paranoia Code is its mirror image. Neither ships reliable systems.

Every program has infinite bugs. Every program therefore has infinite surfaces that could be hardened. The question was never whether to defend. The question is how much defense this specific risk warrants, and whether that defense is loud enough to teach you when it fires.

Defend what would hurt. Ship the rest.