How do I catch specific exception types in EK9?
← Error Handling and Exceptions · Ref: Q138
EK9 supports exception type hierarchies. Custom exceptions extend Exception, and catch blocks match by type. You can catch exact types or use polymorphic catching via a base type.
EXCEPTION HIERARCHY
Create sibling exception types:
NetworkError extends Exception ... TimeoutError extends Exception ...
Both extend Exception but are distinct types.
EXACT TYPE MATCHING
Catch a specific exception type:
try throw networkError catch -> ex as NetworkError handleNetworkError(ex)
Only NetworkError (and its subtypes) will be caught.
POLYMORPHIC CATCHING
Catch the base Exception to handle any exception type:
try throw networkError catch -> ex as Exception handleAnyError(ex)
Since all exceptions extend Exception, catching Exception catches everything.
TYPE MISMATCH BEHAVIOUR
If the thrown type does not match the catch type, the exception propagates:
try throw networkError catch -> ex as TimeoutError // NOT reached - NetworkError is not TimeoutError
The exception passes through to an enclosing try/catch or terminates the program.
NESTED TRY FOR MULTI-TYPE
Use nested try blocks to handle different exception types:
try try riskyOperation() catch -> ex as NetworkError handleNetwork(ex) catch -> ex as Exception handleOther(ex)
The inner catch handles NetworkError specifically. Anything else propagates to the outer catch.
See Q136 for throwing and creating custom exceptions. See Q134 for basic try/catch. See Q102 for the 'as open' modifier used in inheritance.
See Q308 for the dispatcher pattern for exception type routing.
Example
defines module qa.errorhandling.exceptionsubtypes defines class <?- Exception for network-related failures. -?> NetworkError extends Exception host <- String() NetworkError() -> reason as String host as String super(reason) this.host :=: host host() as pure <- rtn as String: host default operator ? <?- Exception for timeout failures. -?> TimeoutError extends Exception seconds <- Integer() TimeoutError() -> reason as String seconds as Integer super(reason) this.seconds :=: seconds seconds() as pure <- rtn as Integer: seconds default operator ? defines program ExceptionSubtypesDemo() stdout <- Stdout() // === EXACT TYPE MATCH === stdout.println("=== Exact type match ===") try ex <- NetworkError("Connection refused", "api.example.com") throw ex catch -> ex as NetworkError stdout.println("Network error on host: " + ex.host()) // === POLYMORPHIC CATCH (base Exception) === stdout.println("=== Polymorphic catch ===") try ex <- NetworkError("DNS failure", "db.example.com") throw ex catch -> ex as Exception stdout.println("Caught via base Exception: " + ex.reason()) // === TYPE MISMATCH (nested try) === stdout.println("=== Type mismatch propagation ===") try try ex <- NetworkError("Connection reset", "web.example.com") throw ex catch -> ex as TimeoutError stdout.println("Should NOT reach here") catch -> ex as Exception stdout.println("Propagated to outer catch: " + ex.reason()) // === NESTED TRY FOR MULTI-TYPE HANDLING === stdout.println("=== Multi-type handling ===") try try ex <- TimeoutError("Request timed out", 30) throw ex catch -> ex as TimeoutError stdout.println(`Timeout after ${ex.seconds()} seconds: ${ex.reason()}`) catch -> ex as Exception stdout.println("Other error: " + ex.reason())
Common mistakes
E50060 — The method is named host(), not getHost(). EK9 does not use Java-style getter naming conventions. Check the class definition to confirm method names. See ek9 -h E50060 for details.
Incorrect:
ex.getHost()
Correct:
ex.host()
E04030 — Catch blocks require a type that extends Exception. Catching a String triggers E04030 — type must be of Exception type. See ek9 -h E04030 for details.
Incorrect:
-> ex as String stdout.println("Network error on host: " + ex)
Correct:
-> ex as NetworkError stdout.println("Network error on host: " + ex.host())
E50060 — EK9 Exception has no getMessage() method. Use reason() for the error message. See ek9 -h E50060 for details.
Incorrect:
stdout.println("Propagated to outer catch: " + ex.getMessage())
Correct:
stdout.println("Propagated to outer catch: " + ex.reason())
E50060 — The method is host(), not getHost(). EK9 does not use Java-style getter naming. See ek9 -h E50060 for details.
Incorrect:
stdout.println("Network error on host: " + ex.getHost())
Correct:
stdout.println("Network error on host: " + ex.host())
E50060 — EK9 Exception has no getMessage() method. Use reason() to get the exception message. See ek9 -h E50060 for details.
Incorrect:
stdout.println("Caught via base Exception: " + ex.getMessage())
Correct:
stdout.println("Caught via base Exception: " + ex.reason())
Other ways to ask this
- Can I catch different exception types in EK9?
- How does exception type matching work in EK9?
- How do I handle multiple exception types?
Coming from another language?
Java: multiple catch blocks (catch IOException | SQLException), ordered most specific first. Python: multiple except clauses, tuple of types. Rust: no exception types, uses enum variants in Result. Go: errors.Is/errors.As for type checking error chains. Kotlin: multiple catch blocks like Java. EK9: single catch per try block with type matching, use nested try blocks for multiple types, polymorphic matching via base Exception.
Keywords: match, handle, type, specific, nested, visitor, extends, hierarchy, polymorphic, exception, subtype, sealed, handler, catch