Should I catch an Exception that carries an exit code, or let it end the program?
← Error Handling and Exceptions · Ref: Q1436
It depends on whether the program can carry on.
CATCH IT when the program can recover. The catch handles the failure, the program continues, and the exception's exit code no longer applies. In the program below, the first read fails with code 4, the catch recovers, and the program goes on.
LET IT PASS when the program cannot recover. An Exception nothing catches ends the program with its own exit code, after the finally blocks and teardown (see Q1432).
CATCH, LOG, AND THROW IT AGAIN when you want both. Throw the same exception from the catch and its code is kept. The second try below logs the failure and throws ex again, so the program exits 4:
catch -> ex as Exception stdout.println(`Logging, then passing it on: ${ex.reason()}`) throw ex
THE TRAPS
- Catching an exception and only printing it ends the failure, and the program then exits 0. A CI step that runs it will not see a failure.
- Throwing a NEW exception without a code exits 1, even if the caught one had a code (see Q1433). To keep the code, give the new exception one too: Exception("Import failed", ex, 4).
- Throwing the message instead of the exception, 'reason <- ex.reason()' then 'throw reason', is E04030. Only an Exception can be thrown, never a String.
See Q134 for try/catch. See Q135 for finally. See Q1431 for every way a program sets its exit status.
Example
defines module qa.errorhandling.catchorexit defines function readOrders() -> source as String <- rtn as Integer: 0 if source <> "orders.csv" throw Exception(`Cannot read ${source}`, 4) rtn: 12 defines program CatchOrExitDemo() stdout <- Stdout() try stdout.println(`Orders: ${readOrders("backup.csv")}`) catch -> ex as Exception stdout.println(`Recovered from: ${ex.reason()}`) try stdout.println(`Orders: ${readOrders("orders.csv")}`) readOrders("archive.csv") catch -> ex as Exception stdout.println(`Logging, then passing it on: ${ex.reason()}`) throw ex
Common mistakes
E04030 — Only an Exception can be thrown, and ex.reason() gives a String. Throw ex itself to pass the failure on with its exit code. See ek9 -h E04030 for details.
Incorrect:
reason <- ex.reason() throw reason
Correct:
throw ex
Other ways to ask this
- Why did my program exit 0 after I caught the exception?
- How do I log an exception and still exit with its code?
- How do I rethrow an exception in EK9?
- Does catching an exception lose its exit code?
Coming from another language?
Java: catch (E e) { log(e); throw e; } keeps the exception, but the JVM exits 1 whatever it carries. Python: a bare 'raise' re-raises. EK9: 'throw ex' inside the catch throws the same exception again, and its exit code becomes the program's status if nothing else catches it.
Keywords: throw ex, exit code, catch, log and rethrow, rethrow, propagate, recover