Skip to content
Axios

Axios

Officialv5.5.11

@kubb/plugin-axios

kubb add plugin-axios

Handle errors

Handle failures from the client Kubb generates. Catch a ResponseError, switch to a returned error result with throwOnError, and tell a network failure apart from a 4xx or 5xx response.

The generated client throws a ResponseError on non-2xx responses by default:

import { getPetById } from './gen/clients/getPetById'
import { ResponseError } from './gen/.kubb/client'

try {
  const { data } = await getPetById({ path: { petId: 1 } })
  console.info(data.name)
} catch (error) {
  if (ResponseError.is(error)) {
    console.error(error.status) // 404
    console.error(error.data) // the parsed error body
  }
}

The message holds the HTTP method and the URL without its query string, so query credentials stay out of logs. For example: GET https://api.example.com/pets/1 failed with status 404 Not Found.

The error exposes these fields:

class ResponseError extends Error {
  static is(error: unknown): error is ResponseError<unknown, unknown, unknown>
  data: TError // the parsed error body
  status: number
  statusText: string
  contentType: string | undefined
  request: AxiosRequestConfig
  response: AxiosResponse
}

Each generated package bundles its own ResponseError class, so narrow with ResponseError.is(error) instead of instanceof. is() checks the error name.

Return the error instead

Pass throwOnError: false and the call resolves for every documented status. The result is a discriminated union: data is set on success and error on failure. Branch on status, because an empty error body can leave error empty or undefined.

const result = await getPetById({ path: { petId: 1 }, throwOnError: false })

if (result.status === 200) {
  console.info(result.data.name)
}
if (result.status !== 200) {
  console.error(result.status, result.error)
}

Set the generated default

Set throwOnErrorDefault on the client plugin to choose how generated operations handle non-2xx responses by default. Each call can still override that setting with throwOnError:

import { pluginAxios } from '@kubb/plugin-axios'

pluginAxios({ throwOnErrorDefault: false })

// resolves with an error result
const list = await searchPets({ query: { status: 'available' } })

// opt one call back into throwing
const pet = await getPetById({ path: { petId: 1 }, throwOnError: true })

client.setConfig({ throwOnError }) does not change this default, because each generated operation passes its own value. Set it on the plugin.

Network failures still throw

throwOnError only applies when the server answers. A dropped connection, a DNS failure, or an aborted AbortSignal always rejects. A ResponseError means the server answered with a non-2xx status, and a ParseError means a body failed validation. Any other error usually means the request never completed.
try {
  const { data } = await getPetById({ path: { petId: 1 }, throwOnError: false })
  use(data)
} catch (error) {
  // not a ResponseError: the request never completed
  console.error('request failed to send', error)
}

Pass an AbortSignal to cancel a request. The call rejects with the abort reason.

Validation failures

When you turn on the validator option, a body that does not match its Zod schema throws a ParseError instead of returning. It carries the schema's raw issues:

import { ParseError } from './gen/.kubb/standardSchema'

try {
  const { data } = await getPetById({ path: { petId: 1 } })
  use(data)
} catch (error) {
  if (error instanceof ParseError) {
    console.error(error.issues) // [{ message, path }]
  }
}

A ParseError reports schema validation issues. A ResponseError reports a non-2xx status. With throwOnError: false, the error body is checked against its own error schema.

Calling .unwrap() on a throwOnError: false call turns that same error into a rejection, so a try/catch works there too.

See also