Skip to content
Documentation menu

Errors

Every error code across the REST API and the MCP server, and what to do about each.

REST error envelope

Every non-2xx REST response has the same body. code is drawn from a closed vocabulary and is what your code should branch on; message is human-readable and may change.

{
  "error": {
    "code": "UNSUPPORTED_FILE_TYPE",
    "message": "original must be a .docx, .doc, or .pdf file",
    "request_id": "01J..."
  }
}

Send an X-Request-Id header to correlate your logs with ours. If you don't, one is minted and echoed back in the response.

Request errors

StatusCodeCauseRetry?
400INVALID_REQUESTMalformed request — missing, empty, or unnamed file fieldNo, fix the request
400UNSUPPORTED_FILE_TYPEExtension is not .docx, .doc, or .pdfNo
400INVALID_COMPARISON_IDThe comparison id is malformed, or is a mrg_ merge idNo
400INVALID_MERGE_IDThe merge id is malformed, or is a cmp_ comparison idNo
400UNSUPPORTED_FORMATA requested format is unknown, or not valid for this operationNo
401INVALID_API_KEYMissing, malformed, unknown, inactive, or expired keyNo, check the credential
402USAGE_LIMIT_REACHEDThe organization's monthly upload allowance is exhaustedNo, it's a billing state
403API_KEY_ORG_MISMATCHThe key's service account no longer belongs to the key's organizationNo, issue a new key
404COMPARISON_NOT_FOUNDNo such comparison, or the key's user cannot access itNo
404MERGE_NOT_FOUNDNo such merge, or the key's user cannot access itNo
413FILE_TOO_LARGEA file exceeds the 100 MB limitNo
500INTERNAL_ERRORSomething went wrong on our sideYes, with backoff

COMPARISON_NOT_FOUND and MERGE_NOT_FOUND intentionally cover both "doesn't exist" and "not yours", so ids cannot be probed for existence.

INTERNAL_ERROR is the only code worth retrying blindly. Everything else in this table describes a request or account condition that will produce the same result next time.

Comparison failures

A comparison that cannot be generated is not an HTTP error. The request succeeded — it correctly reported that the work will not finish — so it returns 200 with "status": "failed":

{
  "comparison_id": "cmp_...",
  "status": "failed",
  "error": {
    "code": "DOCUMENT_PROTECTED",
    "upstream_code": "ONE_OR_MORE_DOCUMENTS_ARE_PROTECTED"
  }
}
error.codeMeaningWhat to do
DOCUMENT_PROTECTEDA source is password-protected or permission-restrictedRemove protection and resubmit
DOCUMENT_UNREADABLEA source could not be opened — corrupt or malformedCheck the file opens in Word
DOCUMENT_CONVERSION_FAILEDA .doc, .pdf, or email source could not be converted to .docxConvert it yourself and resubmit
SOURCE_UPLOAD_FAILEDA source did not reach storage intactResubmit
PDF_RENDER_FAILEDThe redline generated but the PDF rendering did notRequest format=docx instead
COMPARISON_FAILEDCatch-all — upstream_code carries the specific pipeline codeInspect upstream_code; contact support if it recurs

failed is terminal for that comparison. Waiting longer changes nothing; submit a new comparison to retry.

MCP errors

The MCP server does not use HTTP status codes for tool outcomes. Failures surface two ways.

Tool errors — a call that cannot proceed raises an MCP tool error carrying a message. These are argument and permission problems: too few revisions for a merge, a project the signed-in user cannot access, an exhausted upload allowance. Read the message; it says what is wrong.

Statuses — a call that succeeded but whose artifact isn't ready reports it in the result:

StatusMeaningWhat to do
readyThe artifact existsFetch download_manifest_url
processingStill generatingCall again with identical arguments
failedTerminalRead failure_code or errors; do not retry
awaiting_uploadsSources were never transferredComplete the PUTs listed in missing_uploads

A comparison can be partly successful: some formats generate while others fail. Such a comparison carries both downloads and failed_options with a failure_code. Anything present in the manifest is valid and usable.

Transfer errors

The upload endpoint returns ordinary HTTP status codes:

StatusCause
400Empty request body
403Missing, invalid, or expired upload authorization
408The upload exceeded the 300-second timeout
413The body exceeded the 100 MB cap
502Storage rejected the write
503All 16 concurrent upload slots are busy — honor Retry-After: 1

A 403 most often means the upload manifest is more than an hour old. Call the create tool again with the same version_story_id to stage fresh transfers.

If a transfer fails with a host-allowlist error rather than a status code, the calling agent's network policy is blocking *.versionstory.com. For Claude, the fix is in Settings → Capabilities — the illustrated steps are in Claude Connector Setup.

Pipeline failure codes

failure_code and upstream_code come from the document pipeline and are more specific than the public codes above. The ones you are most likely to see:

CodeMeaning
ONE_OR_MORE_DOCUMENTS_ARE_PROTECTEDA source is password-protected
ONE_OR_MORE_DOCUMENTS_ARE_UNABLE_TO_BE_OPENEDA source could not be opened
ONE_OR_MORE_DOCUMENTS_FAILED_TO_CONVERT_TO_DOCXConversion to .docx failed
ONE_OR_MORE_DOCUMENTS_FAILED_TO_UPLOAD_TO_S3A source did not reach storage
FAILED_TO_SAVE_REDLINE_AS_PDFPDF rendering of the redline failed
FAILED_TO_GENERATE_COMPARISONThe comparison itself failed
OUT_OF_MEMORYThe documents exceeded the processing budget
UNHANDLED_ERRORUnclassified failure

OUT_OF_MEMORY on very large or deeply nested documents is worth reporting to support — it is usually a fixable characteristic of the specific file rather than a hard limit.