Quick answer: An exception is a structured error signal that interrupts normal flow but can be caught and handled, letting the program recover. A crash is an unexpected termination of the program. Many crashes are simply exceptions that were never caught, while others are hard native faults the program cannot survive at all.
Developers often use "exception" and "crash" loosely, but the distinction matters for how you handle errors and how your crash reporting behaves. The short version: an exception is an error your code gets a chance to deal with, while a crash is the program dying. The relationship between them, an unhandled exception often becomes a crash, is at the heart of writing resilient game code.
What an Exception Is
An exception is a structured way a program signals that something went wrong, a file was missing, a value was null, an operation was invalid. When raised, it interrupts the normal flow and propagates up the call stack looking for code that will handle it. If your code wraps the risky operation in a handler (a try/catch), it can catch the exception, deal with it gracefully, log it, show a message, fall back, and continue running.
The key property is recoverability. Exceptions are designed to be catchable. A well-placed handler turns a potential disaster into a managed hiccup: the player sees an error message instead of the game vanishing. Exceptions are how robust code anticipates and absorbs the things that can go wrong.
What a Crash Is
A crash is the program terminating unexpectedly, the process dies and the game is gone. Crashes come in two main flavors. The first is an unhandled exception: an exception was raised but no handler caught it, so it propagated all the way up and the runtime terminated the program. The second is a hard native fault, a segfault, a memory access violation, a stack overflow, where something corrupted at a low level that cannot be caught and recovered like a managed exception.
The first kind is, in a sense, preventable: a handler in the right place would have turned that crash into a caught exception. The second kind is more severe; native faults often indicate memory corruption or other serious problems that the program genuinely cannot survive, and the best you can do is capture a report on the way down.
Why the Distinction Matters
Understanding the difference shapes how you write and stabilize a game. Many crashes are unhandled exceptions, which means strategic error handling, catching exceptions where recovery is possible, can convert crashes into graceful degradation. A game that catches a save error and warns the player is far better than one that crashes on it. But you cannot, and should not, catch everything; native faults need to be caught at the reporting level, not the recovery level.
Your crash reporting should capture both. Bugnet's crash reporting records unhandled exceptions with their stack traces and native crashes alike, attaching device context and the build version to each. That lets you see which of your crashes are unhandled exceptions you could guard against with better error handling, versus native faults that point at deeper memory or platform problems, two different categories that call for two different fixes.
An exception is an error you can catch; a crash is the program dying. Many crashes are just exceptions nobody caught in time.