> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://docs.ampdb.io/api/mcp` to find what you need.

# Errors

The SDK's methods tell you how they can fail in their types: an `Effect<A, E>` or a `Stream<A, E>` fails with one of
the errors in `E`. This page lists the errors of queries and streams. [Error Codes](/sdks/typescript/error-codes) lists
those of the Admin API, the Registry API, and the authentication service, which have codes.

## Handle errors

Every error has a `_tag` property, its name. In Effect code, `Effect.catchTag` handles one, by its `_tag`, and
`Effect.catchTags` several:

```ts
const batches =
  yield* flight.query(sql).pipe(
    Effect.catchTags({
      // Log the server's message, and go on with no results
      RpcError: (error) => Effect.as(Effect.logError(`Query failed: ${error.cause}`), []),
      // Treat a row that doesn't match the schema as a bug
      ParseRecordBatchError: (error) => Effect.die(error),
    }),
  )
```

[Effect Basics](/sdks/typescript/effect#errors) explains these. In `async` code, a failed Effect's promise rejects with
the error itself: check its `_tag`. Query and stream errors are `Error`s, named like `Amp/RpcError`, so they have a
stack trace. The errors with codes are plain objects, `{ _tag, code, message }`.

## Defects

Some failures aren't in `E`: the SDK treats them as bugs, or as problems your program can't fix, and makes the program
fail with a defect. `Effect.catchDefect` handles them, and in `async` code the promise rejects with them. The SDK fails
with a defect when:

* **A stream gets a keep-alive message**, 30 seconds into the stream:
  `RangeError: Offset is outside the bounds of the DataView`. See
  [Keep a stream running](/sdks/typescript/streaming#keep-a-stream-running).
* **An Admin API request fails without one of its errors**: the Admin API can't be reached, or answers with a status the
  endpoint doesn't declare, like a hosted Amp's 401 when your token is missing. The defect is an `HttpClientError`,
  whose `reason` has the request, and the response's status.
* **The Admin API's response doesn't match its schema**, which can happen when the SDK and Amp are different versions:
  a `SchemaError`.
* **The query server sends a message the SDK can't read.**

## Arrow Flight errors

`ArrowFlight`'s methods fail with `ArrowFlightError`, one of these. Import them from `@edgeandnode/amp`'s `ArrowFlight`
namespace.

### `RpcError`

A request to the query server failed. Its properties:

* `method`: the request, `"getFlightInfo"` to plan the query, or `"doGet"` to fetch its results. A query can pass
  `"getFlightInfo"` and still fail in `"doGet"`, like one that [can't
  stream](/querying/streaming-queries#what-streaming-queries-support).
* `cause`: a Connect `ConnectError`, with the server's `rawMessage`, and a gRPC `code`.

Its own `message` is empty: print `String(error.cause)`, or read `error.cause.rawMessage`. The `code` says what went
wrong:

| Code | Name                | Causes                                                                                                                                                                                                                                |
| ---- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 3    | `invalid_argument`  | The SQL is wrong: `SQL parse error`, a table that doesn't exist (`table 'amp.acme/missing.blocks' not found`), a column that doesn't (`No field named nope`), or a stream Amp can't run (`query is not supported in streaming mode`). |
| 4    | `deadline_exceeded` | The request took longer than the transport's `defaultTimeoutMs`: `the operation timed out`.                                                                                                                                           |
| 13   | `internal`          | Amp failed to run the query, or the query has [one of these mistakes](/querying/arrow-flight#mistakes-that-return-internal).                                                                                                          |
| 14   | `unavailable`       | The query server can't be reached, like `connect ECONNREFUSED 127.0.0.1:1602`. Check its URL, and that Amp is running.                                                                                                                |
| 16   | `unauthenticated`   | A hosted Amp got no token (`Jwt is missing`), or one it rejects. See [Authentication](/sdks/typescript/authentication).                                                                                                               |

### `ParseRecordBatchError`

A batch of results couldn't be decoded. Usually, a row didn't match the query's `schema`: its `cause` is the schema's
error, like `Expected number at [0]["block_num"]`. Fix the schema, or the options that decode the values (see
[Give rows a type](/sdks/typescript/querying#give-rows-a-type)).

### `ParseSchemaError`

The results' Arrow schema couldn't be read. The SDK can't read every Arrow type: `Utf8View`, which
`CAST(… AS VARCHAR)` produces, fails with an `InvalidArrowDataTypeError` as its `cause`, with `type: 24`. Cast to
`arrow_cast(…, 'Utf8')` instead.

### `NoEndpointsError`, `MultipleEndpointsError`, and `TicketNotFoundError`

The query server planned the query, but its answer didn't say where to fetch the results from: no endpoint, more than
one, or an endpoint without a ticket. Each has the `query`. They mean the server isn't behaving as Amp's query server
does: check that the URL points to one.

### `ParseDictionaryBatchError`

A dictionary batch couldn't be read. The SDK doesn't read dictionary batches yet, so it never fails with this.

## Protocol stream errors

`ProtocolStream.stream` fails with `ProtocolStreamError`, one of these. Import them from `@edgeandnode/amp`'s
`ProtocolStream` namespace.

### `ProtocolArrowFlightError`

The query failed. Its `cause` is the [Arrow Flight error](/sdks/typescript/errors#arrow-flight-errors).

### `ProtocolValidationError`

A message's block ranges broke one of Amp's guarantees (see [Validation](/sdks/typescript/streaming#validation)). Its
`cause` is the `ValidationError`, and its `message` says which, like
`Protocol validation failed: Gap in block numbers for network mainnet: missing blocks 5 to 9`. Resume the stream from
its last watermark.

The `ValidationError`s:

| Error                                  | Properties                                  | What happened                                                                                        |
| -------------------------------------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `DuplicateNetworkError`                | `network`                                   | A message had two ranges for the same chain.                                                         |
| `NetworkCountChangedError`             | `expected`, `actual`                        | A message had more or fewer chains than the previous one.                                            |
| `UnexpectedNetworkError`               | `network`                                   | A message had a chain the previous ones didn't.                                                      |
| `MissingPrevHashError`                 | `network`, `block`                          | A range that doesn't start at block 0 had no parent hash.                                            |
| `InvalidPrevHashError`                 | `network`                                   | A range that starts at block 0 had a parent hash that isn't all zeros.                               |
| `HashMismatchOnConsecutiveBlocksError` | `network`, `expectedHash`, `actualPrevHash` | A range followed the previous one, but its parent hash isn't the previous range's last block's hash. |
| `InvalidReorgError`                    | `network`                                   | A range went back, as in a reorg, but with the same hash as before.                                  |
| `GapError`                             | `network`, `missingStart`, `missingEnd`     | A range skipped blocks, from `missingStart` to `missingEnd`.                                         |

## Transactional stream errors

`TransactionalStream`'s methods fail with `TransactionalStreamError`: a [protocol stream
error](/sdks/typescript/errors#protocol-stream-errors), or one of these. Import them from `@edgeandnode/amp`'s `TransactionalStream` namespace.

### `StateStoreError`

The state store failed. Its properties:

* `operation`: what failed, `"advance"`, `"commit"`, `"truncate"`, or `"load"`.
* `reason`: why, in words.
* `cause`: the underlying error, if any.

Your own state store fails with it, as in [Save the state](/sdks/typescript/transactional-streams#save-the-state).

### `UnrecoverableReorgError`

A reorg went back further than the watermarks the stream kept, so it can't tell which transactions to undo. Its
`reason` says so. Start over, with an empty state and destination, and raise the stream's `retention`.

### `PartialReorgError`

A reorg started in the middle of a watermark's block range, on the chain in `network`, so only part of that range's
transactions would need undoing. Start over, with an empty state and destination.

## CDC stream errors

`CdcStream`'s methods fail with `CdcStreamError`: a [transactional stream error](/sdks/typescript/errors#transactional-stream-errors), or a
`BatchStoreError`. Import it from `@edgeandnode/amp`'s `CdcStream` namespace.

### `BatchStoreError`

The batch store failed. Like `StateStoreError`, it has `operation` (`"append"`, `"seek"`, `"load"`, or `"prune"`),
`reason`, and `cause`. A failure to prune doesn't stop the stream: it's logged, and retried at the next watermark.
