> ## Documentation Index
> Fetch the complete documentation index at: https://acme-c84a37e5.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Error Handling

> Error normalization to ResultError and customizable rules

## ResultError

The library normalizes unknown values to a `ResultError` with:

* `code`: stable identifier
* `message`: error description
* `status?`: optional numeric status
* `meta?`: additional payload
* `cause?`: original value

## Default normalizer

If no custom rules are provided, `tryo` automatically applies the following rules:

* **abort**: Detects `AbortError` and returns `code: "ABORTED"`.
* **timeout**: Detects `TimeoutError` and returns `code: "TIMEOUT"`.
* **httpStatus**: Detects errors with numeric `status` or `statusCode`. Returns `code: "HTTP"` and preserves the status.
* **aggregate**: Handles `AggregateError` by saving internal errors in `meta.errors`.
* **string**: If a string is thrown, it is used as the message.
* **message**: Extracts the `message` property from objects.

Example using default rules:

```typescript theme={null}
import tryo from "tryo";

const runner = tryo(); // Uses default rules

const result = await runner.run(async () => {
  throw new DOMException("Time out", "TimeoutError");
});

if (!result.ok && result.error.code === "TIMEOUT") {
  console.log("Request timed out");
}
```

## Custom rules

Use `errorRule` to define specific mappings and `tryo` to apply them.

```typescript theme={null}
import tryo, { errorRule } from "tryo";

class HttpError extends Error {
  constructor(
    public status: number,
    public url: string,
    public body?: unknown
  ) {
    super("HTTP error");
  }
}

const runner = tryo({
  rules: [
    errorRule.instance(HttpError).toError((e) => ({
      code: "HTTP",
      message: `Request failed (${e.status})`,
      status: e.status,
      meta: { url: e.url, body: e.body },
      cause: e,
    })),
  ],
});
```

## Transformation with `mapError`

Allows adjusting the already normalized error to enrich or standardize it.

```typescript theme={null}
const r = await run(() => fetch("/api"), {
  mapError: (e) => ({ ...e, message: `[api] ${e.message}` }),
});
```

## Cancellation and Timeout

* `signal` and `timeout` affect how long we wait for the task to complete.
* If your function does not consume the provided `AbortSignal`, the library cannot cancel underlying I/O automatically.
* We race the task and return `ABORTED`/`TIMEOUT` promptly, but the inner request only stops if it cooperates with `signal`.

```typescript theme={null}
const controller = new AbortController();
const r = await run(() => fetch("/api"), { signal: controller.signal, timeout: 2000 });
```

## Circuit Breaker (Runner-level)

* Circuit breaker is configured at the Runner level: `tryo({ circuitBreaker })`.
* Per-call circuit breaker is intentionally not exposed in `RunOptions` to keep the API lean.
