Error codes

Complete BoardApiError catalog with guards, recovery decisions, retries, and observability.

Every 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.

ts
class 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

ts
import {
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

GuardExact matchRecovery
isBoardApiErrorStructural BoardApiError brand, numeric status, and string codeLog structured fields and use a general failure boundary.
isNotFoundHTTP 404Render not found or try the managed redirect resolver.
isUnauthorizedHTTP 401Run the host-owned explicit refresh flow or sign out. The SDK does not refresh automatically.
isBoardPasswordRequired401 + board_password_requiredShow the board-password gate, not board-user login.
isForbiddenHTTP 403Explain or remove the action for the current viewer.
isConflictHTTP 409Re-read authoritative state before asking the user to resolve the conflict.
isRateLimitedHTTP 429Back off. Capture Retry-After in onResponse if the application needs the response header.
isValidationError400 + validation_bad_requestInterpret 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.

FamilyCodesRecovery and retry
Cross-cuttinginternal_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_errorCorrect 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 pagesboards_not_found, board_page_not_foundCheck the board identifier or route. Do not retry unchanged input.
Board-user authenticationboard_auth_email_taken, board_auth_invalid_credentials, board_auth_invalid_token, board_auth_registration_disabled, board_auth_token_expiredRender the matching registration, sign-in, or expired-token state. Credential failures are not transient.
Board passwordboard_password_required, board_password_invalidRequest or re-request the board password grant. Do not treat this as a board-user 401.
Jobsjobs_not_found, jobs_invalid_filterReturn 404 for a missing job; correct or remove an invalid filter.
Taxonomycategories_not_found, skills_not_found, places_not_foundResolve a canonical slug or return 404.
Companiescompanies_not_found, company_markets_not_found, company_salary_not_found, company_category_salary_not_foundReturn 404 or remove a link to data that no longer exists.
Salariessalaries_title_not_found, salaries_skill_not_found, salaries_location_not_found, salaries_title_location_not_found, salaries_skill_location_not_foundRedirect a resolved alias or return 404. Do not create an empty indexable salary page.
Blogblog_post_not_found, blog_author_not_found, blog_tag_not_foundHonor post redirects when returned; otherwise render 404.
Talenttalent_not_found, talent_directory_not_found, talent_directory_restrictedDistinguish a missing/private profile, disabled directory, and employer-only access. Restricted access can lead to employer sign-in or an upsell.
Job alertsjob_alert_not_found, job_alerts_disabled, candidate_alert_limit_reached, candidate_alert_not_foundRender missing/disabled state or ask the signed-in candidate to remove an alert before creating another. Retry only after state changes.
Candidate accountscandidate_entry_not_found, candidate_handle_taken, candidate_job_not_found, resume_invalid_file, resume_upload_forbiddenReload a deleted entry, choose another handle, or correct file/permission state. Do not automatically repeat an upload.
Applicationsapplications_external_apply_only, applications_guest_not_allowed, applications_job_not_found, applications_not_found, applications_resume_invalid_file, applications_unprocessableOpen 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.
Messagingmessaging_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_expiredRefresh the thread and render the precise permission, lifecycle, or moderation outcome. Back off messaging_rate_limited; do not replay message writes automatically.
Employer self-serviceemployer_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_foundRe-read the membership, job, applicant, pipeline, quota, and billing state. Ask the employer to resolve naming, membership, payment, or workflow issues before retrying.
Candidate paywallpaywall_already_active, paywall_disabled, paywall_invalid_checkout_session, paywall_no_candidate_profile, paywall_no_recurring_subscription, paywall_offer_not_foundRe-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 postingjob_posting_logo_lookup_unavailable, job_posting_logo_not_found, job_posting_rejectedContinue 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.