Handle SDK errors
Map typed API errors into native route, authentication, validation, and retry boundaries.
A
JEvery non-2xx Board API response throws BoardApiError. Catch an error only where your application can choose a specific response. Route loaders own 404s, authentication boundaries own sign-in/refresh, forms own validation feedback, and the global error boundary owns unexpected failures.
Inspect an API error
| Property | Meaning |
|---|---|
status | HTTP response status |
code | Stable machine-readable code, such as jobs_not_found |
message | Human-readable server message |
details | Optional structured, code-specific details |
requestId | Optional request identifier for logs and support |
raw | Parsed response body without discarded fields |
The error-code type remains open because Cavuno can add codes within v1. Always keep an unknown fallback.
Map errors at the boundary that owns the response
| Error | Preferred owner | Typical response |
|---|---|---|
| Not found | Framework route boundary | Native 404 UI and status |
| Unauthorized | Session boundary | One explicit refresh, then sign in |
| Forbidden | Feature/access boundary | Explain missing access or offer upgrade |
| Validation | Form/action boundary | Field or form feedback from details |
| Conflict | Mutation flow | Reload current state and explain the conflict |
| Rate limited | Request policy | Bounded backoff for safe reads; no blind mutation retry |
| Other API/transport failure | Error boundary and observability | Log context, preserve request ID, rethrow |
Do not write one generic loader that converts every category into null or a new anonymous Error; that destroys the framework response and the original Cavuno context.
Use the framework’s native 404
Next.js App Router:
1234567891011import { isNotFound } from '@cavuno/board';import { notFound } from 'next/navigation';export async function loadJob(slug: string) {try {return await board.jobs.retrieve(slug);} catch (error) {if (isNotFound(error)) notFound();throw error;}}
React Router Framework Mode:
12345678910import { isNotFound } from '@cavuno/board';try {return await board.jobs.retrieve(params.jobSlug);} catch (error) {if (isNotFound(error)) {throw new Response('Job not found', { status: 404 });}throw error;}
The generic SDK guard stays the same; the framework decides how a 404 is represented.
Preserve validation details in actions
1234567891011import { isValidationError } from '@cavuno/board';try {return await board.jobs.apply(jobSlug, input);} catch (error) {if (isValidationError(error)) {return { ok: false as const, fields: error.details };}throw error;}
Do not match human-readable messages. Use the stable guard and let the form decide how known details map to fields.
Distinguish board access from candidate login
123456789101112131415161718import {isBoardPasswordRequired,isUnauthorized,} from '@cavuno/board';try {return await board.jobs.list({ limit: 20 });} catch (error) {if (isBoardPasswordRequired(error)) {return { requiresBoardPassword: true };}if (isUnauthorized(error)) {return { requiresUserSession: true };}throw error;}
A board-password grant is board-wide access, not a candidate login. On a nostore client, persist the grant in your application’s board-access cookie and pass it per call.
Log API context without leaking credentials
123456789101112131415import { isBoardApiError } from '@cavuno/board';try {return await operation();} catch (error) {if (isBoardApiError(error)) {console.error('Cavuno API request failed', {status: error.status,code: error.code,requestId: error.requestId,});}throw error;}
Keep the original error when adding application context. Never log authorization headers, access tokens, refresh tokens, passwords, or uploaded résumé contents.
Handle transport and retry uncertainty
If fetch fails before an HTTP response—DNS, connectivity, or abort—the value is not a BoardApiError. Do not blindly retry mutations: an interrupted response does not prove the server made no change. Retrieve current state before deciding whether a repeat is safe. For 429 reads, use bounded backoff; for 5xx mutations, treat the outcome as unknown until verified.
Verify error handling
- Request an invalid job slug and confirm a native 404 status and UI.
- Call a private method signed out and confirm the session boundary refreshes once or signs in.
- Trigger validation and confirm the form retains typed details.
- Test a password-protected board without a grant and confirm it does not enter candidate login.
- Abort a request and confirm it follows the transport path, not validation handling.
- Confirm logs include
requestIdwhen supplied and never include credentials.
With the fundamentals in place, continue to Build your job board.