Error codes
Complete BoardApiError catalog with guards, recovery decisions, retries, and observability.
A
JEvery non-2xx response throws BoardApiError. The client preserves the API’s machine code, human message, structured details, request ID, HTTP status, and parsed raw body.
1234567class BoardApiError extends Error {status: number;code: BoardApiErrorCode;details?: unknown;requestId?: string;raw: unknown;}
If the response is not a parseable Cavuno error envelope, the SDK synthesizes unknown_error and retains the parsed body when one exists.
Handle an error once
12345678910111213141516171819202122232425262728293031323334import {isBoardApiError,isBoardPasswordRequired,isNotFound,isRateLimited,isUnauthorized,} from '@cavuno/board';export async function loadJob(jobSlug: string) {try {return { state: 'ready' as const, job: await board.jobs.retrieve(jobSlug) };} catch (error) {if (isBoardPasswordRequired(error)) {return { state: 'board_password_required' as const };}if (isUnauthorized(error)) {return { state: 'session_expired' as const };}if (isNotFound(error)) return { state: 'not_found' as const };if (isRateLimited(error)) return { state: 'retry_later' as const };if (isBoardApiError(error)) {console.error({code: error.code,status: error.status,requestId: error.requestId,});}throw error;}}
Catch an error where the interface can make a recovery decision. Do not turn every error into an empty list.
Guards
| Guard | Exact match | Recovery |
|---|---|---|
isBoardApiError | Structural BoardApiError brand, numeric status, and string code | Log structured fields and use a general failure boundary. |
isNotFound | HTTP 404 | Render not found or try the managed redirect resolver. |
isUnauthorized | HTTP 401 | Run the host-owned explicit refresh flow or sign out. The SDK does not refresh automatically. |
isBoardPasswordRequired | 401 + board_password_required | Show the board-password gate, not board-user login. |
isForbidden | HTTP 403 | Explain or remove the action for the current viewer. |
isConflict | HTTP 409 | Re-read authoritative state before asking the user to resolve the conflict. |
isRateLimited | HTTP 429 | Back off. Capture Retry-After in onResponse if the application needs the response header. |
isValidationError | 400 + validation_bad_request | Interpret known details for field errors and keep an unknown-details fallback. |
The guards are structural rather than instanceof-only so they remain correct when separate helper bundles contain their own class copy.
Complete known-code catalog
This is the complete exported BOARD_API_ERROR_CODES catalog in version 1.34.0. Codes can be added compatibly within API v1, so a default branch remains mandatory.
| Family | Codes | Recovery and retry |
|---|---|---|
| Cross-cutting | internal_error, validation_bad_request, validation_payload_too_large, rate_limited, rate_limit_unavailable, search_unavailable, too_many_filter_values, pagination_invalid_cursor, pagination_offset_too_large, auth_unauthenticated, auth_forbidden, plan_upgrade_required, unknown_error | Correct validation, payload, filter, cursor, window, auth, or plan state. Back off public reads for rate/search/service failures; do not blindly retry writes or unknown outcomes. |
| Board resolution and pages | boards_not_found, board_page_not_found | Check the board identifier or route. Do not retry unchanged input. |
| Board-user authentication | board_auth_email_taken, board_auth_invalid_credentials, board_auth_invalid_token, board_auth_registration_disabled, board_auth_token_expired | Render the matching registration, sign-in, or expired-token state. Credential failures are not transient. |
| Board password | board_password_required, board_password_invalid | Request or re-request the board password grant. Do not treat this as a board-user 401. |
| Jobs | jobs_not_found, jobs_invalid_filter | Return 404 for a missing job; correct or remove an invalid filter. |
| Taxonomy | categories_not_found, skills_not_found, places_not_found | Resolve a canonical slug or return 404. |
| Companies | companies_not_found, company_markets_not_found, company_salary_not_found, company_category_salary_not_found | Return 404 or remove a link to data that no longer exists. |
| Salaries | salaries_title_not_found, salaries_skill_not_found, salaries_location_not_found, salaries_title_location_not_found, salaries_skill_location_not_found | Redirect a resolved alias or return 404. Do not create an empty indexable salary page. |
| Blog | blog_post_not_found, blog_author_not_found, blog_tag_not_found | Honor post redirects when returned; otherwise render 404. |
| Talent | talent_not_found, talent_directory_not_found, talent_directory_restricted | Distinguish a missing/private profile, disabled directory, and employer-only access. Restricted access can lead to employer sign-in or an upsell. |
| Job alerts | job_alert_not_found, job_alerts_disabled, candidate_alert_limit_reached, candidate_alert_not_found | Render missing/disabled state or ask the signed-in candidate to remove an alert before creating another. Retry only after state changes. |
| Candidate accounts | candidate_entry_not_found, candidate_handle_taken, candidate_job_not_found, resume_invalid_file, resume_upload_forbidden | Reload a deleted entry, choose another handle, or correct file/permission state. Do not automatically repeat an upload. |
| Applications | applications_external_apply_only, applications_guest_not_allowed, applications_job_not_found, applications_not_found, applications_resume_invalid_file, applications_unprocessable | Open the external apply URL, request sign-in, return 404, correct the file, or show the server’s workflow rejection. Native apply itself converges on an existing application; other writes are not blanket-retried. |
| Messaging | messaging_application_not_found, messaging_application_not_linked, messaging_blocked, messaging_cannot_block_self, messaging_cold_rule, messaging_conversation_not_found, messaging_disabled, messaging_edit_window_expired, messaging_message_deleted, messaging_message_not_found, messaging_not_author, messaging_not_participant, messaging_not_permitted, messaging_not_recipient, messaging_rate_limited, messaging_recipient_not_found, messaging_recipient_not_open, messaging_unsend_window_expired | Refresh the thread and render the precise permission, lifecycle, or moderation outcome. Back off messaging_rate_limited; do not replay message writes automatically. |
| Employer self-service | employer_applicant_not_found, employer_ats_unprocessable, employer_checkout_failed, employer_company_exists, employer_company_name_taken, employer_company_not_found, employer_job_not_found, employer_job_slug_taken, employer_jobs_quota_exceeded, employer_not_member, employer_payment_required, employer_pipeline_stage_not_found | Re-read the membership, job, applicant, pipeline, quota, and billing state. Ask the employer to resolve naming, membership, payment, or workflow issues before retrying. |
| Candidate paywall | paywall_already_active, paywall_disabled, paywall_invalid_checkout_session, paywall_no_candidate_profile, paywall_no_recurring_subscription, paywall_offer_not_found | Re-read offers and the access grant, create the required profile, or hide recurring management for lifetime access. Never infer access from a retry or redirect. |
| Public job posting | job_posting_logo_lookup_unavailable, job_posting_logo_not_found, job_posting_rejected | Continue without automatic logo discovery when appropriate, or show the posting rejection. Do not automatically resubmit a paid posting. |
Retry rules
The SDK performs exactly one fetch for every method call.
- Public reads can be retried by the host with bounded backoff after 429 or transient 5xx/search failures.
- A 401 refresh is explicit because refresh tokens rotate. Coordinate one refresh, persist the new pair, then retry the owning read once.
- Do not retry validation, permission, not-found, plan, quota, or conflict errors until input or server state changes.
- Do not blanket-retry writes. Some individual operations converge or support a specific retry contract, but the SDK provides no global mutation idempotency promise.
- For a network failure after a write, the result can be unknown. Re-read state before offering another submission.
Observability and user copy
Use code for control flow and translation lookup. The server’s message is useful for diagnostics but is not a stable localization key. Treat details as unknown until narrowed for the specific code.
Log code, status, requestId, route or operation name, and non-sensitive context. Never log access tokens, password grants, resumes, application content, messages, checkout secrets, or the entire raw body by default.
Verify error handling
Request a known missing resource in development. Confirm that the UI reaches the 404 branch and the diagnostic event contains the server request ID when one was returned. Then simulate an unknown code and confirm the default branch remains reachable.