# Error Management

Every program can fail. What sets Effect apart is how much it tells you about
failure: the error type is part of an effect's signature, so the compiler knows
exactly which errors a computation can produce and forces you to deal with them.

An `Effect<A, E, R>` carries three type parameters: it succeeds with an `A`,
fails with an `E`, and needs requirements `R`. The middle slot — the **error
channel** — is the heart of error management.

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

// HttpError is a tagged error — defined with Schema.TaggedErrorClass below.
declare class HttpError {
  readonly _tag: "HttpError"
}

//      ┌─── succeeds with a number
//      │       ┌─── can fail with HttpError
//      ▼       ▼
declare const program: Effect.Effect<number, HttpError>
```

Effect distinguishes two fundamentally different kinds of failure:

- **Failures** (expected errors) are values you anticipate — a missing record,
  a rejected payment, a malformed input. They are tracked in the `E` channel,
  show up in the type, and are meant to be handled. They behave like checked
  exceptions, but as ordinary typed values.

- **Defects** (unexpected errors) are bugs and broken invariants — a thrown
  exception, a failed assertion, dividing by zero. They are *not* tracked in the
  type, because you are not supposed to handle them at every call site. The
  runtime still captures them, so nothing is lost.

Both live inside a [`Cause`](https://effect.plants.sh/error-management/result-and-exit/), the runtime's
complete record of why a fiber stopped — which may include multiple failures,
defects, and interruptions at once.

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

class HttpError extends Schema.TaggedErrorClass<HttpError>()("HttpError", {
  status: Schema.Number
}) {}

// Failure: an expected error, tracked in the type as HttpError
const expected: Effect.Effect<never, HttpError> = Effect.fail(
  new HttpError({ status: 503 })
)

// Defect: an unexpected error, NOT tracked in the type (E stays `never`)
const unexpected: Effect.Effect<never> = Effect.die(
  new Error("invariant broken")
)
```

The rest of this section walks through the full toolkit, from defining errors to
recovering from them, retrying, and inspecting raw outcomes.
**Expected vs unexpected**
Understand [failures and defects](https://effect.plants.sh/error-management/expected-errors/) and
    when each applies.

**Tagged errors**
Define typed errors with
    [`Schema.TaggedErrorClass`](https://effect.plants.sh/error-management/tagged-errors/).

**Catching errors**
Recover with
    [`catch`, `catchTag`, `catchTags`, `catchCause`](https://effect.plants.sh/error-management/catching-errors/).

**Reason errors**
Model a closed set of causes inside one error with
    [`catchReason`](https://effect.plants.sh/error-management/reason-errors/).

**Fallback & retry**
Build resilience with
    [retries, timeouts, and fallbacks](https://effect.plants.sh/error-management/fallback-and-retry/).

**Matching**
Fold both channels at once with
    [`match` and `matchCause`](https://effect.plants.sh/error-management/matching/).

**Result & Exit**
Inspect outcomes as values with
    [`Result` and `Exit`](https://effect.plants.sh/error-management/result-and-exit/).
**Tip:** Effect never uses JavaScript's `throw` for control flow. Errors are values
  that flow through the error channel, so they compose like any other data.