Free — no signup required

Bohrbugs — The Deterministic Failures

3 min read

What Is a Bohrbug?

Imagine a light switch that's broken. Every time you flip it up, the light stays off. It doesn't matter who flips it, what time of day it is, or whether you're watching. The switch is broken in a consistent, repeatable way. That's a Bohrbug.

A Bohrbug is a software defect that manifests consistently under a well-defined set of conditions. The name comes from Niels Bohr's atomic model, where electrons orbit in predictable, deterministic paths. Bohrbugs behave the same way: given the same inputs and the same environment, they produce the same failure every single time.

Examples of Bohrbugs:

  • A function that divides by zero when passed quantity=0
  • A YAML configuration file with incorrect indentation that always fails to parse
  • An API endpoint that returns a 500 error every time it receives a payload larger than 1MB
  • A SQL query with a missing WHERE clause that always deletes the entire table

The debugging strategy for Bohrbugs is straightforward:

  1. Reproduce it. Write down the exact steps, inputs, and environment that trigger the bug.
  2. Isolate it. Narrow down which component, function, or line is responsible. Use binary search: comment out half the code, see if the bug persists, repeat.
  3. Write a failing test. Before you fix anything, write an automated test that captures the exact failure condition. This test should fail now and pass after your fix.
  4. Fix it. Apply the minimal change that makes the test pass.
  5. Verify no regressions. Run your full test suite to ensure the fix didn't break something else.

A classic example: a line-counting utility that actually counts newline characters, not lines. A file with content but no trailing newline reports zero lines — not because anything is random, but because the tool's definition of "line" quietly diverges from the intuitive one. Every file missing a trailing newline triggers the same wrong count, every time. That's the Bohrbug signature: a deterministic mismatch between what the code actually does and what everyone assumes it does.

The step that separates junior from senior engineers is step 3: writing a failing test before applying the fix. This discipline forces you to fully understand the failure condition, creates a permanent regression guard, and proves your fix actually addresses the root cause rather than masking a symptom. Bohrbugs are sometimes called "easy" bugs, but that's misleading. A Bohrbug in a complex distributed system can still take days to reproduce if you don't know the exact combination of inputs and state that triggers it. The difficulty isn't in the fix — it's in achieving reliable reproduction. The moment you can reliably reproduce a bug, you're 80% of the way to fixing it.

Key Point: The most dangerous Bohrbugs are the ones that only manifest under specific combinations of inputs that are rare in testing but common in production. This is why techniques like property-based testing (e.g., Hypothesis for Python, QuickCheck for Haskell) and fuzz testing are valuable — they explore input spaces that humans wouldn't think to test manually. A bug that triggers one-in-a-million requests is still a Bohrbug; it just has a complex trigger condition.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free