Get AI summaries of any video or article — Sign up free
Why I Prefer Exceptions To Errors thumbnail

Why I Prefer Exceptions To Errors

The PrimeTime·
5 min read

Based on The PrimeTime's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.

TL;DR

Value-based errors are presented as safer for servers because they force handling at the point of failure, reducing the risk of corrupted intermediate state.

Briefing

The central claim is that exceptions are often a worse fit for building reliable server software than returning errors as explicit values—because value-based errors force developers to decide what to do at the exact point an error can occur, while exceptions can leave programs in an uncertain state if something goes wrong mid-function.

The argument starts from operational reality: server code maintains significant in-memory state and aims for uptime. In that setting, failing one request is preferable to crashing the entire process. Exceptions can unwind the call stack automatically, but the downside is that it’s harder to know where the error was triggered and where it will be caught. With exceptions, a thrown error can bypass local recovery logic and jump to a higher-level handler, potentially skipping cleanup or state correction in intermediate frames. The result, according to this view, is “implicit knowledge” scattered across the stack: developers must trust that the right handler exists above, and that any mutated state in the intervening frames remains valid.

Value-based error handling, by contrast, makes failure part of the function’s contract. If a function returns an error value, callers must handle it immediately—either by propagating it upward, converting it into a default response, or returning a controlled failure to the client (e.g., sending an error message or closing a connection). The pro-exceptions side is acknowledged, but the counter is that “good exception handling” tends to devolve into widespread try/catch blocks anyway, which undermines the idea that exceptions reduce complexity.

A major thread of the discussion targets performance and overhead. Exceptions are framed as having near-zero cost on the success path because the normal control flow doesn’t need to branch on every call. Error values, on the other hand, require explicit checks and branching, and can introduce heavier “fat” result objects that may hinder optimizations like tail-call elimination. A benchmark example is used to claim C++ exceptions can be dramatically faster than returning error values in a contrived recursive Fibonacci workload, while Rust and C++ “expected/result” style approaches are slower.

Still, the performance debate doesn’t land as a decisive win for exceptions. The counterpoint is that the benchmark is intentionally worst-case and that real systems often avoid the pathological patterns where error propagation becomes expensive. More importantly, the discussion emphasizes that the hardest failures—out-of-memory, stack overflow, integer overflow/underflow—may not be safely recoverable in either model. That’s why some systems adopt “tiger style” programming: assert invariants aggressively (even in production) and design the system so unreachable states are treated as fatal rather than something to recover from.

The closing position is pragmatic: errors as values are favored because they make failure points visible and force deliberate handling, which is crucial for robust services. Exceptions are treated as potentially useful in languages that support them well, but their reputation is described as rooted in historically poor implementations and in the way exception-based control flow can obscure where and how state becomes invalid. The overall takeaway is less about ideology and more about engineering control: knowing exactly which functions can fail, and ensuring the program responds in a controlled, user-visible way without risking hidden corruption of server state.

Cornell Notes

The discussion argues for “errors as values” over exceptions in server-style software. The key reason is control: when errors are explicit in return types, developers must decide immediately how to handle them, which helps prevent corrupted in-memory state when failures occur mid-function. Exceptions can unwind the stack automatically, but that can hide where the failure originated and can force recovery logic to be pushed upward, sometimes requiring try/catch everywhere. Performance is debated with benchmarks claiming exceptions can be faster on success paths, yet the pro-value side counters that real-world code rarely matches the contrived worst cases and that reliability often matters more than micro-optimizations. The conversation also highlights extreme failure modes (OOM, stack overflow) where neither approach guarantees graceful recovery, motivating “assert/tiger style” design.

Why does explicit error-returning (errors as values) get framed as safer for servers with shared in-memory state?

Because the error is part of the function’s contract: callers see it immediately and choose how to respond (propagate, default, or return a controlled failure). With exceptions, a thrown error can jump over intermediate frames, leaving mutated state in an uncertain condition unless every intermediate layer is written to tolerate unwinding. The argument emphasizes that exception handling relies on implicit assumptions about where the error will be caught and whether intermediate state remains valid.

What’s the critique of “catching exceptions at the top” as a general strategy?

The critique is that top-level handlers don’t address the correctness of intermediate state changes. If an exception occurs deep in a call chain, any state modified in the frames between the error point and the catch site may not be rolled back in a way that preserves invariants. To be truly safe, developers end up adding try/catch blocks closer to where errors can occur—reducing the supposed simplicity advantage of exceptions.

How does the discussion connect error handling style to user-visible behavior in server programs?

Value-based errors are portrayed as enabling deliberate, user-facing responses: for example, returning an error response to the client (or closing the connection) rather than crashing the whole process. The pro-value stance also treats “single request failure” as acceptable while protecting uptime and state integrity, aligning error handling with operational goals like meeting SLAs.

What performance claims are made, and why are they contested?

A benchmark-style claim is that C++ exceptions can be about four times faster than Rust-style result/expected error returns in a recursive Fibonacci example, because exceptions avoid success-path overhead while error values require checks and may move “fat” result objects. The contest is that the example is contrived and that real systems can avoid the worst-case patterns; plus, reliability and correctness around state often outweigh micro-level performance differences.

What does “tiger style” (assert-heavy) programming contribute to the exceptions-vs-values debate?

It reframes recovery: some failure modes are treated as unreachable or fatal rather than something to recover from. The conversation cites systems like Tiger Beetle using asserts in production and references NASA-style guidance for building “NASA-level” reliability. The implication is that for certain extreme conditions (OOM, overflow, stack overflow), neither exceptions nor error values guarantee safe continuation, so the design goal becomes preventing invalid states and failing fast when invariants break.

How does the discussion treat out-of-memory and other extreme failures?

It argues that OOM and similar system-level failures may be unhandleable in practice because the program may not have enough resources to allocate error objects, write logs, or even safely unwind into a meaningful recovery path. That’s used to support the idea that robust systems must plan for these cases explicitly—often via design constraints and asserts—rather than assuming any error-handling mechanism will gracefully recover.

Review Questions

  1. What specific reliability problem does the argument claim exceptions can create when errors occur mid-function in server code?
  2. How do explicit error returns change the developer’s decision-making compared with exception unwinding?
  3. Why does the conversation say that extreme failures like OOM may require a different strategy than ordinary error handling?

Key Points

  1. 1

    Value-based errors are presented as safer for servers because they force handling at the point of failure, reducing the risk of corrupted intermediate state.

  2. 2

    Exception unwinding is criticized for hiding where failures originate and for relying on implicit assumptions about what intermediate frames did to shared state.

  3. 3

    A “top-level catch” approach is portrayed as insufficient for correctness unless intermediate layers are designed to tolerate unwinding.

  4. 4

    Performance arguments favor exceptions on the success path, but the pro-value side disputes conclusions drawn from contrived benchmarks and emphasizes real-world reliability tradeoffs.

  5. 5

    Extreme failure modes (OOM, stack overflow, overflow/underflow) may be difficult or impossible to recover from cleanly, motivating assert-heavy “tiger style” designs.

  6. 6

    The debate ultimately centers on engineering control: knowing which functions can fail and ensuring failures produce controlled, user-visible outcomes rather than crashes or hidden corruption.

Highlights

The strongest reliability claim is that exceptions can bypass intermediate recovery logic, leaving mutated in-memory state in an odd or invalid condition unless every layer is written with unwinding safety in mind.
Value-based errors make failure points explicit in function contracts, forcing callers to choose between propagation, defaults, or user-visible responses (like returning an error or closing a connection).
Performance comparisons are tied to success-path overhead: exceptions avoid per-call branching, while error values require checks and can involve heavier result objects—though the benchmark example is treated as contrived.
“Tiger style” programming reframes the problem for extreme failures: asserts and invariant enforcement can be more practical than trying to recover from states like OOM or overflow.

Topics

  • Exceptions vs Errors
  • Server Reliability
  • Error Handling Contracts
  • Stack Unwinding
  • Out of Memory
  • Tiger Style Programming

Mentioned

  • OOM
  • SLAs
  • SIGFP