# HTTPError

Custom error class for HTTP responses with typed data, status code, and headers. Includes the isHTTPError type guard.

## Import

```ts
import { HTTPError, isHTTPError } from "@noverax/courier"
```

## HTTPError Class

```ts
import { CourierError, type HttpResponse } from "@noverax/courier"

declare class HTTPError<TData = unknown> extends CourierError<"HTTP_ERROR"> {
  readonly status: number
  readonly headers: Headers
  readonly data: TData

  constructor(response: HttpResponse<TData>, options?: { cause?: unknown; message?: string })
}
```

## Properties

```ts
error.name       // "HTTPError"
error.code       // "HTTP_ERROR"
error.message    // "HTTP {status}" (e.g., "HTTP 404")
error.status     // HTTP status code (e.g., 404)
error.headers    // Response headers (Headers object)
error.data       // Parsed response body (typed as R)
```

- `status` — the HTTP status code. `0` for network errors (DNS failure, connection refused).
- `headers` — the response `Headers` object. Empty `Headers` for network errors.
- `data` — the parsed response body. Typed as `TData` (defaults to `unknown`).
- `name` — always `"HTTPError"`; `code` — always `"HTTP_ERROR"`.
- `message` — `"HTTP {status}"` (e.g., `"HTTP 404"`), or, when there was no answer, `"Network request failed"` or `"Request timed out"`.

## isHTTPError

Type guard function to check if an error is an HTTPError:

```ts
import type { HTTPError } from "@noverax/courier"

declare function isHTTPError<TData = unknown>(error: unknown): error is HTTPError<TData>
```

> **isHTTPError types the error's data**
>
> `isHTTPError(error)` checks what `error instanceof HTTPError` checks, and takes a type parameter for the error's `data`: `isHTTPError<ErrorResponse>(error)` — see [Typed Error Data](#typed-error-data).

## Basic Usage

```ts
import { isHTTPError } from "@noverax/courier"

try {
  const user = await caller.users.getById({ id: "999" })
} catch (error) {
  if (isHTTPError(error)) {
    console.error(`HTTP ${error.status}:`, error.data)
  }
}
```

## Typed Error Data

Pass a type parameter to `isHTTPError` to type the error's `data`:

```ts
import { isHTTPError } from "@noverax/courier"

type ErrorResponse = {
  success: false
  message: string
  code?: string
}

try {
  await caller.users.getById({ id: "999" })
} catch (error) {
  if (isHTTPError<ErrorResponse>(error)) {
    console.error(error.data.message)  // "User not found"
    console.error(error.data.code)     // "USER_NOT_FOUND"
  }
}
```

## Status Code Handling

```ts
import { isHTTPError } from "@noverax/courier"

try {
  await caller.users.getAll()
} catch (error) {
  if (isHTTPError(error)) {
    switch (error.status) {
      case 400: console.error("Bad request:", error.data); break
      case 401: redirectToLogin(); break
      case 403: showForbiddenMessage(); break
      case 404: showNotFound(); break
      case 429: console.warn("Rate limited, retry later"); break
      default:
        if (error.status >= 500) console.error("Server error:", error.data)
    }
  }
}
```

## Middleware-Based Error Handling

Use middleware to handle errors globally across all requests:

```ts
import { defineMiddleware } from "@noverax/courier/middleware"
import { isHTTPError } from "@noverax/courier"

const errorMiddleware = defineMiddleware("errors", "wrap", async (ctx, next) => {
  try {
    return await next()
  } catch (error) {
    if (isHTTPError(error) && error.status === 401) {
      // redirect to login, refresh token, etc.
    }
    throw error
  }
})
```

## Network Errors

Network-level errors (DNS failures, connection refused, timeouts) are converted to `HTTPError` with `status: 0`. A timeout says so: its message is `"Request timed out"` and `error.data.code` is `"TIMEOUT"`. Through the proxy, a timeout on the server's side arrives as a `504` with `code: "UPSTREAM_TIMEOUT"`:

```ts
import { isHTTPError } from "@noverax/courier"

try {
  await caller.users.getAll()
} catch (error) {
  if (isHTTPError(error) && error.status === 0) {
    console.error("Network error:", error.data)
  }
}
```

## Related

- [Error Handling Guide](/docs/core-concepts/error-handling) — in-depth error handling patterns
- [Middleware](/docs/middleware/overview) — middleware chain for error interception
- [HttpClient](/docs/api/instance) — where HTTPError is thrown
- [Types](/docs/api/types) — HttpResponse and related types
