Skip to content

Expected Errors

Expected errors are tracked at the type level by the Effect data type in the “Error” channel:

1
import {
import Effect
Effect
} from "effect"
2
3
class
class HttpError
HttpError
{
4
readonly
(property) HttpError._tag: "HttpError"
_tag
= "HttpError"
5
}
6
7
const
const program: Effect.Effect<never, HttpError, never>
program
=
import Effect
Effect
.
const fail: <HttpError>(error: HttpError) => Effect.Effect<never, HttpError, never>
fail
(new
constructor HttpError(): HttpError
HttpError
())

The type of program shows that it can fail with an error of type HttpError:

const program: Effect<never, HttpError, never>

We use a class to represent the HttpError type above simply to gain access to both the error type and a free constructor. However, you can use whatever you like to model your error types.

It’s worth noting that added a readonly _tag field to the class to serve as a discriminant for the error:

class HttpError {
readonly _tag = "HttpError"
}

This will be useful later when we discuss APIs like Effect.catchTag.

The following program serves as an illustration of how errors are automatically tracked for you:

1
import {
import Effect
Effect
,
import Random
Random
} from "effect"
2
3
class
class HttpError
HttpError
{
4
readonly
(property) HttpError._tag: "HttpError"
_tag
= "HttpError"
5
}
6
7
class
class ValidationError
ValidationError
{
8
readonly
(property) ValidationError._tag: "ValidationError"
_tag
= "ValidationError"
9
}
10
11
const
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<number, never, never>> | YieldWrap<Effect.Effect<never, HttpError, never>> | YieldWrap<Effect.Effect<never, ValidationError, never>>, string>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
12
// Generate two random numbers between 0 and 1
13
const
const n1: number
n1
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
14
const
const n2: number
n2
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
15
16
// Simulate an HTTP error
17
if (
const n1: number
n1
< 0.5) {
18
yield*
import Effect
Effect
.
const fail: <HttpError>(error: HttpError) => Effect.Effect<never, HttpError, never>
fail
(new
constructor HttpError(): HttpError
HttpError
())
19
}
20
// Simulate a validation error
21
if (
const n2: number
n2
< 0.5) {
22
yield*
import Effect
Effect
.
const fail: <ValidationError>(error: ValidationError) => Effect.Effect<never, ValidationError, never>
fail
(new
constructor ValidationError(): ValidationError
ValidationError
())
23
}
24
25
return "some result"
26
})

Effect automatically keeps track of the possible errors that can occur during the execution of the program:

const program: Effect<string, HttpError | ValidationError, never>

indicating that it can potentially fail with either a HttpError or a ValidationError.

When working with APIs like Effect.gen, Effect.map, Effect.flatMap, Effect.andThen and Effect.all, it’s important to understand how they handle errors. These APIs are designed to short-circuit the execution upon encountering the first error.

What does this mean for you as a developer? Well, let’s say you have a chain of operations or a collection of effects to be executed in sequence. If any error occurs during the execution of one of these effects, the remaining computations will be skipped, and the error will be propagated to the final result.

In simpler terms, the short-circuiting behavior ensures that if something goes wrong at any step of your program, it won’t waste time executing unnecessary computations. Instead, it will immediately stop and return the error to let you know that something went wrong.

Example

1
import {
import Effect
Effect
,
import Console
Console
} from "effect"
2
3
// Define three effects representing different tasks.
4
const
const task1: Effect.Effect<void, never, never>
task1
=
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log
("Executing task1...")
5
const
const task2: Effect.Effect<never, string, never>
task2
=
import Effect
Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>
fail
("Something went wrong!")
6
const
const task3: Effect.Effect<void, never, never>
task3
=
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log
("Executing task3...")
7
8
// Compose the three tasks to run them in sequence.
9
// If one of the tasks fails, the subsequent tasks won't be executed.
10
const
const program: Effect.Effect<void, string, never>
program
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>> | YieldWrap<Effect.Effect<never, string, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
11
yield*
const task1: Effect.Effect<void, never, never>
task1
12
// After task1, task2 is executed, but it fails with an error
13
yield*
const task2: Effect.Effect<never, string, never>
task2
14
// This computation won't be executed because the previous one fails
15
yield*
const task3: Effect.Effect<void, never, never>
task3
16
})
17
18
import Effect
Effect
.
const runPromiseExit: <void, string>(effect: Effect.Effect<void, string, never>, options?: { readonly signal?: AbortSignal; } | undefined) => Promise<Exit<void, string>>

Runs an `Effect` workflow, returning a `Promise` which resolves with the `Exit` value of the workflow.

runPromiseExit
(
const program: Effect.Effect<void, string, never>
program
).
(method) Promise<Exit<void, string>>.then<void, never>(onfulfilled?: ((value: Exit<void, string>) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>

Attaches callbacks for the resolution and/or rejection of the Promise.

then
(
namespace console var console: Console

The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```

console
.
(method) globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.

log
)
19
/*
20
Output:
21
Executing task1...
22
{
23
_id: 'Exit',
24
_tag: 'Failure',
25
cause: { _id: 'Cause', _tag: 'Fail', failure: 'Something went wrong!' }
26
}
27
*/

This code snippet demonstrates the short-circuiting behavior when an error occurs. Each operation depends on the successful execution of the previous one. If any error occurs, the execution is short-circuited, and the error is propagated. In this specific example, task3 is never executed because an error occurs in task2.

The Effect.either function transforms an Effect<A, E, R> into an effect that encapsulates both potential failure and success within an Either data type:

Effect<A, E, R> -> Effect<Either<A, E>, never, R>

The resulting effect cannot fail because the potential failure is now represented within the Either’s Left type. The error type of the returned Effect is specified as never, confirming that the effect is structured to not fail.

By yielding an Either, we gain the ability to “pattern match” on this type to handle both failure and success cases within the generator function.

1
import {
import Effect
Effect
,
import Either
Either
,
import Random
Random
} from "effect"
2
19 collapsed lines
3
class
class HttpError
HttpError
{
4
readonly
(property) HttpError._tag: "HttpError"
_tag
= "HttpError"
5
}
6
7
class
class ValidationError
ValidationError
{
8
readonly
(property) ValidationError._tag: "ValidationError"
_tag
= "ValidationError"
9
}
10
11
const
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<number, never, never>> | YieldWrap<Effect.Effect<never, HttpError, never>> | YieldWrap<Effect.Effect<never, ValidationError, never>>, string>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
12
const
const n1: number
n1
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
13
const
const n2: number
n2
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
14
if (
const n1: number
n1
< 0.5) {
15
yield*
import Effect
Effect
.
const fail: <HttpError>(error: HttpError) => Effect.Effect<never, HttpError, never>
fail
(new
constructor HttpError(): HttpError
HttpError
())
16
}
17
if (
const n2: number
n2
< 0.5) {
18
yield*
import Effect
Effect
.
const fail: <ValidationError>(error: ValidationError) => Effect.Effect<never, ValidationError, never>
fail
(new
constructor ValidationError(): ValidationError
ValidationError
())
19
}
20
return "some result"
21
})
22
23
const
const recovered: Effect.Effect<string, never, never>
recovered
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<Either.Either<string, HttpError | ValidationError>, never, never>>, string>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
24
const
const failureOrSuccess: Either.Either<string, HttpError | ValidationError>
failureOrSuccess
= yield*
import Effect
Effect
.
const either: <string, HttpError | ValidationError, never>(self: Effect.Effect<string, HttpError | ValidationError, never>) => Effect.Effect<...>

Returns an effect whose failure and success have been lifted into an `Either`. The resulting effect cannot fail, because the failure case has been exposed as part of the `Either` success case. This method is useful for recovering from effects that may fail. The error parameter of the returned `Effect` is `never`, since it is guaranteed the effect does not model failure.

either
(
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
)
25
if (
import Either
Either
.
const isLeft: <string, HttpError | ValidationError>(self: Either.Either<string, HttpError | ValidationError>) => self is Either.Left<HttpError | ValidationError, string>

Determine if a `Either` is a `Left`.

isLeft
(
const failureOrSuccess: Either.Either<string, HttpError | ValidationError>
failureOrSuccess
)) {
26
// Failure case: you can extract the error from the `left` property
27
const
const error: HttpError | ValidationError
error
=
const failureOrSuccess: Either.Left<HttpError | ValidationError, string>
failureOrSuccess
.
(property) Left<HttpError | ValidationError, string>.left: HttpError | ValidationError
left
28
return `Recovering from ${
const error: HttpError | ValidationError
error
.
(property) _tag: "HttpError" | "ValidationError"
_tag
}`
29
} else {
30
// Success case: you can extract the value from the `right` property
31
return
const failureOrSuccess: Either.Right<HttpError | ValidationError, string>
failureOrSuccess
.
(property) Right<HttpError | ValidationError, string>.right: string
right
32
}
33
})

We can make the code less verbose by using the Either.match function, which directly accepts the two callback functions for handling errors and successful values:

1
import {
import Effect
Effect
,
import Either
Either
,
import Random
Random
} from "effect"
2
19 collapsed lines
3
class
class HttpError
HttpError
{
4
readonly
(property) HttpError._tag: "HttpError"
_tag
= "HttpError"
5
}
6
7
class
class ValidationError
ValidationError
{
8
readonly
(property) ValidationError._tag: "ValidationError"
_tag
= "ValidationError"
9
}
10
11
const
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<number, never, never>> | YieldWrap<Effect.Effect<never, HttpError, never>> | YieldWrap<Effect.Effect<never, ValidationError, never>>, string>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
12
const
const n1: number
n1
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
13
const
const n2: number
n2
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
14
if (
const n1: number
n1
< 0.5) {
15
yield*
import Effect
Effect
.
const fail: <HttpError>(error: HttpError) => Effect.Effect<never, HttpError, never>
fail
(new
constructor HttpError(): HttpError
HttpError
())
16
}
17
if (
const n2: number
n2
< 0.5) {
18
yield*
import Effect
Effect
.
const fail: <ValidationError>(error: ValidationError) => Effect.Effect<never, ValidationError, never>
fail
(new
constructor ValidationError(): ValidationError
ValidationError
())
19
}
20
return "some result"
21
})
22
23
const
const recovered: Effect.Effect<string, never, never>
recovered
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<Either.Either<string, HttpError | ValidationError>, never, never>>, string>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
24
const
const failureOrSuccess: Either.Either<string, HttpError | ValidationError>
failureOrSuccess
= yield*
import Effect
Effect
.
const either: <string, HttpError | ValidationError, never>(self: Effect.Effect<string, HttpError | ValidationError, never>) => Effect.Effect<...>

Returns an effect whose failure and success have been lifted into an `Either`. The resulting effect cannot fail, because the failure case has been exposed as part of the `Either` success case. This method is useful for recovering from effects that may fail. The error parameter of the returned `Effect` is `never`, since it is guaranteed the effect does not model failure.

either
(
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
)
25
return
import Either
Either
.
const match: <string, HttpError | ValidationError, string, string>(self: Either.Either<string, HttpError | ValidationError>, options: { ...; }) => string (+1 overload)

Takes two functions and an `Either` value, if the value is a `Left` the inner value is applied to the `onLeft function, if the value is a `Right` the inner value is applied to the `onRight` function.

match
(
const failureOrSuccess: Either.Either<string, HttpError | ValidationError>
failureOrSuccess
, {
26
(property) onLeft: (left: HttpError | ValidationError) => string
onLeft
: (
(parameter) error: HttpError | ValidationError
error
) => `Recovering from ${
(parameter) error: HttpError | ValidationError
error
.
(property) _tag: "HttpError" | "ValidationError"
_tag
}`,
27
(property) onRight: (right: string) => string
onRight
: (
(parameter) value: string
value
) =>
(parameter) value: string
value
// Do nothing in case of success
28
})
29
})

The Effect.catchAll function allows you to catch any error that occurs in the program and provide a fallback.

1
import {
import Effect
Effect
,
import Random
Random
} from "effect"
2
19 collapsed lines
3
class
class HttpError
HttpError
{
4
readonly
(property) HttpError._tag: "HttpError"
_tag
= "HttpError"
5
}
6
7
class
class ValidationError
ValidationError
{
8
readonly
(property) ValidationError._tag: "ValidationError"
_tag
= "ValidationError"
9
}
10
11
const
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<number, never, never>> | YieldWrap<Effect.Effect<never, HttpError, never>> | YieldWrap<Effect.Effect<never, ValidationError, never>>, string>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
12
const
const n1: number
n1
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
13
const
const n2: number
n2
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
14
if (
const n1: number
n1
< 0.5) {
15
yield*
import Effect
Effect
.
const fail: <HttpError>(error: HttpError) => Effect.Effect<never, HttpError, never>
fail
(new
constructor HttpError(): HttpError
HttpError
())
16
}
17
if (
const n2: number
n2
< 0.5) {
18
yield*
import Effect
Effect
.
const fail: <ValidationError>(error: ValidationError) => Effect.Effect<never, ValidationError, never>
fail
(new
constructor ValidationError(): ValidationError
ValidationError
())
19
}
20
return "some result"
21
})
22
23
const
const recovered: Effect.Effect<string, never, never>
recovered
=
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
.
(method) Pipeable.pipe<Effect.Effect<string, HttpError | ValidationError, never>, Effect.Effect<string, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<string, HttpError | ValidationError, never>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
24
import Effect
Effect
.
const catchAll: <HttpError | ValidationError, string, never, never>(f: (e: HttpError | ValidationError) => Effect.Effect<string, never, never>) => <A, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+1 overload)

Recovers from all recoverable errors. **Note**: that `Effect.catchAll` will not recover from unrecoverable defects. To recover from both recoverable and unrecoverable errors use `Effect.catchAllCause`.

catchAll
((
(parameter) error: HttpError | ValidationError
error
) =>
25
import Effect
Effect
.
const succeed: <string>(value: string) => Effect.Effect<string, never, never>
succeed
(`Recovering from ${
(parameter) error: HttpError | ValidationError
error
.
(property) _tag: "HttpError" | "ValidationError"
_tag
}`)
26
)
27
)

We can observe that the type in the error channel has changed to never:

const recovered: Effect<string, never, never>

indicating that all errors have been handled.

Suppose we want to handle a specific error, such as HttpError.

1
import {
import Effect
Effect
,
import Random
Random
,
import Either
Either
} from "effect"
2
19 collapsed lines
3
class
class HttpError
HttpError
{
4
readonly
(property) HttpError._tag: "HttpError"
_tag
= "HttpError"
5
}
6
7
class
class ValidationError
ValidationError
{
8
readonly
(property) ValidationError._tag: "ValidationError"
_tag
= "ValidationError"
9
}
10
11
const
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<number, never, never>> | YieldWrap<Effect.Effect<never, HttpError, never>> | YieldWrap<Effect.Effect<never, ValidationError, never>>, string>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
12
const
const n1: number
n1
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
13
const
const n2: number
n2
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
14
if (
const n1: number
n1
< 0.5) {
15
yield*
import Effect
Effect
.
const fail: <HttpError>(error: HttpError) => Effect.Effect<never, HttpError, never>
fail
(new
constructor HttpError(): HttpError
HttpError
())
16
}
17
if (
const n2: number
n2
< 0.5) {
18
yield*
import Effect
Effect
.
const fail: <ValidationError>(error: ValidationError) => Effect.Effect<never, ValidationError, never>
fail
(new
constructor ValidationError(): ValidationError
ValidationError
())
19
}
20
return "some result"
21
})
22
23
const
const recovered: Effect.Effect<string, never, never>
recovered
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<Either.Either<string, HttpError | ValidationError>, never, never>>, string>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
24
const
const failureOrSuccess: Either.Either<string, HttpError | ValidationError>
failureOrSuccess
= yield*
import Effect
Effect
.
const either: <string, HttpError | ValidationError, never>(self: Effect.Effect<string, HttpError | ValidationError, never>) => Effect.Effect<...>

Returns an effect whose failure and success have been lifted into an `Either`. The resulting effect cannot fail, because the failure case has been exposed as part of the `Either` success case. This method is useful for recovering from effects that may fail. The error parameter of the returned `Effect` is `never`, since it is guaranteed the effect does not model failure.

either
(
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
)
25
if (
import Either
Either
.
const isLeft: <string, HttpError | ValidationError>(self: Either.Either<string, HttpError | ValidationError>) => self is Either.Left<HttpError | ValidationError, string>

Determine if a `Either` is a `Left`.

isLeft
(
const failureOrSuccess: Either.Either<string, HttpError | ValidationError>
failureOrSuccess
)) {
26
const
const error: HttpError | ValidationError
error
=
const failureOrSuccess: Either.Left<HttpError | ValidationError, string>
failureOrSuccess
.
(property) Left<HttpError | ValidationError, string>.left: HttpError | ValidationError
left
27
if (
const error: HttpError | ValidationError
error
.
(property) _tag: "HttpError" | "ValidationError"
_tag
=== "HttpError") {
28
return "Recovering from HttpError"
29
} else {
30
return "Recovering from ValidationError"
31
}
32
} else {
33
return
const failureOrSuccess: Either.Right<HttpError | ValidationError, string>
failureOrSuccess
.
(property) Right<HttpError | ValidationError, string>.right: string
right
34
}
35
})

We can observe that the type in the error channel of our program has changed to only show ValidationError:

const recovered: Effect<string, ValidationError, never>

indicating that HttpError has been handled.

If we also want to handle ValidationError, we can easily add another case to our code:

1
import {
import Effect
Effect
,
import Random
Random
,
import Either
Either
} from "effect"
2
19 collapsed lines
3
class
class HttpError
HttpError
{
4
readonly
(property) HttpError._tag: "HttpError"
_tag
= "HttpError"
5
}
6
7
class
class ValidationError
ValidationError
{
8
readonly
(property) ValidationError._tag: "ValidationError"
_tag
= "ValidationError"
9
}
10
11
const
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<number, never, never>> | YieldWrap<Effect.Effect<never, HttpError, never>> | YieldWrap<Effect.Effect<never, ValidationError, never>>, string>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
12
const
const n1: number
n1
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
13
const
const n2: number
n2
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
14
if (
const n1: number
n1
< 0.5) {
15
yield*
import Effect
Effect
.
const fail: <HttpError>(error: HttpError) => Effect.Effect<never, HttpError, never>
fail
(new
constructor HttpError(): HttpError
HttpError
())
16
}
17
if (
const n2: number
n2
< 0.5) {
18
yield*
import Effect
Effect
.
const fail: <ValidationError>(error: ValidationError) => Effect.Effect<never, ValidationError, never>
fail
(new
constructor ValidationError(): ValidationError
ValidationError
())
19
}
20
return "some result"
21
})
22
23
const
const recovered: Effect.Effect<string, never, never>
recovered
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<Either.Either<string, HttpError | ValidationError>, never, never>>, string>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
24
const
const failureOrSuccess: Either.Either<string, HttpError | ValidationError>
failureOrSuccess
= yield*
import Effect
Effect
.
const either: <string, HttpError | ValidationError, never>(self: Effect.Effect<string, HttpError | ValidationError, never>) => Effect.Effect<...>

Returns an effect whose failure and success have been lifted into an `Either`. The resulting effect cannot fail, because the failure case has been exposed as part of the `Either` success case. This method is useful for recovering from effects that may fail. The error parameter of the returned `Effect` is `never`, since it is guaranteed the effect does not model failure.

either
(
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
)
25
if (
import Either
Either
.
const isLeft: <string, HttpError | ValidationError>(self: Either.Either<string, HttpError | ValidationError>) => self is Either.Left<HttpError | ValidationError, string>

Determine if a `Either` is a `Left`.

isLeft
(
const failureOrSuccess: Either.Either<string, HttpError | ValidationError>
failureOrSuccess
)) {
26
const
const error: HttpError | ValidationError
error
=
const failureOrSuccess: Either.Left<HttpError | ValidationError, string>
failureOrSuccess
.
(property) Left<HttpError | ValidationError, string>.left: HttpError | ValidationError
left
27
if (
const error: HttpError | ValidationError
error
.
(property) _tag: "HttpError" | "ValidationError"
_tag
=== "HttpError") {
28
return "Recovering from HttpError"
29
} else {
30
return "Recovering from ValidationError"
31
}
32
} else {
33
return
const failureOrSuccess: Either.Right<HttpError | ValidationError, string>
failureOrSuccess
.
(property) Right<HttpError | ValidationError, string>.right: string
right
34
}
35
})

We can observe that the type in the error channel has changed to never:

const recovered: Effect<string, never, never>

indicating that all errors have been handled.

If we want to catch and recover from only some types of errors and effectfully attempt recovery, we can use the Effect.catchSome function:

1
import {
import Effect
Effect
,
import Random
Random
,
import Option
Option
} from "effect"
2
19 collapsed lines
3
class
class HttpError
HttpError
{
4
readonly
(property) HttpError._tag: "HttpError"
_tag
= "HttpError"
5
}
6
7
class
class ValidationError
ValidationError
{
8
readonly
(property) ValidationError._tag: "ValidationError"
_tag
= "ValidationError"
9
}
10
11
const
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<number, never, never>> | YieldWrap<Effect.Effect<never, HttpError, never>> | YieldWrap<Effect.Effect<never, ValidationError, never>>, string>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
12
const
const n1: number
n1
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
13
const
const n2: number
n2
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
14
if (
const n1: number
n1
< 0.5) {
15
yield*
import Effect
Effect
.
const fail: <HttpError>(error: HttpError) => Effect.Effect<never, HttpError, never>
fail
(new
constructor HttpError(): HttpError
HttpError
())
16
}
17
if (
const n2: number
n2
< 0.5) {
18
yield*
import Effect
Effect
.
const fail: <ValidationError>(error: ValidationError) => Effect.Effect<never, ValidationError, never>
fail
(new
constructor ValidationError(): ValidationError
ValidationError
())
19
}
20
return "some result"
21
})
22
23
const
const recovered: Effect.Effect<string, HttpError | ValidationError, never>
recovered
=
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
.
(method) Pipeable.pipe<Effect.Effect<string, HttpError | ValidationError, never>, Effect.Effect<string, HttpError | ValidationError, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
24
import Effect
Effect
.
const catchSome: <HttpError | ValidationError, string, never, never>(pf: (e: HttpError | ValidationError) => Option.Option<Effect.Effect<string, never, never>>) => <A, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+1 overload)

Recovers from some or all of the error cases.

catchSome
((
(parameter) error: HttpError | ValidationError
error
) => {
25
if (
(parameter) error: HttpError | ValidationError
error
.
(property) _tag: "HttpError" | "ValidationError"
_tag
=== "HttpError") {
26
return
import Option
Option
.
const some: <Effect.Effect<string, never, never>>(value: Effect.Effect<string, never, never>) => Option.Option<Effect.Effect<string, never, never>>

Creates a new `Option` that wraps the given value.

some
(
import Effect
Effect
.
const succeed: <string>(value: string) => Effect.Effect<string, never, never>
succeed
("Recovering from HttpError"))
27
}
28
return
import Option
Option
.
const none: <never>() => Option.Option<never>

Creates a new `Option` that represents the absence of a value.

none
()
29
})
30
)

In the code above, Effect.catchSome takes a function that examines the error (error) and decides whether to attempt recovery or not. If the error matches a specific condition, recovery can be attempted by returning Option.some(effect). If no recovery is possible, you can simply return Option.none().

It’s important to note that while Effect.catchSome lets you catch specific errors, it doesn’t alter the error type itself. Therefore, the resulting effect will still have the same error type as the original effect:

const recovered: Effect<string, HttpError | ValidationError, never>

Similar to Effect.catchSome, the function Effect.catchIf allows you to recover from specific errors based on a predicate:

1
import {
import Effect
Effect
,
import Random
Random
} from "effect"
2
3
class
class HttpError
HttpError
{
4
readonly
(property) HttpError._tag: "HttpError"
_tag
= "HttpError"
5
}
6
7
class
class ValidationError
ValidationError
{
8
readonly
(property) ValidationError._tag: "ValidationError"
_tag
= "ValidationError"
9
}
10
11
const
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<number, never, never>> | YieldWrap<Effect.Effect<never, HttpError, never>> | YieldWrap<Effect.Effect<never, ValidationError, never>>, string>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
12
const
const n1: number
n1
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
13
const
const n2: number
n2
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
14
if (
const n1: number
n1
< 0.5) {
15
yield*
import Effect
Effect
.
const fail: <HttpError>(error: HttpError) => Effect.Effect<never, HttpError, never>
fail
(new
constructor HttpError(): HttpError
HttpError
())
16
}
17
if (
const n2: number
n2
< 0.5) {
18
yield*
import Effect
Effect
.
const fail: <ValidationError>(error: ValidationError) => Effect.Effect<never, ValidationError, never>
fail
(new
constructor ValidationError(): ValidationError
ValidationError
())
19
}
20
return "some result"
21
})
22
23
const
const recovered: Effect.Effect<string, ValidationError, never>
recovered
=
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
.
(method) Pipeable.pipe<Effect.Effect<string, HttpError | ValidationError, never>, Effect.Effect<string, ValidationError, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
24
import Effect
Effect
.
const catchIf: <HttpError | ValidationError, HttpError, string, never, never>(refinement: Refinement<HttpError | ValidationError, HttpError>, f: (e: HttpError) => Effect.Effect<...>) => <A, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+3 overloads)

Recovers from errors that match the given predicate.

catchIf
(
25
(
(parameter) error: HttpError | ValidationError
error
) =>
(parameter) error: HttpError | ValidationError
error
.
(property) _tag: "HttpError" | "ValidationError"
_tag
=== "HttpError",
26
() =>
import Effect
Effect
.
const succeed: <string>(value: string) => Effect.Effect<string, never, never>
succeed
("Recovering from HttpError")
27
)
28
)

It’s important to note that for TypeScript versions < 5.5, while Effect.catchIf lets you catch specific errors, it doesn’t alter the error type itself. Therefore, the resulting effect will still have the same error type as the original effect:

const recovered: Effect<string, HttpError | ValidationError, never>

In TypeScript versions >= 5.5, improved type narrowing causes the resulting error type to be inferred as ValidationError.

For TypeScript versions < 5.5, if you provide a user-defined type guard instead of a predicate, the resulting error type will be pruned, returning an Effect<string, ValidationError, never>:

1
import {
import Effect
Effect
,
import Random
Random
} from "effect"
2
19 collapsed lines
3
class
class HttpError
HttpError
{
4
readonly
(property) HttpError._tag: "HttpError"
_tag
= "HttpError"
5
}
6
7
class
class ValidationError
ValidationError
{
8
readonly
(property) ValidationError._tag: "ValidationError"
_tag
= "ValidationError"
9
}
10
11
const
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<number, never, never>> | YieldWrap<Effect.Effect<never, HttpError, never>> | YieldWrap<Effect.Effect<never, ValidationError, never>>, string>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
12
const
const n1: number
n1
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
13
const
const n2: number
n2
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
14
if (
const n1: number
n1
< 0.5) {
15
yield*
import Effect
Effect
.
const fail: <HttpError>(error: HttpError) => Effect.Effect<never, HttpError, never>
fail
(new
constructor HttpError(): HttpError
HttpError
())
16
}
17
if (
const n2: number
n2
< 0.5) {
18
yield*
import Effect
Effect
.
const fail: <ValidationError>(error: ValidationError) => Effect.Effect<never, ValidationError, never>
fail
(new
constructor ValidationError(): ValidationError
ValidationError
())
19
}
20
return "some result"
21
})
22
23
const
const recovered: Effect.Effect<string, ValidationError, never>
recovered
=
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
.
(method) Pipeable.pipe<Effect.Effect<string, HttpError | ValidationError, never>, Effect.Effect<string, ValidationError, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
24
import Effect
Effect
.
const catchIf: <HttpError | ValidationError, HttpError, string, never, never>(refinement: Refinement<HttpError | ValidationError, HttpError>, f: (e: HttpError) => Effect.Effect<...>) => <A, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+3 overloads)

Recovers from errors that match the given predicate.

catchIf
(
25
(
(parameter) error: HttpError | ValidationError
error
):
(parameter) error: HttpError | ValidationError
error
is
class HttpError
HttpError
=>
(parameter) error: HttpError | ValidationError
error
.
(property) _tag: "HttpError" | "ValidationError"
_tag
=== "HttpError",
26
() =>
import Effect
Effect
.
const succeed: <string>(value: string) => Effect.Effect<string, never, never>
succeed
("Recovering from HttpError")
27
)
28
)

If your program’s errors are all tagged with a _tag field that acts as a discriminator you can use the Effect.catchTag function to catch and handle specific errors with precision.

1
import {
import Effect
Effect
,
import Random
Random
} from "effect"
2
19 collapsed lines
3
class
class HttpError
HttpError
{
4
readonly
(property) HttpError._tag: "HttpError"
_tag
= "HttpError"
5
}
6
7
class
class ValidationError
ValidationError
{
8
readonly
(property) ValidationError._tag: "ValidationError"
_tag
= "ValidationError"
9
}
10
11
const
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<number, never, never>> | YieldWrap<Effect.Effect<never, HttpError, never>> | YieldWrap<Effect.Effect<never, ValidationError, never>>, string>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
12
const
const n1: number
n1
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
13
const
const n2: number
n2
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
14
if (
const n1: number
n1
< 0.5) {
15
yield*
import Effect
Effect
.
const fail: <HttpError>(error: HttpError) => Effect.Effect<never, HttpError, never>
fail
(new
constructor HttpError(): HttpError
HttpError
())
16
}
17
if (
const n2: number
n2
< 0.5) {
18
yield*
import Effect
Effect
.
const fail: <ValidationError>(error: ValidationError) => Effect.Effect<never, ValidationError, never>
fail
(new
constructor ValidationError(): ValidationError
ValidationError
())
19
}
20
return "some result"
21
})
22
23
const
const recovered: Effect.Effect<string, ValidationError, never>
recovered
=
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
.
(method) Pipeable.pipe<Effect.Effect<string, HttpError | ValidationError, never>, Effect.Effect<string, ValidationError, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
24
import Effect
Effect
.
const catchTag: <"HttpError", HttpError | ValidationError, string, never, never>(k: "HttpError", f: (e: HttpError) => Effect.Effect<string, never, never>) => <A, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+1 overload)

Recovers from the specified tagged error.

catchTag
("HttpError", (
(parameter) _HttpError: HttpError
_HttpError
) =>
25
import Effect
Effect
.
const succeed: <string>(value: string) => Effect.Effect<string, never, never>
succeed
("Recovering from HttpError")
26
)
27
)

In the example above, the Effect.catchTag function allows us to handle HttpError specifically. If a HttpError occurs during the execution of the program, the provided error handler function will be invoked, and the program will proceed with the recovery logic specified within the handler.

We can observe that the type in the error channel of our program has changed to only show ValidationError, indicating that HttpError has been handled.

If we also wanted to handle ValidationError, we can simply add another catchTag:

1
import {
import Effect
Effect
,
import Random
Random
} from "effect"
2
19 collapsed lines
3
class
class HttpError
HttpError
{
4
readonly
(property) HttpError._tag: "HttpError"
_tag
= "HttpError"
5
}
6
7
class
class ValidationError
ValidationError
{
8
readonly
(property) ValidationError._tag: "ValidationError"
_tag
= "ValidationError"
9
}
10
11
const
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<number, never, never>> | YieldWrap<Effect.Effect<never, HttpError, never>> | YieldWrap<Effect.Effect<never, ValidationError, never>>, string>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
12
const
const n1: number
n1
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
13
const
const n2: number
n2
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
14
if (
const n1: number
n1
< 0.5) {
15
yield*
import Effect
Effect
.
const fail: <HttpError>(error: HttpError) => Effect.Effect<never, HttpError, never>
fail
(new
constructor HttpError(): HttpError
HttpError
())
16
}
17
if (
const n2: number
n2
< 0.5) {
18
yield*
import Effect
Effect
.
const fail: <ValidationError>(error: ValidationError) => Effect.Effect<never, ValidationError, never>
fail
(new
constructor ValidationError(): ValidationError
ValidationError
())
19
}
20
return "some result"
21
})
22
23
const
const recovered: Effect.Effect<string, never, never>
recovered
=
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
.
(method) Pipeable.pipe<Effect.Effect<string, HttpError | ValidationError, never>, Effect.Effect<string, ValidationError, never>, Effect.Effect<...>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
24
import Effect
Effect
.
const catchTag: <"HttpError", HttpError | ValidationError, string, never, never>(k: "HttpError", f: (e: HttpError) => Effect.Effect<string, never, never>) => <A, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+1 overload)

Recovers from the specified tagged error.

catchTag
("HttpError", (
(parameter) _HttpError: HttpError
_HttpError
) =>
25
import Effect
Effect
.
const succeed: <string>(value: string) => Effect.Effect<string, never, never>
succeed
("Recovering from HttpError")
26
),
27
import Effect
Effect
.
const catchTag: <"ValidationError", ValidationError, string, never, never>(k: "ValidationError", f: (e: ValidationError) => Effect.Effect<string, never, never>) => <A, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+1 overload)

Recovers from the specified tagged error.

catchTag
("ValidationError", (
(parameter) _ValidationError: ValidationError
_ValidationError
) =>
28
import Effect
Effect
.
const succeed: <string>(value: string) => Effect.Effect<string, never, never>
succeed
("Recovering from ValidationError")
29
)
30
)

We can observe that the type in the error channel of our program has changed to never, indicating that all errors have been handled.

Instead of using the Effect.catchTag function multiple times to handle individual error types, we have a more convenient option called Effect.catchTags. With Effect.catchTags, we can handle multiple errors in a single block of code.

1
import {
import Effect
Effect
,
import Random
Random
} from "effect"
2
19 collapsed lines
3
class
class HttpError
HttpError
{
4
readonly
(property) HttpError._tag: "HttpError"
_tag
= "HttpError"
5
}
6
7
class
class ValidationError
ValidationError
{
8
readonly
(property) ValidationError._tag: "ValidationError"
_tag
= "ValidationError"
9
}
10
11
const
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<number, never, never>> | YieldWrap<Effect.Effect<never, HttpError, never>> | YieldWrap<Effect.Effect<never, ValidationError, never>>, string>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
12
const
const n1: number
n1
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
13
const
const n2: number
n2
= yield*
import Random
Random
.
const next: Effect.Effect<number, never, never>

Returns the next numeric value from the pseudo-random number generator.

next
14
if (
const n1: number
n1
< 0.5) {
15
yield*
import Effect
Effect
.
const fail: <HttpError>(error: HttpError) => Effect.Effect<never, HttpError, never>
fail
(new
constructor HttpError(): HttpError
HttpError
())
16
}
17
if (
const n2: number
n2
< 0.5) {
18
yield*
import Effect
Effect
.
const fail: <ValidationError>(error: ValidationError) => Effect.Effect<never, ValidationError, never>
fail
(new
constructor ValidationError(): ValidationError
ValidationError
())
19
}
20
return "some result"
21
})
22
23
const
const recovered: Effect.Effect<string, never, never>
recovered
=
const program: Effect.Effect<string, HttpError | ValidationError, never>
program
.
(method) Pipeable.pipe<Effect.Effect<string, HttpError | ValidationError, never>, Effect.Effect<string, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<string, HttpError | ValidationError, never>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
24
import Effect
Effect
.
const catchTags: <HttpError | ValidationError, { HttpError: (_HttpError: HttpError) => Effect.Effect<string, never, never>; ValidationError: (_ValidationError: ValidationError) => Effect.Effect<...>; }>(cases: { ...; }) => <A, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+1 overload)

Recovers from the specified tagged errors.

catchTags
({
25
(property) HttpError: (_HttpError: HttpError) => Effect.Effect<string, never, never>
HttpError
: (
(parameter) _HttpError: HttpError
_HttpError
) =>
26
import Effect
Effect
.
const succeed: <string>(value: string) => Effect.Effect<string, never, never>
succeed
(`Recovering from HttpError`),
27
(property) ValidationError: (_ValidationError: ValidationError) => Effect.Effect<string, never, never>
ValidationError
: (
(parameter) _ValidationError: ValidationError
_ValidationError
) =>
28
import Effect
Effect
.
const succeed: <string>(value: string) => Effect.Effect<string, never, never>
succeed
(`Recovering from ValidationError`)
29
})
30
)

In the above example, instead of using Effect.catchTag multiple times to handle individual errors, we utilize the Effect.catchTags combinator. This combinator takes an object where each property represents a specific error _tag ("HttpError" and "ValidationError" in this case), and the corresponding value is the error handler function to be executed when that particular error occurs.