Why Defensive Coding Fails at Scale
In traditional systems, the instinct is to catch every exception and try to recover:
try {
processPayment(order);
} catch (DatabaseException e) {
// Retry? Roll back? Log and continue?
// The state of 'order' is now unknown.
log.error("Something went wrong", e);
// Hope for the best...
}
The problem is that after an unexpected exception, you do not know what state your objects are in. The payment might be half-processed. The database connection might be corrupted. The in-memory cache might have stale data. Your recovery code is now operating on an unknown, potentially corrupted state — which is often worse than crashing cleanly.
In a large system, this leads to a class of bugs called heisenbugs: intermittent failures that are impossible to reproduce because they depend on the exact corrupted state that accumulated over hours of running.
Let It Crash
The Erlang community discovered a counterintuitive solution: do not try to recover from unexpected errors. Just crash.
Kill the actor immediately. Its corrupted state is garbage-collected. A supervisor (explained in the next section) starts a fresh replacement with a clean, known-good initial state. The system heals itself automatically.
Actor encounters unexpected error
│
▼
Actor DIES immediately
(state is discarded)
│
▼
Supervisor is notified
│
▼
Supervisor starts fresh Actor
(clean initial state)
│
▼
System continues processing
This philosophy only works because of two properties of the Actor Model:
- Isolation: When an actor crashes, it cannot corrupt other actors' state (because state is never shared).
- Supervision: Every actor has a parent that is responsible for restarting it.
The practical result is that Ericsson's AXD 301 switch, built with Erlang, famously achieved nine nines of availability (99.9999999% uptime) — less than 31 milliseconds of downtime per year. Not because they prevent failures, but because they recover from them in milliseconds.
What "Let It Crash" does NOT mean: It does not mean ignoring expected errors. If a user submits an invalid form, you handle that gracefully — it is an expected condition, not a system failure. "Let It Crash" applies to unexpected failures: null pointer exceptions, corrupted state, hardware faults, bugs you did not anticipate.
A common interview question: "How is 'Let It Crash' different from just ignoring errors?" The answer: it is the opposite of ignoring errors. It is acknowledging the error by immediately terminating the corrupted component and delegating recovery to a supervisor. The key insight is that a fresh restart to a known-good state is more reliable than attempting to recover from an unknown-bad state. Supervisors make this automatic and systematic.