Polimorf Docs

Errors

The Polimorf error envelope, HTTP status mapping, and the typed SDK error classes you can branch on.

Every error the API returns uses one stable envelope: a machine-readable code, the HTTP status, a human message, and — for validation errors — a list of offending fields.

The error envelope

{
  "code": "VALIDATION_ERROR",
  "status": 400,
  "message": "messages must contain at least one message",
  "fields": [{ "field": "messages", "issue": "must not be empty" }]
}
  • code is the value to branch on in your application. It is drawn from a closed catalog and is stable across releases.
  • message is for humans (logs, debugging) — do not match on it.
  • fields is present only for VALIDATION_ERROR (400).

Status mapping

The SDK throws the most specific PolimorfApiError subclass for each status, so you can catch with instanceof:

StatusSDK classTypical codes
400BadRequestErrorVALIDATION_ERROR, INVALID_REQUEST
401AuthenticationErrorUNAUTHENTICATED, INVALID_CREDENTIALS
403PermissionDeniedErrorFORBIDDEN
404NotFoundErrorASSISTANT_NOT_FOUND, DEPLOYMENT_NOT_FOUND
409ConflictErrorIDEMPOTENCY_KEY_CONFLICT
429RateLimitErrorRATE_LIMITED, COST_QUOTA_EXCEEDED
≥500ServerErrorINTERNAL_ERROR

An unmapped status is thrown as the base PolimorfApiError, so an unforeseen status never produces an unexpected shape.

Handling errors

import {
  createClient,
  PolimorfApiError,
  PolimorfError,
  BadRequestError,
  RateLimitError,
} from '@polimorfapp/sdk';

const client = createClient();

try {
  await client.assistant('support').run({ input: 'Hello' });
} catch (err) {
  if (err instanceof BadRequestError) {
    // Inspect err.fields for the offending inputs.
    console.error(err.fields);
  } else if (err instanceof RateLimitError) {
    // 429 — back off and retry.
  } else if (err instanceof PolimorfApiError) {
    // Any other non-2xx: err.status and err.code are set.
    console.error(err.status, err.code, err.message);
  } else if (err instanceof PolimorfError) {
    // Transport failure: network, timeout, or abort.
    console.error('transport error', err.cause);
  } else {
    throw err;
  }
}

Two error families exist. PolimorfApiError means the server replied with a non-2xx envelope (it has status, code, and sometimes fields). Its base, PolimorfError, is thrown when the request never completed — a network failure, timeout, or abort. Catch PolimorfError to cover both.

Switching on the code

For finer control than status classes, switch on the stable code. Unknown codes stay typed as string, so a newly published server code never breaks an older SDK build:

if (err instanceof PolimorfApiError) {
  switch (err.code) {
    case 'COST_QUOTA_EXCEEDED':
      // Workspace spend limit reached.
      break;
    case 'INVALID_CREDENTIALS':
      // Bad or revoked API key.
      break;
    default:
      // Handle or rethrow.
  }
}

Error code catalog

The codes most relevant to the runtime API:

CodeMeaning
VALIDATION_ERRORRequest body failed validation; see fields.
INVALID_REQUESTRequest was malformed or semantically invalid.
PAYLOAD_TOO_LARGERequest body exceeded the size limit.
UNAUTHENTICATEDMissing or malformed credentials.
INVALID_CREDENTIALSUnknown or revoked API key.
FORBIDDENKey lacks the required scope.
RATE_LIMITEDToo many requests; retry after backoff.
COST_QUOTA_EXCEEDEDWorkspace spend quota reached.
ASSISTANT_NOT_FOUNDNo assistant matches the slug.
DEPLOYMENT_NOT_FOUNDThe assistant is not deployed to the target environment.
IDEMPOTENCY_KEY_CONFLICTAn idempotency key was reused with a different body.
INTERNAL_ERRORUnexpected server error; safe to retry.

The catalog is a closed set; the SDK vendors it as the ErrorCode union for autocomplete while still accepting any string for forward compatibility.