A failed call answers with an HTTP status and a JSON body:
{
"error": "invalid_body",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/invalid_body"
}
| Field | Contents |
|---|
error | The code. Each code has its own page, listed below. |
request_id | The same id as the response's Request-Id header. Quote it when you ask komplai about a call. |
doc_url | The page for the code, with what happened and what to do. |
The OpenAPI document describes this body as components.schemas.Error.
Some codes add fields that help you act: hint with engine_retired and mapping_not_available, state with job_not_finished, nerDeployment with ner_location_unavailable, estimatedSeconds and holdSeconds with use_job, and pages with scanned_pages_not_supported. The example on each code's page shows them. Apart from a Coding stream that has already begun, a failed call returns no partial result.
A few codes are the web server's own reason phrases, such as Not Found or Payload Too Large. Their bodies also carry the server's message and statusCode.
Branch on the HTTP status first and the code second, and treat a code you do not know by its status.
| Status | What it means | What to do |
|---|
| 400, 413, 415, 422 | The request, the text or the file cannot be processed as sent. | Correct it. The same request gets the same answer. |
| 401 | The key is missing, unknown, expired or revoked. | Check that you send the whole key, or create a new one. |
| 403 | The key may not do this: a scope is missing, the tool is not assigned to you, the processing is not approved, or an organisation integration key cannot use the operation. | Use a key with the right access, or ask your organisation's administrator. |
| 404 | No text job with that id for this key, a model or connection you named is not available to you, or no operation has that method and path. | Check the id, the key, the model or connection and the path. |
| 409 | The request conflicts with the current state. | Read the code: some ask you to send the request again, some to wait, and others need a change. |
| 410 | A text job ended without a result. | Submit the text again as a new job. |
| 429 | A limit is reached. | For a request limit, wait the seconds in Retry-After, then try again. For an AI spending limit, see below. |
| 500, 502, 503 | komplai or a service behind it failed or is unavailable. | Try again later. If the call may have reached a model, do not send it again automatically. |
| 504 | The time ran out. | After processing_timeout, send the text as a text job. After timeout, the outcome is unknown. |
A response without a Request-Id header was answered before the API handled the call, for example by the gateway while the API restarts. Treat it by its status.
- 429 with
Retry-After. rate_limited and processing_capacity_busy say how many seconds to wait in Retry-After, at most 60. A 429 from the per-IP limit also has x-ratelimit-limit, x-ratelimit-remaining and x-ratelimit-reset. Limits lists the limits. - 429 for AI spending. After
ai_credit_exhausted and person_ai_credit_exhausted, waiting does not help: a monthly cap starts again next month. Choose local processing, or ask your organisation's administrator about the limit. - A model may have answered. After a 502, 503 or 504 on a call that reaches a model, such as Chat or a synchronous Redact call with
llm, the model may already have worked and EU cloud usage may already count towards the cap. Do not resend such calls automatically. Text jobs and Coding have their own protection against duplicates: see Retries and idempotency. - Busy local infrastructure.
model_busy (503) on POST /v1/redact also sends Retry-After. A text job waits for its turn by itself. - Other 4xx answers do not change by trying again. Correct the request, the key or the access first, unless the code's page tells you to send the request again, as
processing_access_changed does.
A text job that fails ends in state failed, cancelled or invalidated, and GET /v1/redact/jobs/{id} names the reason in error. GET /v1/redact/jobs/{id}/result then answers 410. Codes that only end a text job, such as redact_job_stalled, have no HTTP status of their own and are listed under Text jobs at the end of the index.
When POST /v1/coding/chat/completions fails after the stream has begun, the last event is data: {"error": {"message": "…", "code": "…", "request_id": "…", "doc_url": "…"}} without data: [DONE]. Treat the outcome as unknown.
400 Bad Request
| Code | Meaning |
|---|
Bad Request | Fastify's reason phrase: a path parameter does not have the documented form, for example a job id that is not a UUID. |
empty_file | file.data decodes to nothing. |
engine_retired | engine review, the separate LLM engine, is retired. Send engine pipeline, or leave engine out, with detectors ["regex", "llm"]; hint says the same. Nothing was reserved or processed. |
file_type_mismatch | The extension or contentType disagrees with the file's content. |
invalid_body | The body is not a JSON object with the documented fields: invalid JSON, Content-Type text/plain, an unknown field, a field of the wrong type, or a required field that is missing or blank. |
invalid_coding_input | The body is not a coding request as documented. |
invalid_detectors | detectors is empty, has an unknown or repeated value, or more than three values. |
invalid_file | file is missing or malformed (filename missing, blank, longer than 255 characters or with control characters; data not a string; an unknown key), or the PDF or Word file itself is damaged or not a Word document. |
invalid_file_encoding | file.data is empty or not base64. |
invalid_idempotency_key | Idempotency-Key is not a UUID, or it was sent more than once. |
invalid_include | include has an unknown or repeated value. |
invalid_input | The request is not what the operation documents, for example invalid JSON, a field that is not listed or a value out of range. |
invalid_job | job is not a UUID. |
invalid_mapping | mapping is not an object, or a value is empty, not a string, or contains NUL or a lone surrogate. |
invalid_ner_deployment | nerDeployment is not eu-de or local. |
invalid_placeholder | A mapping key is empty, longer than 128 UTF-16 code units, has surrounding spaces, contains NUL or a lone surrogate, or is `__proto__`, `constructor` or `prototype`. |
invalid_processing | processing is not local or eu-cloud. |
invalid_request_id | X-Request-Id is missing or not a version 4 UUID. |
invalid_restore_source | Send exactly one of mapping and job. |
invalid_sources | sources has an unknown or repeated value. |
invalid_text_encoding | text contains NUL or a lone UTF-16 surrogate. |
llm_model_not_applicable | model was sent, but llm is not in detectors, or engine is not pipeline. |
llm_model_not_validated | The language model in model is not validated for Redact at the processing you chose. GET /v1/access lists the models you may name. |
ner_deployment_without_ner | nerDeployment was sent, but ner is not in detectors (or mode is regex). |
ner_model_unavailable | The NER model in nerModel is retired or does not run at the chosen place. A model other than the default also needs detectors. |
ner_model_unknown | No NER model has the id in nerModel. GET /v1/access lists the models you may choose. |
ner_model_without_ner | nerModel was sent, but ner is not in detectors (or mode is regex). |
reasoning_not_supported | The coding model does not take this reasoning_effort. |
unsupported_engine_detectors | The detectors do not fit engine agentic: it needs regex and llm, with optional ner. |
unsupported_engine_mode | mode disagrees with detectors. Leave mode out when you send detectors. |
unsupported_engine_sources | sources was sent without engine agentic. |
unsupported_file_type | The file is neither a PDF nor a Word .docx, by its content, its extension or its contentType. |
unsupported_pilot_mode | mode is not regex or ner, or semantic is true. No language model runs on this operation. |
unsupported_processing | processing eu-cloud needs llm in detectors (and engine pipeline). Add llm to detectors. |
unsupported_redact_engine | engine is not one of the documented values. |
unsupported_redact_mode | mode is not regex, ner or semantic. |
unsupported_redact_policy | policy is not all-detected. |
401 Unauthorized
| Code | Meaning |
|---|
api_key_required | No Authorization: Bearer header with a komplai key. |
invalid_api_key | The key is unknown, expired, revoked or retired, the person behind a personal key is no longer a member or no longer assigned any app the key covers, or your organisation's API access for it is not set up or no longer active. |
invalid_token | The key was revoked or expired, or its access ended, while the request was admitted or processed. |
403 Forbidden
| Code | Meaning |
|---|
agentic_lookup_not_allowed | A source in sources is not approved by the organisation's administrator. |
agentic_preview_not_enabled | The organisation's administrator has not turned on the Redact Agentic preview. |
ai_credit_not_granted | No monthly AI spending cap is set up for this month, so eu-cloud cannot run. |
app_not_assigned | The key's person lost the app or their membership while the request was admitted. |
approved_redact_storage_policy_required | Your organisation processes personal data but has no approved storage policy for text jobs. |
coding_not_enabled | Coding is not enabled for the organisation, its Chat does not run in komplai's EU cloud with an approved setup, or the key's person is not assigned Chat. |
identity_retired | The person behind a personal key has been removed from komplai. |
insufficient_scope | The key lacks a scope the operation needs (x-komplai-scopes): it was not issued or created with it, its person is no longer assigned the app, or the organisation's processing approval no longer covers it. |
integration_not_permitted | An organisation integration key cannot use this operation or this option. |
ner_model_preview_required | The NER model in nerModel is a preview. It needs your organisation's Redact preview, which an organisation integration key does not have. |
processing_access_changed | The organisation's processing setup changed while the request was handled. Send it again. |
processing_access_withdrawn | Access to the job was withdrawn after it was created: the agreement, the processing setup, the organisation's redaction rules or the storage policy for text jobs changed. The job is invalidated and its text and result are deleted. This is final: stop reading the job and do not reuse its Idempotency-Key; submit the text again as a new job when access allows it. |
processing_choice_not_allowed | The organisation does not allow this processing (local infrastructure or EU cloud) through the API, or the connection is not made available through the API. |
processing_not_approved | The organisation's processing approval for the app is missing or was withdrawn. |
processing_not_enabled | The processing is not enabled for the app in the organisation: EU processing is not approved and enabled, or the agreement keeps processing on local infrastructure. |
404 Not Found
| Code | Meaning |
|---|
connection_not_found | No connection with this id is available to you through the API. |
model_not_enabled | The model is not one you may use at this processing, or it is not offered there right now. |
Not Found | Fastify's reason phrase: no operation has this method and path. |
not_found | No job with this id for this key. A job is visible only to the key that created it, and it disappears when it expires. |
409 Conflict
| Code | Meaning |
|---|
connection_model_unavailable | The provider behind the connection does not know the model the connection names. |
duplicate_request | This X-Request-Id was used before with this key, so nothing was sent to the model. |
idempotency_conflict | This Idempotency-Key was used with a different body. Use a new UUID for a new job. |
job_not_finished | The job is still queued or running; state says which. Try again after Retry-After seconds. |
llm_model_not_validated | The language model in model is not validated for Redact at the processing you chose. GET /v1/access lists the models you may name. |
mapping_not_available | The job kept neither mapping nor changes; hint says how to submit it again. |
model_not_enabled | The model is not one you may use at this processing, or it is not offered there right now. |
processing_access_changed | The organisation's processing setup changed while the request was handled. Send it again. |
processing_policy_changed | Your organisation's redaction rules changed while the request ran. Send it again. |
reasoning_effort_not_supported | The reasoning effort komplai set for this EU language model in Redact is not one the model accepts on your organisation's EU route. Nothing was sent to the model, and the API does not send another effort. |
reasoning_not_enabled | The model does not take this reasoning_effort, or one of the organisation's own connections was sent one other than none. |
terms_changed | X-Komplai-Contract is not the current contract: the provider, its terms, the data mode, the agreement or the coding models and their prices changed. |
413 Content Too Large
| Code | Meaning |
|---|
context_limit | The input and the requested output do not fit the model: max_tokens is over the model's limit, the input with max_tokens is over its context, or, in Redact, a part of the text does not fit even after it was asked again in halves down to 1,500 characters. |
exceeds_ner_window | text is over 16,000 UTF-16 code units, or the body is over 100,000 bytes. Use POST /v1/redact for longer texts. |
file_too_complex | Reading the file took more than 120 seconds or more resources than allowed (memory, ZIP entries, XML size or depth). |
file_too_large | The file is over 50 MiB, or the body is over its byte limit. |
Payload Too Large | Fastify's reason phrase: the body is over the operation's byte limit. |
processing_complexity_exceeded | The text needs more work than its length allows: more candidate matches or matched characters than the per-character bounds in /v1/access, coreference matching work beyond its per-character bound (for example one name nested inside itself thousands of times), or more time for the organisation rules than their limit, which grows with the text and the number of rules. The bounds grow with the text, so splitting it rarely helps. Nothing partial is returned. |
restore_too_large | The body, the mapping (more than 100,000 entries, more than 2,000,000 UTF-16 code units or more than 500 fixed tokens) or the restored text (over 8,000,000 UTF-16 code units) is too large. |
result_too_large | The result would be over 32 MiB. Ask for fewer include reports or split the text. |
text_too_large | text is over the operation's limit in UTF-16 code units, or the body is over its byte limit. |
too_many_pages | The PDF has more than 2,000 pages. |
use_job | The run cannot finish within the 300 seconds a synchronous call may take. estimatedSeconds is komplai's estimate from its measured speeds, with an empty queue; holdSeconds is the limit. Nothing was processed or charged. Send the same body as a text job (POST /v1/redact/jobs), or this call with Prefer: respond-async. |
415 Unsupported Media Type
| Code | Meaning |
|---|
invalid_body | The body is not a JSON object with the documented fields: invalid JSON, Content-Type text/plain, an unknown field, a field of the wrong type, or a required field that is missing or blank. |
Unsupported Media Type | Fastify's reason phrase: the body has no Content-Type, or one the API does not read, such as XML or form data. |
422 Unprocessable Content
| Code | Meaning |
|---|
encrypted_file | The PDF is password protected. |
invalid_file | file is missing or malformed (filename missing, blank, longer than 255 characters or with control characters; data not a string; an unknown key), or the PDF or Word file itself is damaged or not a Word document. |
no_text_found | The file contains no text at all. |
scanned_pages_not_supported | A page has no text layer, for example a scan. No OCR runs. pages lists the pages; allowPagesWithoutText true processes the rest. |
429 Too Many Requests
| Code | Meaning |
|---|
ai_credit_exhausted | The organisation's monthly AI spending cap for EU cloud is reached, or its own lower limit, or on a pilot the pilot's total allowance. Local processing keeps working. |
connection_rate_limited | The provider behind the connection refused the call for now. |
person_ai_credit_exhausted | Your personal AI limit is reached (personal keys only). |
processing_capacity_busy | All organisation-rule workers in this API process are busy. There is no queue: try again after Retry-After. |
rate_limited | Too many requests: the per-minute limit of the person behind a personal key (shared with that person's other keys and use of the hub) or of the integration behind an organisation integration key (shared by its keys), the organisation's (120), the API's (300) or the per-IP network limit. Wait Retry-After seconds. |
upstream_rate_limited | The coding model's provider refused the call for now. |
500 Internal Server Error
502 Bad Gateway
| Code | Meaning |
|---|
agent_no_progress | Redact Agentic stopped making progress: several rounds in a row read nothing new, found nothing and moved to no new step. No partial result is returned. |
coding_service_unavailable | The coding model's provider failed or could not be reached, or an unexpected failure happened. |
connection_failed | The provider behind one of the organisation's own connections could not be reached or failed. |
connection_payment_required | The provider behind the connection wants payment on the organisation's account. |
connection_request_refused | The provider behind the connection refused the request, for example a value it does not take. |
connection_unauthorized | The provider refused the connection's key. |
detection_service_unavailable | The detection service could not be reached or failed. |
eu_cloud_refused | komplai's EU cloud refused the call, so the model did not answer it. |
incomplete_detection | A detection layer did not finish the whole text. No partial result is returned. |
invalid_coding_response | The model provider's stream failed validation. |
invalid_detection | A detection layer returned output that failed validation. For llm: an answer that still could not be used after its part of the text was asked again in halves down to 1,500 characters. |
invalid_response | The model's answer failed validation, so nothing was returned. |
service_unavailable | The model failed or could not be reached, or local infrastructure is not set up for this call right now. |
unsafe_placeholder | A fixed replacement token from your organisation's rules occurs in the text or collides with a label. |
504 Gateway Timeout
| Code | Meaning |
|---|
model_queue_expired | The language model's shared queue on local infrastructure did not reach this call before its deadline. Try again later, or send it as a text job, which waits for its turn. |
model_stalled | The language model stopped answering: its connection was silent, or it ran past the time its answer needs at the model's measured speed. No partial result is returned. |
processing_timeout | The call took more than 300 seconds, or the client disconnected. Send long texts as text jobs. |
timeout | The model did not answer in time. The call reached the model, so its outcome is unknown. |
Text jobs
| Code | Meaning |
|---|
processing_outcome_uncertain | A text job submitted before 20 October 2026 was interrupted during work by the language model, so komplai cannot tell whether that step finished. A job now resumes from its checkpoint instead. |
redact_job_progress_failed | The worker could not record the job's progress, so it stopped the job instead of letting it run unrecorded. No partial result is kept. Submit it again. |
redact_job_stalled | The job made no progress for 65 minutes, longer than any single step can take, and was stopped. Waiting for the language model on local infrastructure is not progress. No partial result is kept. |