0Pricing
Scala for Backend Engineering & Functional Programming · Lesson

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")).attempt

Pattern 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 = 7

Retrying 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:

  • raiseError to fail explicitly
  • handleError / handleErrorWith to recover
  • attempt to materialize Either
  • redeem / redeemWith for both branches
  • guarantee for 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

  1. Cats Type Classes
  2. The IO Monad
  3. Composing IO
  4. Error Handling in IO
← Back to Scala for Backend Engineering & Functional Programming