Skip to main content

Error codes

All Traceable API error responses include a code field containing a machine-readable string identifier. Use code, not the HTTP status, as the primary basis for error handling logic — the same HTTP status can represent different error conditions.

Full error reference

HTTP StatusCodeMeaningCommon causeRecommended action
400VALIDATION_ERRORRequest body or query parameter failed validationMissing required field, wrong data type, invalid enum valueInspect details.fields in the response for per-field error messages. Fix the request before retrying.
400INVALID_SLUGThe slug format is invalidSlug contains uppercase letters, spaces, or special charactersURL-encode the slug and ensure it matches [a-z0-9-]+
401UNAUTHORIZEDNo authentication credentials providedMissing Authorization header on an endpoint that requires itAdd the Authorization: Bearer {key} header to the request
401INVALID_API_KEYThe provided API key is not recognised or has been revokedKey was deleted in the portal, or a typo in the key valueCheck the key value in your environment config. Generate a new key if necessary.
401EXPIRED_API_KEYThe API key has passed its expiry dateKey was created with an explicit expiry (if your account has key expiry policy enabled)Generate a new key in Settings → API Keys
403FORBIDDENAuthentication succeeded but the authenticated entity lacks permission for this actionAttempting to verify a PoLI request that belongs to a different API key, or accessing a feature not enabled for your accountVerify you are using the correct API key for this action. Contact support if you believe the restriction is incorrect.
403DPP_NOT_PUBLICThe DPP exists but is not accessible to the requesterAttempting to access a DPP that has been unpublished or is in draft stateCheck the product's status in the Traceable portal. Only published DPPs are accessible via the public API.
404PRODUCT_NOT_FOUNDNo published product found for the given identifierSlug does not exist, the DPP has been deleted, or it has not yet been published. Also returned when a productSlug in a PoLI request refers to an unknown product.Verify the identifier is correct. Check the product exists and is published in the Traceable portal.
404REQUEST_NOT_FOUNDThe PoLI access request ID does not existIncorrect requestId in a verify call, or the request was deletedCheck the requestId value. Ensure you are using the same API key that submitted the request.
409DUPLICATE_REQUESTA conflicting resource already existsSubmitting a PoLI access request when an active request already exists for the same product from the same entityUse GET /api/poli/verify to check the status of the existing request instead of creating a new one
422UNPROCESSABLE_ENTITYThe request was well-formed but semantically invalidJurisdiction code is valid ISO 3166-1 but not an EU member state for a PoLI request; productSlug refers to a product with no published DPPReview the specific constraint described in details. This is a logic error, not a format error — fix the request values.
429RATE_LIMITEDToo many requests in the current windowBurst of requests from a single IP or API key exceeding the rate limitWait for retryAfter seconds and retry with exponential backoff. See Rate Limiting.
500INTERNAL_ERRORAn unexpected error occurred on the serverA server-side bug or unhandled exceptionLog the X-Request-Id header value and contact support if the error persists. Do not retry immediately — wait at least 30 seconds.
503SERVICE_UNAVAILABLEThe platform or a critical dependency is temporarily unavailableDatabase maintenance, Redis connectivity issue, or platform deploymentRetry with exponential backoff. Check status.traceable.digital for incident information.

Error response structure

Every error response follows this structure:

{
"error": "Human-readable description",
"code": "MACHINE_READABLE_CODE",
"details": {}
}

For VALIDATION_ERROR responses, details contains field-level messages:

{
"error": "Request body validation failed",
"code": "VALIDATION_ERROR",
"details": {
"fields": {
"jurisdiction": "Must be a valid ISO 3166-1 alpha-2 country code",
"contactEmail": "Must be a valid email address"
}
}
}

For DUPLICATE_REQUEST, details contains the existing request ID:

{
"error": "An active access request already exists for this product",
"code": "DUPLICATE_REQUEST",
"details": {
"existingRequestId": "poli_req_01HABC..."
}
}

Error handling best practices

Use code, not HTTP status

// Correct: handle by code string
const data = await response.json();
if (data.code === 'DUPLICATE_REQUEST') {
return { requestId: data.details.existingRequestId, alreadyExists: true };
}

// Fragile: multiple error conditions share the same HTTP status
if (response.status === 409) { ... } // might miss VALIDATION_ERROR on status 400 with same meaning

Only retry 429 and 503

Retry with backoff exclusively for transient errors:

const RETRYABLE_CODES = new Set(['RATE_LIMITED', 'SERVICE_UNAVAILABLE']);

async function callWithRetry(fn: () => Promise<Response>): Promise<Response> {
const response = await fn();
const data = await response.json();

if (!response.ok && RETRYABLE_CODES.has(data.code)) {
// retry with backoff
}

return response; // return immediately for all other errors — retrying won't help
}

Do not retry 4xx errors without fixing the cause

A VALIDATION_ERROR, INVALID_SLUG, PRODUCT_NOT_FOUND, or DUPLICATE_REQUEST will not resolve itself on retry. Fix the request before retrying.

Log the X-Request-Id for 5xx errors

const requestId = response.headers.get('X-Request-Id');

if (response.status >= 500) {
logger.error('Traceable API server error', {
requestId,
status: response.status,
code: data.code,
url: response.url,
});
// Include requestId when contacting support
}

Surface meaningful errors to users

Map error codes to user-facing messages in your integration:

function getErrorMessage(code: string): string {
const messages: Record<string, string> = {
PRODUCT_NOT_FOUND: 'This product passport is not available. The product may not exist or may not be published yet.',
RATE_LIMITED: 'Too many requests. Please wait a moment and try again.',
SERVICE_UNAVAILABLE: 'The Traceable platform is temporarily unavailable. Please try again shortly.',
INTERNAL_ERROR: 'An unexpected error occurred. If this persists, please contact support.',
};
return messages[code] ?? 'An error occurred. Please try again.';
}