Error Handling in IO
handleError.
Error Handling in IO is a free Scala for Backend Engineering & Functional Programming lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Scala for Backend Engineering & Functional Programming learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Errors as Values
In Cats Effect, an IO can fail. The failure is part of the value, so you can inspect and recover from it without unstructured try/catch.
Raising Errors
Use IO.raiseError to create a failed IO explicitly with a chosen exception.
import cats.effect.IO
val failed: IO[Int] =
IO.raiseError(new RuntimeException("boom"))handleError
handleError recovers a failed IO by supplying a fallback value computed from the error. The result is an IO that cannot fail at this point.
import cats.effect.IO
val safe: IO[Int] =
IO.raiseError[Int](new RuntimeException("x"))
.handleError(_ => -1)handleErrorWith
handleErrorWith recovers with another IO, so the fallback can itself be effectful (e.g. logging, retrying, returning a default).
import cats.effect.IO
val recovered: IO[Int] =
IO(throw new RuntimeException("fail"))
.handleErrorWith(e => IO.println(s"caught: ${e.getMessage}").as(0))attempt
attempt converts an IO[A] into IO[Either[Throwable, A]], materializing the error into the value so you can pattern-match on it.
import cats.effect.IO
val e: IO[Either[Throwable, Int]] =
IO.raiseError[Int](new RuntimeException("oops")).attemptPattern Matching attempt
After attempt you can branch on success or failure with a normal flatMap over the Either.
import cats.effect.IO
val prog: IO[Unit] = IO(10 / 2).attempt.flatMap {
case Right(v) => IO.println(s"ok: $v")
case Left(e) => IO.println(s"err: ${e.getMessage}")
}redeem
redeem handles both branches in one call: one function for the error, one for the success, both returning a plain value.
import cats.effect.IO
val label: IO[String] =
IO(42).redeem(e => s"failed: $e", v => s"value: $v")redeemWith
redeemWith is like redeem but each branch returns an IO, allowing effectful handling of both success and failure.
import cats.effect.IO
val prog: IO[Unit] = IO(42).redeemWith(
e => IO.println(s"err: $e"),
v => IO.println(s"got: $v")
)Cleanup with guarantee
guarantee runs a finalizer whether the effect succeeds or fails — perfect for releasing resources or logging completion.
import cats.effect.IO
val prog: IO[Int] =
IO(compute()).guarantee(IO.println("done"))
def compute(): Int = 7Retrying on Failure
You can build a simple retry by recursively recovering with handleErrorWith, decrementing a counter until it reaches zero.
import cats.effect.IO
def retry[A](io: IO[A], n: Int): IO[A] =
if (n <= 0) io
else io.handleErrorWith(_ => retry(io, n - 1))Plain Scala try/catch
Compare with classic eager error handling in plain Scala. IO's combinators give the same safety but as composable, pure values.
object Main {
def main(args: Array[String]): Unit = {
val result = try { 10 / 0 } catch { case _: ArithmeticException => -1 }
println(s"result: $result")
}
}Quick Check
Which method turns an IO[A] into IO[Either[Throwable, A]]?
Recap
You handled errors in IO with:
raiseErrorto fail explicitlyhandleError/handleErrorWithto recoverattemptto materializeEitherredeem/redeemWithfor both branchesguaranteefor cleanup
You've completed the Cats and IO course.
Frequently asked questions
Is the “Error Handling in IO” lesson free?
Yes — the full text of “Error Handling in IO” is free to read here on the web, and the Scala for Backend Engineering & Functional Programming course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Scala for Backend Engineering & Functional Programming course, upgrade to CoddyKit PRO.
What will I learn in “Error Handling in IO”?
handleError. You practise Scala for Backend Engineering & Functional Programming with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Scala for Backend Engineering & Functional Programming?
No prior experience is required. Scala for Backend Engineering & Functional Programming on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Error Handling in IO” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Scala for Backend Engineering & Functional Programming lesson?
Yes. Every Scala for Backend Engineering & Functional Programming lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Cats Type Classes
- The IO Monad
- Composing IO
- Error Handling in IO