Let it crash: the error philosophy behind this site's name

LLM-authored, human-reviewed

Concurrency & the BEAM

This site is called LetItCrash. The name is not a joke about uptime. It names the error-handling philosophy of the language the site teaches, and it sounds like the opposite of what you were taught about reliable software: “Handle every error.” “Never let an exception escape.” “Defensive programming.” Let it crash takes the other position. Stop predicting every failure. Write code that assumes something will fail, then build the system so that failure is cheap to absorb. That is the idea, and this article explains what it asks of you.

The two ways to handle errors

Software has two basic ways to survive failure. Most languages push you toward one of them.

The first is defensive programming: anticipate every way a function can fail, then handle each one where it might happen. Wrap the call in try/catch. Check the input before using it. Return a default when something is nil. The code grows a crust of guards, each one a prediction about a future that usually does not arrive. Defensive code is exhausting to write and read. It also has one blind spot: the error you did not predict. That crash still happens, except now it lands inside carefully guarded code whose recovery path was never designed.

The second is let it crash: accept that you cannot predict every failure, then arrange things so you do not need to. When something goes wrong, the process dies. Not “dies gracefully” - dies. The system notices and restarts it from a known-good state. The code stays clean. Guards do not spread through it, and recovery does not tangle with the happy path. Error handling moves out of the function and into the structure around it.

Why a crash can be cheap

For let-it-crash to work, a crash has to be genuinely cheap. The BEAM - the virtual machine this site’s concurrency article describes -

  • does the heavy lifting. The unit of work is the process: a small, isolated box with its own memory. Processes cannot corrupt each other; they communicate only by passing messages. When a process crashes, only its own state goes down. Nothing else in the system is touched. The process that sent it a message either sees no answer or gets a signal saying the receiver died.

Because a crash is isolated, restarting is the recovery. A supervisor is a process whose whole job is to watch another process and restart it when it dies. The supervisor does not try to determine why the process died or clean up after it. It restarts the process from the top, with the same arguments as before. If the failure was transient, the process returns and the system continues as if nothing happened. If the failure is permanent, the process crashes again. The supervisor can escalate: restart it a few times, then give up and fail upward to its own supervisor. This continues until something recovers or the whole supervised tree stops and the system tells you loudly that it is down.

A supervisor with two workers: one crashed, one fine, and the supervisor's
restart arrow - the whole philosophy in one picture.

What the philosophy actually asks of you

Let it crash is not permission to be sloppy. It is a trade: stop predicting failures and structure the system around them instead. Keep the happy path clear. Let unexpected failures kill the process rather than half-recovering inside it. Put a supervisor around anything that should be restarted. Handle the errors you can do something about - a bad user input, a missing record - as ordinary values. Those are not crashes; they are data. The philosophy separates failures you can meaningfully handle from failures you cannot, then keeps code out of the second category.

That is why the site’s exercises let you write code that would blow up in a defensive language. The recursion exercises run your function against test cases. If a clause is missing, the function crashes, and the feedback is the crash itself. No wall of error-handling sits between you and the lesson. The BEAM and its supervisors provide the recovery structure. Your job is to get the happy path right.

Why this matters here

The name at the top of every page states the philosophy. When you meet Elixir’s processes and supervisors in the concurrency and orchestration articles, you will see the same error story: crashes are isolated, restarts are the recovery, and the system treats failure as a signal rather than a catastrophe. The alternative - predicting every failure inside every function - is not more robust. It is more code for the unpredicted failure to crash inside. Let it crash is not the absence of error handling. It is error handling done once, at the boundary, where it can work.

Where to go next

  • Process Ring - the philosophy in motion: spawn a ring of processes, pass a token, and watch the BEAM treat each one as an isolated unit that can die without taking the ring with it.
  • Ping-Pong Counter - two processes bouncing a counter. The grader watches the messages, not just the return value.
  • Print in Order - the ordering question: given tasks and prerequisites, is a valid order even possible? Kahn’s algorithm, not processes.
  • Print in Order (concurrent) - three processes that must fire in sequence, coordinated by messages.
  • Bits have no meaning - “let it crash” at the silicon level: the machine cannot always be reasoned out of a state, only reset - which is why the isolation this article preaches matters.
  • The halting problem
    • the mathematical reason the philosophy exists: you cannot certify that a process will not hang, so you structure the system for the hang instead.
  • The BEAM is the broker and Publish-subscribe - the error philosophy behind the message-passing runtime that makes the isolation real.

Related exercises

← Back to articles