How do I use try/catch to handle exceptions in EK9?
← Error Handling and Exceptions · Ref: Q134
EK9 uses try/catch blocks to handle exceptions, similar to Java, Python, and other languages. The catch block binds the exception to a variable using the arrow syntax.
BASIC TRY/CATCH
Wrap code that might throw in a try block, and handle errors in catch:
try riskyOperation() catch -> ex as Exception handleError(ex)
The catch block only executes if an exception is thrown inside the try block.
EXCEPTION BINDING
The catch block declares an exception variable with arrow syntax:
catch -> ex as Exception
This binds the caught exception to the variable 'ex' for use within the catch body.
ACCESSING EXCEPTION INFO
Exception provides reason() and the $ operator for string conversion:
catch -> ex as Exception stdout.println(ex.reason()) stdout.println($ex)
The reason() method returns the message. The $ operator converts the full exception to a string.
HANDLE SYNONYM
EK9 supports 'handle' as a synonym for 'catch'. Both are identical:
try riskyOperation() handle -> ex as Exception handleError(ex)
Use whichever reads better in context.
TRY AS EXPRESSION
Try can be used as an expression that returns a value:
result <- try <- rtn as String: "default" rtn: computeValue() catch -> ex as Exception rtn: "error: " + $ex
The return variable must be declared in the try body.
See Q78 for guard variables in try blocks. See Q48 for the Result type alternative. See Q135 for try/catch/finally. See Q136 for throwing exceptions. See Q246 for debugging strategies. See Q283 for retry logic without break.
See Q304 for require preconditions. See Q305 for require vs assert vs throw.
See Q333 for transaction try-with-resources. See Q338 for partial commit prevention.
Example
defines module qa.errorhandling.trycatch defines function riskyDivide() -> a as Integer b as Integer <- rtn <- Integer() if b == 0 ex <- Exception("Division by zero") throw ex rtn: a / b defines program TryCatchBasics() stdout <- Stdout() // === BASIC TRY/CATCH === try result <- riskyDivide(10, 2) stdout.println("Result: " + $result) catch -> ex as Exception stdout.println("Error: " + $ex) // === CATCHING AN EXCEPTION === try result <- riskyDivide(10, 0) stdout.println("Result: " + $result) catch -> ex as Exception stdout.println("Caught: " + ex.reason()) // === HANDLE SYNONYM === try result <- riskyDivide(5, 0) stdout.println("Result: " + $result) handle -> ex as Exception stdout.println("Handled: " + $ex) // === TRY AS EXPRESSION === message <- try <- rtn as String: "no result" value <- riskyDivide(20, 4) rtn: "Computed: " + $value catch -> ex as Exception rtn: "Failed: " + ex.reason() stdout.println(message)
Common mistakes
E50010 — EK9 catch blocks accept only a single exception parameter. Unlike Java's multi-catch, you cannot list multiple exception types. E50010 is triggered — only a single Exception is supported. Catch the common base type (Exception) and check specific types within the block. See ek9 -h E50010 for details.
Incorrect:
catch -> ex1 as ValidationError ex2 as Exception
Correct:
catch -> ex as Exception
E04030 — The catch variable must be an Exception type or a subclass of Exception. Using a non-exception type like String triggers E04030 — type must be of Exception type. Define custom exceptions with 'extends Exception'. See ek9 -h E04030 for details.
Incorrect:
catch -> ex as String
Correct:
catch -> ex as Exception
E04030 — Only Exception types (or subtypes) can be thrown in EK9. Throwing a String triggers E04030 — type must be of Exception type. Wrap the message in an Exception constructor. See ek9 -h E04030 for details.
Incorrect:
ex <- "Division by zero" throw ex
Correct:
ex <- Exception("Division by zero") throw ex
E50060 — EK9 Exception has no getMessage() method. Use reason() to get the exception message. See ek9 -h E50060 for details.
Incorrect:
stdout.println("Caught: " + ex.getMessage())
Correct:
stdout.println("Caught: " + ex.reason())
E50060 — EK9 has no toString() method. Use the $ operator or string interpolation for string conversion. See ek9 -h E50060 for details.
Incorrect:
stdout.println(ex.toString())
Correct:
stdout.println("Error: " + $ex)
E50060 — EK9 Exception has no getMessage() method. Use reason() to get the exception message. See ek9 -h E50060 for details.
Incorrect:
rtn: "Failed: " + ex.getMessage()
Correct:
rtn: "Failed: " + ex.reason()
E50060 — EK9 has no toString() method. Use the $ operator for string conversion. See ek9 -h E50060 for details.
Incorrect:
stdout.println(ex.toString())
Correct:
stdout.println("Handled: " + $ex)
Other ways to ask this
- What is exception handling in EK9?
- How does try-catch work in EK9?
- What is the EK9 equivalent of Java try-catch?
- How do I catch errors in EK9?
Coming from another language?
Java: try { ... } catch (Exception e) { ... } with checked/unchecked distinction. Python: try: ... except Exception as e: ... with duck-typed exceptions. Rust: no try/catch, uses Result<T,E> and ? operator. Go: no try/catch, uses error return values. Kotlin: try/catch like Java but all exceptions unchecked. Swift: do { try expr() } catch { error }, throws keyword marks throwing functions, try? converts to optional, try! force-unwraps (crashes on error). EK9: try/catch with arrow binding (-> ex as Exception), 'handle' synonym for 'catch', all exceptions unchecked, try can be an expression.
Keywords: catch, error, exception, throw, binding, try, syntax, basic, reason, handle, swift, migrate