Skip to Content
✨ New: Auth Plugin. JWT, OAuth2, API Key, and more authentication strategies out of the box. Read more... 🎉
Error Handling

Error Handling

Error Object Shape

When a request returns a non-2xx status, endpoint-fetcher throws:

{ status: number; // HTTP status code (404, 500, …) statusText: string; // HTTP status text ("Not Found", …) error: TError; // Parsed response body, typed by your TError generic }

Typing Errors with TError

Pass your expected error shape as the third generic parameter to any endpoint helper:

type ApiError = { message: string; code: string }; const api = createApiClient({ createUser: post<CreateUserInput, User, ApiError>('/users'), }, { baseUrl: 'https://api.example.com' }); try { await api.createUser({ name: 'Jane', email: 'bad-email' }); } catch (err: unknown) { const error = err as { status: number; statusText: string; error: ApiError }; console.log(error.status); // 400 console.log(error.error.code); // 'VALIDATION_ERROR' console.log(error.error.message); // 'Invalid email' }

TypeScript doesn’t enforce types in catch blocks — you must use as to get typed access.

Status-Based Handling

try { await api.createUser(data); } catch (err: unknown) { const error = err as { status: number; error: ApiError }; if (error.status === 400) { console.error('Validation error:', error.error.message); } else if (error.status === 401) { window.location.href = '/login'; } else if (error.status >= 500) { console.error('Server error — try again later'); } else { throw err; } }

Global Error Handling

Use the onError hook to handle or log all errors in one place:

const api = createApiClient(endpoints, { baseUrl: 'https://api.example.com', hooks: { onError: async (error) => { // Sentry.captureException(error); console.error('API error:', error); }, }, });

Type Guard

A type guard avoids repeated assertions in catch blocks:

type ApiError = { message: string; code: string }; function isApiError(err: unknown): err is { status: number; statusText: string; error: ApiError } { return typeof err === 'object' && err !== null && 'status' in err && 'error' in err; } try { await api.users.getById({ id: '123' }); } catch (err) { if (isApiError(err)) { console.error(`${err.status}: ${err.error.message}`); } else { throw err; // network error or unexpected } }

Different Error Types Per Endpoint

Each endpoint can have its own TError:

type ValidationError = { message: string; errors: Array<{ field: string; message: string }> }; type NotFoundError = { message: string; resourceId: string }; type AuthError = { message: string; code: 'UNAUTHORIZED' | 'FORBIDDEN' }; const api = createApiClient({ createUser: post<CreateUserInput, User, ValidationError>('/users'), getUser: get<{ id: string }, User, NotFoundError>((input) => `/users/${input.id}`), login: post<LoginInput, AuthTokens, AuthError>('/auth/login'), }, { baseUrl: 'https://api.example.com' });