Skip to content

Error codes

Every non-2xx response, on every endpoint, is one shape, and every one of them bills zero credits. Match on code; never match on message. A code is never repurposed inside /v1 and never changes the HTTP status it is returned with, so a client that switches on code keeps working. New codes may appear, so treat a code you do not recognize as its type and move on.

Each code has a page of its own at https://docs.kaho.ai/errors/<code>, which is exactly the doc_url the error body carries.

type is the coarse class, so a client can branch sensibly on a code it has never seen. The rung column is the rung of the repository’s failure policy the class corresponds to at the boundary.

typeRungCodes
invalid_request_error327
authentication_error34
permission_error35
not_found_error45
payment_required_error22
rate_limit_error29
document_error311
timeout_error22
overloaded_error21
api_error11

Grouped by HTTP status, in the order the contract declares them. Simulate is whether X-Kaho-Simulate can induce the code on a test key; on a live key the header is ignored rather than refused, so a live key can never zero its own pages.

CodetypeRetryableSimulate
malformed_jsoninvalid_request_errorNoNo
multipart_malformedinvalid_request_errorNoNo
missing_sourceinvalid_request_errorNoNo
multiple_sourcesinvalid_request_errorNoNo
unsupported_source_typeinvalid_request_errorNoNo
unknown_parameterinvalid_request_errorNoNo
invalid_parameter_typeinvalid_request_errorNoNo
query_options_not_allowedinvalid_request_errorNoNo
metadata_too_largeinvalid_request_errorNoNo
CodetypeRetryableSimulate
missing_api_keyauthentication_errorNoNo
invalid_api_keyauthentication_errorNoNo
revoked_api_keyauthentication_errorNoNo
expired_api_keyauthentication_errorNoNo
CodetypeRetryableSimulate
insufficient_creditspayment_required_errorNoYes
account_delinquentpayment_required_errorNoYes
CodetypeRetryableSimulate
insufficient_scopepermission_errorNoNo
ip_not_allowedpermission_errorNoNo
account_suspendedpermission_errorNoNo
pdf_extraction_not_permittedpermission_errorNoYes
debug_not_permittedpermission_errorNoNo
CodetypeRetryableSimulate
file_not_foundnot_found_errorNoNo
engine_not_foundnot_found_errorNoNo
unknown_endpointnot_found_errorNoNo
CodetypeRetryableSimulate
file_expirednot_found_errorNoNo
result_expirednot_found_errorNoNo
CodetypeRetryableSimulate
method_not_allowedinvalid_request_errorNoNo
CodetypeRetryableSimulate
unsupported_acceptinvalid_request_errorNoNo
CodetypeRetryableSimulate
idempotency_conflictinvalid_request_errorNoNo
idempotency_in_progressinvalid_request_errorYesNo
CodetypeRetryableSimulate
unsupported_content_typeinvalid_request_errorNoNo
CodetypeRetryableSimulate
file_too_largeinvalid_request_errorNoNo
too_many_pagesinvalid_request_errorNoYes
storage_quota_exceededinvalid_request_errorNoNo
pdf_too_complexinvalid_request_errorNoNo
CodetypeRetryableSimulate
page_range_invalidinvalid_request_errorNoNo
page_range_zeroinvalid_request_errorNoNo
page_range_reversedinvalid_request_errorNoNo
page_range_out_of_boundsinvalid_request_errorNoNo
page_range_too_complexinvalid_request_errorNoNo
unsupported_option_valueinvalid_request_errorNoNo
option_conflictinvalid_request_errorNoNo
ocr_not_availableinvalid_request_errorNoNo
feature_not_enabledinvalid_request_errorNoNo
pdf_invaliddocument_errorNoNo
pdf_corruptdocument_errorNoYes
pdf_read_errordocument_errorNoNo
pdf_parse_faileddocument_errorNoNo
pdf_encrypteddocument_errorNoYes
pdf_password_incorrectdocument_errorNoYes
pdf_unsupported_securitydocument_errorNoNo
pdf_no_pagesdocument_errorNoNo
pdf_is_xfadocument_errorNoNo
document_has_no_text_layerdocument_errorNoYes
document_too_complexdocument_errorNoNo
CodetypeRetryableSimulate
rate_limit_requestsrate_limit_errorYesYes
rate_limit_pagesrate_limit_errorYesYes
rate_limit_concurrencyrate_limit_errorYesYes
rate_limit_uploadsrate_limit_errorYesNo
rate_limit_inspectrate_limit_errorYesNo
rate_limit_tocrate_limit_errorYesNo
rate_limit_no_value_conversionsrate_limit_errorYesNo
rate_limit_unbilled_workrate_limit_errorYesNo
rate_limit_new_accountrate_limit_errorYesNo
CodetypeRetryableSimulate
request_timeouttimeout_errorYesNo
CodetypeRetryableSimulate
conversion_timeouttimeout_errorYesYes
CodetypeRetryableSimulate
internal_errorapi_errorYesNo
CodetypeRetryableSimulate
overloadedoverloaded_errorYesYes

retryable is a field rather than a status-code guessing game: it is true when the identical request, sent again later, can plausibly succeed without you changing anything. That is the 429 family, 503, 500, both timeouts and idempotency_in_progress. Everything else needs you to change the request, the document, the credential or the balance, and retrying it is a way to burn your own rate limit.

Never retry a POST without an Idempotency-Key: a retry without one is a second conversion at full price.