Expected errors and defects

A doubt still remains: did we really handled all errors? What if something else goes wrong?

All the errors that we defined and collected in the Effect type are called Expected errors.

Expected errors (also called failures, typed errors or recoverable errors) are errors that developers anticipate as part of the normal program execution.

The catchTags function is in fact designed to recover from expected errors:

const main = fetchRequest.pipe(
  Effect.flatMap(jsonResponse)
);

FetchError and JsonError are expected errors. As such they are tracked inside the Effect type: Effect<unknown, FetchError | JsonError>.

const main = fetchRequest.pipe(
  Effect.flatMap(jsonResponse),
  Effect.catchTags({
    FetchError: () => Effect.succeed("Fetch error"),
    JsonError: () => Effect.succeed("Json error"),
  })
);

Here we recover from both FetchError and JsonError by returning a string. Since we recovered from these errors, they are removed from the Effect type: Effect<unknown, never>.

But there is another category of errors: Unexpected errors (also called defects, untyped errors, or unrecoverable errors).

Unexpected errors in effect

When working with software a lot of unexpected situations can happen:

  • The server crashes
  • The memory is full
  • The internet connection suddenly disappears

These are errors that developers do not anticipate occurring during normal program execution.

Since these errors are not expected, Effect does not track them at the type level.

However, the Effect runtime does keep track of these errors and provides several methods to aid in recovering from unexpected errors.

Effect internally never loses any information about the program execution.

All errors are collected inside the Cause module:

export type Cause<E> = Empty | Fail<E> | Die | Interrupt | Sequential<E> | Parallel<E>

Effect offers various APIs to access, inspect, and recover from expected and unexpected errors.

Let's learn about the first of them: Exit.