Cats MTL Typed Errors (Scala)
Quick start
- Define a domain error type; it may or may not extend Throwable depending on context.
- Use Cats MTL
Raise[F, E]in functions that can raise errors. - Use
Handle.allow/rescue(Scala 3) orHandle.allowF(Scala 2) to introduce a scoped error capability and handle it like try/catch. - Prefer Cats MTL over
IO[Either[E, A]]and avoidEitherT[IO, E, A]; pure functions returningEither[E, A]are fine at API boundaries. F[_]is optional: you can writeIO-specific code or keepF[_]for polymorphism, depending on the project.
Workflow
- Model domain errors as sealed ADTs (Scala 2) or enums (Scala 3)
- For effectful code that can raise errors, require
Raise[F, E](andMonad[F]orApplicative[F]). - Raise errors with
.raiseand return successful values withpure. - At a boundary, use
Handle.allow(Scala 3) orHandle.allowF(Scala 2) to create a scope where raises are valid. - Close the scope with
.rescueto handle each error case explicitly. - Keep Cats Effect resource and concurrency semantics intact by staying in the monofunctor error channel.
Patterns to apply
- Typed errors in signatures: treat the error type parameter
Eas the checked-exception channel in the function signature. - Scoped error capabilities: require
Raise[F, E]in functions that can fail; useHandle[F, E]when you also need to recover. - Scala 3 ergonomics: prefer
usingand context functions withallow; type inference is significantly better. - Scala 2 compatibility: use
allowFand explicit implicit parameters; expect more braces and explicit types. - Interop with pure code: use pure
Either[E, A]for parsing/validation and lift intoFwhere needed. - Avoid transformer stacks: do not reach for
EitherTjust to get a typed error channel; Cats MTL provides the capability without the stack. - Avoid sealed-on-sealed inheritance: model error hierarchies with composition (wrapper case classes), not sealed inheritance chains.
References
- Load
references/custom-error-types.mdfor detailed guidance, Scala 2/3 syntax, and rationale from the Typelevel article.