Errors are an inevitable part of programming, and they can arise from various sources like failures, defects, fiber interruptions, or combinations of these. This guide explains how to use the Effect.sandbox function to isolate and understand the causes of errors in your Effect-based code.
sandbox / unsandbox
The Effect.sandbox function allows you to encapsulate all the potential causes of an error in an effect. It exposes the full cause of an effect, whether it’s due to a failure, defect, fiber interruption, or a combination of these factors.
In simple terms, it takes an effect Effect<A, E, R> and transforms it into an effect Effect<A, Cause<E>, R> where the error channel now contains a detailed cause of the error.
Syntax
Effect<A, E, R>-> Effect<A, Cause<E>, R>
By using the Effect.sandbox function, you gain access to the underlying causes of exceptional effects. These causes are represented as a type of Cause<E> and are available in the error channel of the Effect data type.
Once you have exposed the causes, you can utilize standard error-handling operators like Effect.catchAll and Effect.catchTags to handle errors more effectively. These operators allow you to respond to specific error conditions.
If needed, we can undo the sandboxing operation with Effect.unsandbox.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
constas: <string>(value:string) => <A, E, R>(self:Effect.Effect<A, E, R>) =>Effect.Effect<string, E, R> (+1overload)
Replaces the value inside an effect with a constant value.
Details
This function allows you to ignore the original value inside an effect and
replace it with a constant value.
When to Use
It is useful when you no longer need the value produced by an effect but want
to ensure that the effect completes successfully with a specific constant
result instead. For instance, you can replace the value produced by a
computation with a predefined value, ignoring what was calculated before.
@example
// Title: Replacing a Value
import { pipe, Effect } from"effect"
// Replaces the value 5 with the constant "new value"
Transforms an effect to expose detailed error causes.
Details
This function enhances an effect by providing detailed information about any
error, defect, or interruption that may occur during its execution. It
modifies the error channel of the effect so that it includes a full cause of
the failure, wrapped in a Cause<E> type.
After applying this function, you can use operators like
catchAll
and
catchTags
to handle specific types of errors.
If you no longer need the detailed cause information, you can revert the
changes using
unsandbox
to return to the original error-handling
behavior.
@see ― unsandbox to restore the original error handling.
@example
import { Effect, Console } from"effect"
// ┌─── Effect<string, Error, never>
// ▼
consttask= Effect.fail(newError("Oh uh!")).pipe(
Effect.as("primary result")
)
// ┌─── Effect<string, Cause<Error>, never>
// ▼
constsandboxed= Effect.sandbox(task)
constprogram= Effect.catchTags(sandboxed, {
Die: (cause) =>
Console.log(`Caught a defect: ${cause.defect}`).pipe(
Effect.as("fallback result on defect")
),
Interrupt: (cause) =>
Console.log(`Caught a defect: ${cause.fiberId}`).pipe(
Effect.as("fallback result on fiber interruption")
),
Fail: (cause) =>
Console.log(`Caught a defect: ${cause.error}`).pipe(
Effect.as("fallback result on failure")
)
})
// Restore the original error handling with unsandbox
Handles multiple errors in a single block of code using their _tag field.
When to Use
catchTags is a convenient way to handle multiple error types at
once. Instead of using
catchTag
multiple times, you can pass an
object where each key is an error type's _tag, and the value is the handler
for that specific error. This allows you to catch and recover from multiple
error types in a single call.
The error type must have a readonly _tag field to use catchTag. This
field is used to identify and match errors.
@example
// Title: Handling Multiple Tagged Error Types at Once
constas: <string>(value:string) => <A, E, R>(self:Effect.Effect<A, E, R>) =>Effect.Effect<string, E, R> (+1overload)
Replaces the value inside an effect with a constant value.
Details
This function allows you to ignore the original value inside an effect and
replace it with a constant value.
When to Use
It is useful when you no longer need the value produced by an effect but want
to ensure that the effect completes successfully with a specific constant
result instead. For instance, you can replace the value produced by a
computation with a predefined value, ignoring what was calculated before.
@example
// Title: Replacing a Value
import { pipe, Effect } from"effect"
// Replaces the value 5 with the constant "new value"
constas: <string>(value:string) => <A, E, R>(self:Effect.Effect<A, E, R>) =>Effect.Effect<string, E, R> (+1overload)
Replaces the value inside an effect with a constant value.
Details
This function allows you to ignore the original value inside an effect and
replace it with a constant value.
When to Use
It is useful when you no longer need the value produced by an effect but want
to ensure that the effect completes successfully with a specific constant
result instead. For instance, you can replace the value produced by a
computation with a predefined value, ignoring what was calculated before.
@example
// Title: Replacing a Value
import { pipe, Effect } from"effect"
// Replaces the value 5 with the constant "new value"
constas: <string>(value:string) => <A, E, R>(self:Effect.Effect<A, E, R>) =>Effect.Effect<string, E, R> (+1overload)
Replaces the value inside an effect with a constant value.
Details
This function allows you to ignore the original value inside an effect and
replace it with a constant value.
When to Use
It is useful when you no longer need the value produced by an effect but want
to ensure that the effect completes successfully with a specific constant
result instead. For instance, you can replace the value produced by a
computation with a predefined value, ignoring what was calculated before.
@example
// Title: Replacing a Value
import { pipe, Effect } from"effect"
// Replaces the value 5 with the constant "new value"
The unsandbox function is used to revert an effect that has been
sandboxed by
sandbox
. When you apply unsandbox, the
effect's error channel is restored to its original state, without the
detailed Cause<E> information. This means that any underlying causes of
errors, defects, or fiber interruptions are no longer exposed in the error
channel.
This function is useful when you want to remove the detailed error tracking
provided by sandbox and return to the standard error handling for
your effect. Once unsandboxed, the effect behaves as if sandbox was
never applied.
@see ― sandbox to expose the full cause of failures, defects, or interruptions.
Executes an effect and returns the result as a Promise.
Details
This function runs an effect and converts its result into a Promise. If the
effect succeeds, the Promise will resolve with the successful result. If
the effect fails, the Promise will reject with an error, which includes the
failure details of the effect.
The optional options parameter allows you to pass an AbortSignal for
cancellation, enabling more fine-grained control over asynchronous tasks.
When to Use
Use this function when you need to execute an effect and work with its result
in a promise-based system, such as when integrating with third-party
libraries that expect Promise results.
@see ― runPromiseExit for a version that returns an Exit type instead
of rejecting.
@example
// Title: Running a Successful Effect as a Promise
Attaches callbacks for the resolution and/or rejection of the Promise.
@param ― onfulfilled The callback to execute when the Promise is resolved.
@param ― onrejected The callback to execute when the Promise is rejected.
@returns ― A Promise for the completion of which ever callback is executed.
then(
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 and
process.stderr. 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 for
more information.
Example using the global console:
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(newError('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
constname='Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
constout=getStreamSomehow();
consterr=getStreamSomehow();
constmyConsole=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(newError('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
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)
(the arguments are all passed to util.format()).