# @dotcom-reliability-kit/fetch-error-handler

> Properly handle fetch errors and avoid a lot of boilerplate in your app.

Latest version **2.0.2** (published 2026-08-19) · MIT license · 0 weekly downloads

## Install

```sh
npm install @dotcom-reliability-kit/fetch-error-handler
pnpm add @dotcom-reliability-kit/fetch-error-handler
yarn add @dotcom-reliability-kit/fetch-error-handler
bun add @dotcom-reliability-kit/fetch-error-handler
```

## Health

**Score 70/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; recently updated; high maintenance score; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 2.0.2 |
| Published | 2026-08-19 |
| First published | 2023-08-18 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Node | ^22.12 \|\| ^24 \|\| ^26 |
| Dependencies | 1 |
| Unpacked size | 40.6 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Maintainers | hamza.samih, rowanmanning, the-ft, robertboulton, leila.micollier |

## Links

- npm: https://www.npmjs.com/package/@dotcom-reliability-kit/fetch-error-handler
- Repository: https://github.com/Financial-Times/dotcom-reliability-kit
- Homepage: https://github.com/Financial-Times/dotcom-reliability-kit/tree/main/packages/fetch-error-handler#readme
- Issues: https://github.com/Financial-Times/dotcom-reliability-kit/issues?q=label:"package: fetch-error-handler"
- npm.io page: https://npm.io/package/@dotcom-reliability-kit/fetch-error-handler

## Dependencies (1)

- [@dotcom-reliability-kit/errors](https://npm.io/package/@dotcom-reliability-kit/errors.md) ^5.1.0

## Recent versions

- 2.0.2 (latest) — 2026-08-19
- 2.0.0-beta.1 (prerelease) — 2026-06-03
- 2.0.1 — 2026-07-14
- 2.0.0 — 2026-06-23
- 1.3.0 — 2025-12-04
- 1.2.0 — 2025-11-05
- 1.1.1 — 2025-10-13
- 1.1.0 — 2025-05-08
- 1.0.0 — 2025-01-30
- 0.3.0 — 2025-01-21
- 0.2.6 — 2024-11-26
- 0.2.5 — 2024-07-01
- 0.2.4 — 2024-06-26
- 0.2.3 — 2024-05-01
- 0.2.2 — 2024-04-29
- … 5 more at https://npm.io/package/@dotcom-reliability-kit/fetch-error-handler/versions

## README

# @dotcom-reliability-kit/fetch-error-handler

Properly handle fetch errors and avoid a lot of boilerplate in your app. This module is part of [FT.com Reliability Kit](https://github.com/Financial-Times/dotcom-reliability-kit#readme).

* [Usage](#usage)
  * [Wrap the fetch function](#wrap-the-fetch-function)
  * [Handle errors with `.then`](#handle-errors-with-then)
  * [Handle the response object](#handle-the-response-object)
  * [Errors thrown](#errors-thrown)
    * [Client errors](#client-errors)
    * [Server errors](#server-errors)
    * [DNS errors](#dns-errors)
    * [Abort and timeout errors](#abort-and-timeout-errors)
    * [Socket errors](#socket-errors)
    * [Invalid JSON errors](#invalid-json-errors)
    * [Invalid body errors](#invalid-body-errors)
    * [Unknown errors](#unknown-errors)
  * [Creating your own handler](#creating-your-own-handler)
  * [`createFetchErrorHandler` configuration options](#createfetcherrorhandler-configuration-options)
    * [`options.upstreamSystemCode`](#optionsupstreamsystemcode)
* [Migrating](#migrating)
* [Contributing](#contributing)
* [License](#license)


## Usage

Install `@dotcom-reliability-kit/fetch-error-handler` as a dependency:

```bash
npm install --save @dotcom-reliability-kit/fetch-error-handler
```

Include in your code:

```js
import { handleFetchErrors } from '@dotcom-reliability-kit/fetch-error-handler';
```

> [!TIP]
> If you're using this package with TypeScript, we recommend using the following settings in your `tsconfig.json` file to avoid type errors:
>
> ```json
> {
>     "esModuleInterop": true,
>     "module": "nodenext",
>     "moduleResolution": "nodenext"
> }
> ```

You can use this function with any `fetch` call to throw appropriate errors based on the [HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) that you get back.

There are several ways to use it, as long as it is `await`ed and is called with either a `Response` object or a `Promise` that resolves to a `Response`.

Some of the options below result in more errors being caught, you can weigh this up when implementing in your own code.

In all of the APIs below, if the response `ok` property is `false`, i.e. when the status code is `400` or greater, then errors will be thrown.

> [!WARNING]
> If you're using node-fetch then it's important to read the body of the request because of a [known memory leak](https://github.com/node-fetch/node-fetch/issues/83). If an error is thrown then we automatically drain the response body stream but, if the request is successful, you'll need to do this yourself.

### Wrap the fetch function

This is the recommended API as this will allow you to handle the most errors (even DNS and timeout errors) correctly:

```js
const response = await handleFetchErrors(
    fetch('https://httpbin.org/status/500')
);
```

You **must not** `await` the `fetch` call itself if you want to handle DNS and timeout errors. This is safe to do and will not result in unhandled promise rejections – `handleFetchErrors` takes care of them all.

### Handle errors with `.then`

This API allows you to handle most errors based on the HTTP response, but it will not allow you to handle errors which occur _before_  a valid response is returned, e.g. DNS or timeout errors.

```js
const response = await fetch('https://httpbin.org/status/500').then(handleFetchErrors);
```

### Handle the response object

This API is for when you already have an HTTP response object, but it will not allow you to handle errors which occur _before_  a valid response is returned, e.g. DNS or timeout errors.

```js
const response = await fetch('https://httpbin.org/status/500');
await handleFetchErrors(response);
```

### Errors thrown

We throw different errors depending on the status code we get back from the `fetch` call.

#### Client errors

If the URL you fetched responds with a status code in the range of `400–499` then this normally indicates that  something is wrong with the _current_ system. Maybe we're sending data in an invalid format or our API key is invalid. For this we throw a generic `500` error to indicate an issue with _our_ system. It'll be an [`HTTPError`](https://github.com/Financial-Times/dotcom-reliability-kit/tree/main/packages/errors#httperror). This error will have the following properties to help you debug:

```js
error.statusCode // 500
error.code // FETCH_CLIENT_ERROR
error.data.upstreamUrl // The URL that was fetched
error.data.upstreamStatusCode // The status code that the URL responded with
error.data.responseBody // The body of the initial response
```

#### Server errors

If the URL you fetched responds with a status code in the range of `500–599` then this indicates something is wrong with the _upstream_ system. For this we can output an [`UpstreamServiceError`](https://github.com/Financial-Times/dotcom-reliability-kit/tree/main/packages/errors#httperror) and attribute it to the system we're fetching from. This error will have the following properties to help you debug:

```js
error.statusCode // 502
error.code // FETCH_SERVER_ERROR
error.data.upstreamUrl // The URL that was fetched
error.data.upstreamStatusCode // The status code that the URL responded with
error.data.responseBody // The body of the initial response
```

#### DNS errors

If the hostname of the URL you fetched cannot be resolved, a DNS error will be thrown, it'll be an [`OperationalError`](https://github.com/Financial-Times/dotcom-reliability-kit/tree/main/packages/errors#operationalerror). This error will have the following properties to help you debug:

```js
error.code // FETCH_DNS_LOOKUP_ERROR
error.cause // The underlying DNS error that was caught
```

> [!IMPORTANT]<br />
> This type of error will only be thrown if you use the ["wrap the fetch function"](#wrap-the-fetch-function) API.

#### Abort and timeout errors

If the request times out or is aborted via [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal), _or_ the non-standard `timeout` option in [node-fetch](https://github.com/node-fetch/node-fetch) is used, then we throw an [`OperationalError`](https://github.com/Financial-Times/dotcom-reliability-kit/tree/main/packages/errors#operationalerror). This error will have the following properties to help you debug:

```js
error.code // FETCH_ABORT_ERROR or FETCH_TIMEOUT_ERROR
error.cause // The underlying abort or timeout error that was caught
```

> [!IMPORTANT]<br />
> This type of error will only be thrown if you use the ["wrap the fetch function"](#wrap-the-fetch-function) API.

#### Socket errors

If the connection is closed early by the server then we throw an [`UpstreamServiceError`](https://github.com/Financial-Times/dotcom-reliability-kit/tree/main/packages/errors#upstreamserviceerror). This error will have the following properties to help you debug:

```js
error.code // FETCH_SOCKET_HANGUP_ERROR
error.cause // The underlying socket error that was caught
```

> [!IMPORTANT]<br />
> This type of error will only be thrown if you use the ["wrap the fetch function"](#wrap-the-fetch-function) API.

#### Invalid JSON errors

If the URL you fetched responds with 200 status code and a JSON body, we try to parse that body to verify it is valid. If the body is invalid, we will throw an [`UpstreamServiceError`](https://github.com/Financial-Times/dotcom-reliability-kit/tree/main/packages/errors#httperror) with the error from the parsing, and the initial body of the response. This error will have the following properties to help you debug:

```js
error.statusCode // 502
error.code // FETCH_INVALID_JSON_ERROR
error.data.upstreamUrl // The URL that was fetched
error.data.upstreamStatusCode // 200
error.data.upstreamErrorMessage // The error that was thrown when attempting to parse the body of the response
error.data.responseBody // The body of the initial response
```

> [!IMPORTANT]<br />
> If the body is too long, we are truncating it because Splunk has a limit of characters to log.

#### Invalid body errors

When decrypting the body of the reponse, it is possible that the .text() method throw an [exception](https://developer.mozilla.org/en-US/docs/Web/API/Response/text#exceptions). In that case, we will throw an [`OperationalError`](https://github.com/Financial-Times/dotcom-reliability-kit/tree/main/packages/errors#operationalerror). This error will have the following properties to help you debug:

```js
error.statusCode // 502
error.code // FETCH_BODY_ABORT_ERROR or FETCH_BODY_TYPE_ERROR depending on the cause
error.message // A more human readable explaination of the exception
error.cause // The cause of the error parsing the body
```

#### Unknown errors

If the URL you fetched responds with an `ok` property of `false` and a status code outside of the `400–599` range, then it's unclear what's happened but we reject with an error anyway to make sure we're able to debug. We output an [`HTTPError`](https://github.com/Financial-Times/dotcom-reliability-kit/tree/main/packages/errors#httperror):

```js
error.statusCode // 500
error.code // FETCH_UNKNOWN_ERROR
error.data.upstreamUrl // The URL that was fetched
error.data.upstreamStatusCode // The status code that the URL responded with
```

### Creating your own handler

You can customise the thrown errors by creating your own fetch handler and passing in [options](#createfetcherrorhandler-configuration-options).

Include in your code:

```js
import { createFetchErrorHandler } from '@dotcom-reliability-kit/fetch-error-handler';
```

Create and use your own handler (the handler supports all the same usage methods as [outlined here](#usage)):

```js
const handleFetchErrors = createFetchErrorHandler({
    upstreamSystemCode: 'httpbin'
});
const response = await handleFetchErrors(fetch('https://httpbin.org/status/500'));
```

### `createFetchErrorHandler` configuration options

Config options can be passed into the `createFetchErrorHandler` function to change the behaviour of the handler.

#### `options.upstreamSystemCode`

Attribute any fetch errors to a given [Biz Ops system](https://biz-ops.in.ft.com/list/Systems). This allows you to easily spot in your logs when an upstream system is the cause of an error. This must be a `String` and a valid [system code](https://tech.in.ft.com/tech-topics/operability/biz-ops/unique-identifiers).

```js
const handleFetchErrors = createFetchErrorHandler({
    upstreamSystemCode: 'next-navigation-api'
});
```

When this is set, any errors thrown by `handleFetchErrors` will have a [`relatesToSystems` property](https://github.com/Financial-Times/dotcom-reliability-kit/tree/main/packages/errors#operationalerrorrelatestosystems) which includes the given system code.


## Migrating

Consult the [Migration Guide](./docs/migration.md) if you're trying to migrate to a later major version of this package.


## Contributing

See the [central contributing guide for Reliability Kit](https://github.com/Financial-Times/dotcom-reliability-kit/blob/main/docs/contributing.md).


## License

Licensed under the [MIT](https://github.com/Financial-Times/dotcom-reliability-kit/blob/main/LICENSE) license.<br/>
Copyright &copy; 2023, The Financial Times Ltd.

---
_Source: https://npm.io/package/@dotcom-reliability-kit/fetch-error-handler · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
