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