# Result & Exit

So far errors have flowed through the error channel. Sometimes you want the
opposite: to *capture* the outcome as an ordinary value you can pattern-match on.
Effect offers two such types.

- **`Result<A, E>`** is a synchronous, two-case value: `Success<A>` or
  `Failure<E>`. It is the v4 replacement for `Either`, and models a computation
  that either produced a value or a typed error — nothing more.
- **`Exit<A, E>`** is the *outcome of running an effect*: `Success<A>` or a
  `Failure` carrying a full [`Cause<E>`](#cause--the-full-story). Because a fiber
  can fail with typed errors, defects, *and* interruptions at once, the failure
  side is a `Cause`, not a bare `E`.

```ts
import { Effect, Result } from "effect"

// `Effect.result` moves the error into the success channel as a Result,
// so the effect itself can no longer fail.
//      ┌─── Effect<Result<number, string>, never>
//      ▼
const program = Effect.fail("boom").pipe(
  Effect.as(42),
  Effect.result
)

const handled = program.pipe(
  Effect.map((result) =>
    Result.match(result, {
      onSuccess: (value) => `ok: ${value}`,
      onFailure: (error) => `error: ${error}`
    })
  )
)
```

## Which capture function should I reach for?

Effect gives you three "outcome encapsulation" combinators plus two `run*Exit`
runners. The right choice depends on *what* you want to capture and *where* you
are standing.

| You want…                                          | Reach for             | One-liner |
| -------------------------------------------------- | --------------------- | --------- |
| The typed outcome, inside a running effect         | `Effect.result`       | `yield* Effect.result(eff)` → `Result<A, E>` |
| Only "did it succeed?", discarding the error value | `Effect.option`       | `yield* Effect.option(eff)` → `Option<A>` |
| The *full* outcome (errors + defects + interrupts) | `Effect.exit`         | `yield* Effect.exit(eff)` → `Exit<A, E>` |
| To run synchronously and get an `Exit`             | `Effect.runSyncExit`  | `Effect.runSyncExit(eff)` → `Exit<A, E>` |
| To run as a `Promise` and get an `Exit`            | `Effect.runPromiseExit` | `await Effect.runPromiseExit(eff)` → `Exit<A, E>` |

The key distinction: **`Result` (and `Option`) only capture typed, recoverable
failures.** Defects and interruptions are *not* folded into a `Result` — they
still fail the surrounding effect. **`Exit` captures everything**, which is why
its failure side is a `Cause`.

## Result — success or typed error as a value

A `Result` is a discriminated union with `_tag` of `"Success"` or `"Failure"`.
Access the payload through `.success` or `.failure` after narrowing, or fold it
with `Result.match`.

```ts
import { Result } from "effect"

const ok = Result.succeed(42) // Result<number, never>
const err = Result.fail("nope") // Result<never, string>

// Narrow with the type guards...
if (Result.isSuccess(ok)) {
  console.log(ok.success) // 42
}
if (Result.isFailure(err)) {
  console.log(err.failure) // "nope"
}

// ...or fold both cases at once.
const message = Result.match(err, {
  onSuccess: (value) => `value ${value}`,
  onFailure: (error) => `failed: ${error}`
})
```

Use `Effect.result` to turn an `Effect<A, E>` into an `Effect<Result<A, E>>` —
handy when you want to inspect the outcome inside a `gen` block without
short-circuiting on failure.

```ts
import { Effect, Result } from "effect"

declare const fetchUser: (id: number) => Effect.Effect<string, Error>

const program = Effect.gen(function* () {
  // `yield* Effect.result(...)` never throws — it yields a Result.
  const result = yield* Effect.result(fetchUser(1))
  if (Result.isFailure(result)) {
    yield* Effect.log(`recovering from ${result.failure.message}`)
    return "default"
  }
  return result.success
})
```

This is the value-level counterpart to [catching errors](https://effect.plants.sh/error-management/catching-errors/):
instead of recovering with a combinator, you capture the outcome as data and
branch on it imperatively. For the full `Result` API — `map`, `flatMap`,
`getOrElse`, `gen`, do-notation, and the rest — see
[Result](https://effect.plants.sh/data-types/result/).

## Exit — the full outcome of a run

An `Exit` is what you get when you *run* an effect to completion. The runtime
returns one from `Effect.runSyncExit` / `Effect.runPromiseExit`, and you can
capture one mid-program with `Effect.exit`.

```ts
import { Effect, Exit } from "effect"

const program = Effect.succeed(42)

const exit = Effect.runSyncExit(program)

const summary = Exit.match(exit, {
  onSuccess: (value) => `produced ${value}`,
  // The failure side receives a Cause, not a bare error.
  onFailure: (cause) => `failed with ${cause}`
})
```

The difference from `Result` is the failure side: a `Result.Failure` holds a
typed `E`, while an `Exit.Failure` holds a `Cause<E>`. That's because running a
fiber can fail in ways the type channel doesn't capture — defects and
interruptions — and `Exit` keeps all of them.

### Capturing an Exit mid-program

`Effect.exit` works inside a `gen` block exactly like `Effect.result`, but
preserves defects and interruptions in the captured `Cause`.

```ts
import { Cause, Effect, Exit } from "effect"

declare const risky: Effect.Effect<number, "Timeout">

const program = Effect.gen(function* () {
  const exit = yield* Effect.exit(risky)
  if (Exit.isSuccess(exit)) {
    return exit.value
  }
  // We have the full Cause here — branch on its contents.
  if (Cause.hasInterrupts(exit.cause)) {
    yield* Effect.log("was interrupted; bailing out")
  }
  return 0
})
```

### Branching on the Cause

`Exit.match` hands you a `Cause` on the failure side. Use the `Exit.has*` guards
(which look *through* into the `Cause`) or the `Cause.has*` predicates to decide
how to react.

```ts
import { Cause, Effect, Exit } from "effect"

const exit = Effect.runSyncExit(Effect.die(new Error("kaboom")))

const report = Exit.match(exit, {
  onSuccess: (value) => `ok: ${value}`,
  onFailure: (cause) =>
    Cause.hasDies(cause)
      ? `defect:\n${Cause.pretty(cause)}`
      : `expected failure: ${cause}`
})

console.log(report)
// => defect:
//    Error: kaboom ...
```

## Cause — the full story

A `Cause<E>` is the runtime's complete record of why a fiber stopped. It is a
collection of *reasons* (`cause.reasons`), each of which is one of:

- **`Fail`** — a typed, expected error (the `E`), accessed via `reason.error`.
- **`Die`** — an untyped defect, accessed via `reason.defect`.
- **`Interrupt`** — a fiber interruption, carrying `reason.fiberId`.

```ts
import { Cause, Effect, Exit } from "effect"

const program = Effect.die(new Error("kaboom"))

const exit = Effect.runSyncExit(program)

if (Exit.isFailure(exit)) {
  const cause = exit.cause

  // Ask high-level questions about the cause...
  console.log(Cause.hasDies(cause)) // true
  console.log(Cause.hasFails(cause)) // false

  // ...or walk its reasons directly.
  for (const reason of cause.reasons) {
    if (Cause.isDieReason(reason)) {
      console.log("defect:", reason.defect)
    } else if (Cause.isFailReason(reason)) {
      console.log("error:", reason.error)
    }
  }

  // `Cause.pretty` renders a human-readable report for logs.
  console.log(Cause.pretty(cause))
}
```
**Note:** A single `Cause` can hold *several* reasons at once — for example two parallel
  fibers that both failed. This is why `Cause` is a collection rather than a
  single tagged value, and why helpers like `hasFails` / `hasDies` are phrased as
  "contains".

For the exhaustive `Cause` and `Exit` API — constructors, mapping combinators,
`prettyErrors`, and the `Reason` variants — see
[Exit & Cause](https://effect.plants.sh/data-types/exit-and-cause/).

## Bridge reference

Every API below converts between an `Effect` (or an already-captured value) and
an inspectable outcome. Each has its own `### ` heading, a short description, and
a runnable snippet.

### Effect.result

`Effect<A, E, R> -> Effect<Result<A, E>, never, R>`. Folds typed failures into a
`Result` in the success channel; the effect can no longer fail. Defects and
interruptions are *not* captured and still fail the effect.

```ts
import { Effect } from "effect"

const program = Effect.result(Effect.fail("Something went wrong"))

Effect.runPromise(program).then(console.log)
// => { _id: 'Result', _tag: 'Failure', failure: 'Something went wrong' }
```

### Effect.option

`Effect<A, E, R> -> Effect<Option<A>, never, R>`. Like `Effect.result`, but
discards the failure value: success becomes `Option.some`, a typed failure
becomes `Option.none`. Reach for it when *which* error happened does not matter.

```ts
import { Effect, Option } from "effect"

const ok = Effect.runSync(Effect.option(Effect.succeed(1)))
console.log(Option.isSome(ok)) // => true

const missing = Effect.runSync(Effect.option(Effect.fail("missing")))
console.log(Option.isNone(missing)) // => true
```

### Effect.exit

`Effect<A, E, R> -> Effect<Exit<A, E>, never, R>`. Captures the *full* outcome —
typed failures, defects, and interruptions — as an `Exit` whose failure side is a
`Cause<E>`. The resulting effect cannot fail.

```ts
import { Effect } from "effect"

const program = Effect.exit(Effect.fail("Something went wrong"))

Effect.runPromise(program).then(console.log)
// => { _id: 'Exit', _tag: 'Failure',
//      cause: { _id: 'Cause', failures: [{ _tag: 'Fail', error: 'Something went wrong' }] } }
```

### Effect.runSyncExit

`Effect<A, E> -> Exit<A, E>`. Runs an effect synchronously and returns its
outcome as an `Exit` instead of throwing on failure. The synchronous sibling of
`runPromiseExit`.

```ts
import { Effect } from "effect"

console.log(Effect.runSyncExit(Effect.succeed(1)))
// => { _id: 'Exit', _tag: 'Success', value: 1 }

console.log(Effect.runSyncExit(Effect.fail("boom")))
// => { _id: 'Exit', _tag: 'Failure',
//      cause: { _id: 'Cause', failures: [{ _tag: 'Fail', error: 'boom' }] } }
```

### Effect.runPromiseExit

`Effect<A, E> -> Promise<Exit<A, E>>`. Runs an effect and resolves with its
`Exit`. Unlike `runPromise`, the returned promise never rejects — failures live
in the resolved `Exit`.

```ts
import { Effect } from "effect"

Effect.runPromiseExit(Effect.fail("boom")).then(console.log)
// => { _id: 'Exit', _tag: 'Failure',
//      cause: { _id: 'Cause', failures: [{ _tag: 'Fail', error: 'boom' }] } }
```

### Effect.fromResult

`Result<A, E> -> Effect<A, E>`. The reverse direction: lift an already-captured
`Result` back into the error channel. A `Failure` becomes an `Effect` failure.

```ts
import { Effect, Result } from "effect"

const program = Effect.fromResult(Result.fail("nope"))

Effect.runPromiseExit(program).then(console.log)
// => { _id: 'Exit', _tag: 'Failure',
//      cause: { _id: 'Cause', failures: [{ _tag: 'Fail', error: 'nope' }] } }
```

### Yielding an Exit directly

An `Exit` *is* an `Effect`, so you can `yield*` it (or pass it where an effect is
expected) to re-raise its outcome into the error channel — the inverse of
`Effect.exit`.

```ts
import { Effect, Exit } from "effect"

const program = Effect.gen(function* () {
  const exit = Exit.fail("captured")
  // Re-raise: a Failure here fails the surrounding effect.
  const value = yield* exit
  return value
})

Effect.runPromiseExit(program).then(console.log)
// => { _id: 'Exit', _tag: 'Failure',
//      cause: { _id: 'Cause', failures: [{ _tag: 'Fail', error: 'captured' }] } }
```

### Converting between Result, Exit, and Option

The data-type accessors convert between these shapes without going through an
`Effect`. A few of the common ones:

```ts
import { Exit, Option, Result } from "effect"

// Exit -> Option (drop the Cause)
console.log(Exit.getSuccess(Exit.succeed(42)))
// => { _id: "Option", _tag: "Some", value: 42 }

// Exit -> first typed error, as Option
console.log(Exit.findErrorOption(Exit.fail("oops")))
// => { _id: "Option", _tag: "Some", value: "oops" }

// Result -> Option
console.log(Result.getSuccess(Result.succeed(1)))
// => { _id: "Option", _tag: "Some", value: 1 }

// Option -> Result
console.log(Result.fromOption(Option.none(), () => "missing"))
// => { _id: "Result", _tag: "Failure", failure: "missing" }
```

The full set — `Exit.filterValue`, `Exit.filterCause`, `Result.merge`, and the
rest — lives in [Exit & Cause](https://effect.plants.sh/data-types/exit-and-cause/) and
[Result](https://effect.plants.sh/data-types/result/).

## When to use which

- Use **`Result`** for synchronous success-or-error values, and to inspect an
  effect's typed outcome (via `Effect.result`) without failing the surrounding
  effect.
- Use **`Option`** (via `Effect.option`) when only success-vs-absence matters and
  the error value is uninteresting.
- Use **`Exit`** when you run an effect and need to know *exactly* how it ended,
  including defects and interruptions.
- Reach into **`Cause`** whenever you need to tell those failure kinds apart.

## Next steps

- See `Cause` in handlers via
  [`catchCause` and `matchCause`](https://effect.plants.sh/error-management/matching/).
- Recover from typed errors with combinators in
  [Catching errors](https://effect.plants.sh/error-management/catching-errors/).
- Browse the exhaustive APIs: [Result](https://effect.plants.sh/data-types/result/) and
  [Exit & Cause](https://effect.plants.sh/data-types/exit-and-cause/).