API docs · Reference
Errors
Every API error code with its HTTP status, what it means, what to do and whether to retry. Plus the job and stage failure codes.
The error envelope
Every error response has the same shape:
{
"error": "callbackUrl must be a public HTTPS URL.",
"code": "INVALID_CALLBACK_URL",
"docUrl": "https://framequery.com/docs/errors#INVALID_CALLBACK_URL",
"param": "callbackUrl",
"requestId": "3c9a7e1f5b2d4068"
}| Field | Notes |
|---|---|
code | Stable identifier. Branch on this |
error | Human-readable message. It can change; do not parse it |
docUrl | This page, at the code's anchor |
param | The request field or query parameter at fault, as a JSON path (fileName, audioTracks[2].offsetMs, clips[3].sourceUrl, metadata.assetId, cursor). Present only when one field is to blame |
requestId | Also in the X-Request-Id response header. Quote it to support |
Some codes add fields, listed below (for example state and reason on RESULTS_UNAVAILABLE, maxUploadBytes on FILE_TOO_LARGE).
When to retry
- Retry every
429and503, and409IDEMPOTENCY_IN_PROGRESSandRESULTS_NOT_READY. All of them carryRetry-Afterin seconds: wait that long, then retry, reusing the sameIdempotency-Keyon creates. - Back off and retry
500 INTERNAL_ERROR(exponential backoff, same idempotency key). It has noRetry-After. - Do not retry anything else unchanged. Every other
4xxis final for that request: fix it first.
The SDKs follow these rules automatically, honouring Retry-After up to 60 seconds.
Summary
| Code | HTTP | Retry? |
|---|---|---|
INVALID_REQUEST | 400 | No |
INVALID_URL | 400 | No |
URL_NOT_ALLOWED | 400 | No |
INVALID_CALLBACK_URL | 400 | No |
UNAUTHORIZED | 401 | No |
INSUFFICIENT_CREDITS | 402 | After topping up |
INSUFFICIENT_SCOPE | 403 | No (reserved) |
ACCOUNT_SUSPENDED | 403 | No |
NOT_FOUND | 404 | No |
RESULTS_UNAVAILABLE | 404 | No, never |
JOB_NOT_CANCELLABLE | 409 | No |
IDEMPOTENCY_IN_PROGRESS | 409 | Yes, after Retry-After (2 s) |
RESULTS_NOT_READY | 409 | Yes, after Retry-After (15 s) |
FILE_TOO_LARGE | 413 | No |
UNSUPPORTED_FORMAT | 415 | No |
IDEMPOTENCY_BODY_MISMATCH | 422 | No |
RATE_LIMITED | 429 | Yes, after Retry-After |
TOO_MANY_ACTIVE_JOBS | 429 | Yes, after Retry-After (30 s) |
THROTTLED | 429 | Not in practice (Retry-After 3600 s) |
INTERNAL_ERROR | 500 | Yes, with backoff |
SERVICE_UNAVAILABLE | 503 | Yes, after Retry-After (30 s) |
Request errors (400)
INVALID_REQUEST
400, not retryable. The body or a query parameter is malformed, missing, or out of range: a missing fileName, an unknown processingMode, metadata over the limits, a bad cursor, state and status filters combined, track missing on a multi-track SRT request. param names the field. Fix it and send a new request.
INVALID_URL
400, not retryable. A media URL (url, audioUrl, audioTracks[].url, clips[].sourceUrl) is not an absolute http or https URL. Send the full URL including the scheme.
URL_NOT_ALLOWED
400, not retryable. The URL points to a private, loopback, link-local or cloud-metadata address, or an internal host name. We only fetch from the public internet. Use a publicly reachable URL, such as a presigned link to your object storage.
INVALID_CALLBACK_URL
400, not retryable. callbackUrl (or the url of POST /webhooks/test) is not a public HTTPS URL. Use https:// on a public host; plain HTTP and private addresses are refused.
Authentication and account (401, 402, 403)
UNAUTHORIZED
401, not retryable. The API key is missing, malformed, revoked, rotated or expired. Check that FRAMEQUERY_API_KEY holds a current fq_live_ key and that you send it as Authorization: Bearer <key> or X-API-Key: <key>. After a rotation the old key stops working within about a minute. See Authentication.
INSUFFICIENT_CREDITS
402, retry after topping up. Your available credits (balance minus holds for running jobs) do not cover even the 30-second minimum for this job. Buy credits on the API keys page and check GET /quota. The same code appears as a job error when the balance cannot cover the full file once its duration is known; that job is not charged.
INSUFFICIENT_SCOPE
403. Reserved for scoped keys. Keys have no scopes during the beta, so the API does not return it today.
ACCOUNT_SUSPENDED
403, not retryable. The account is suspended. Contact support@framequery.com.
Not found (404)
NOT_FOUND
404, not retryable. No such job, track or key for this account. Jobs of other accounts look exactly like missing ones, and an id that is not a UUID is also 404. Check the id and that the key belongs to the account that created the job.
RESULTS_UNAVAILABLE
404, never retry. The requested result does not exist and never will: the stage was skipped or failed, the audio track failed, or the job was cancelled, expired or failed before the stage ran. The body adds state, stage, stageStatus, reason (processing_mode, audio_only_input, no_audio, stage_skipped, stage_failed, track_failed, job_cancelled, job_expired, job_failed), and errorCode or trackIndex when relevant. Stop polling for this result. See Results.
Conflicts (409, 422)
JOB_NOT_CANCELLABLE
409, not retryable. The job is already completed, failed, cancelled or expired. The body adds jobId and state. Nothing to do.
IDEMPOTENCY_IN_PROGRESS
409, retryable. An earlier request with the same idempotency key is still running. Wait Retry-After (2 seconds) and retry with the same key and body; you will get the original response.
RESULTS_NOT_READY
409, retryable. The stage is pending or running and may still complete. The body adds state, stage and stageStatus. Retry after Retry-After (15 seconds) or wait for the webhook.
IDEMPOTENCY_BODY_MISMATCH
422, not retryable. The idempotency key was already used, within the last 24 hours, with a different request body (or the header and body keys differ). Use a new key for each distinct request.
File problems (413, 415)
FILE_TOO_LARGE
413, not retryable. fileSizeBytes is over the limit for the file's tier (20 GiB standard, 100 GiB camera RAW). The body adds maxUploadBytes and formatTier, and param is fileSizeBytes. Split the file, or ask us about a higher limit.
UNSUPPORTED_FORMAT
415, not retryable. The file type is blocked (executables and scripts), or it is a camera RAW format that is not enabled yet. Check GET /formats. See Formats and limits.
Rate limits (429)
RATE_LIMITED
429, retryable. The account went over a per-minute limit (600 GETs, 30 job creations, 120 other requests), or a client IP went over 120 requests per minute on the keyless endpoints. Wait Retry-After seconds. X-RateLimit-Reset is when the window resets, as a Unix timestamp. See Rate limits.
TOO_MANY_ACTIVE_JOBS
429, retryable. The account has too many unfinished jobs. The body adds maxActiveJobs and activeJobs. Wait Retry-After (30 seconds) or for running jobs to finish, then retry. Ask us if you need a higher limit.
THROTTLED
429. Job creation is temporarily restricted for this account, with Retry-After: 3600. The SDKs do not wait that long. Contact support@framequery.com if it persists.
Server errors (500, 503)
INTERNAL_ERROR
500, retry with backoff. Something failed on our side. Retry with exponential backoff and the same idempotency key, so a create that did succeed is replayed rather than duplicated. If it persists, send us the requestId.
SERVICE_UNAVAILABLE
503, retryable. A dependency is briefly unavailable, for example your credit balance could not be verified. Retry after Retry-After (30 seconds).
Job and stage error codes
These are not HTTP errors. They appear in a job's error.code when its state is failed, and in stages.<stage>.error.code for a stage that failed. A failed stage is never charged; other stages that completed are charged and stay readable.
| Code | Stage | Meaning | What to do |
|---|---|---|---|
VALIDATION_FAILED | ingest | Unsupported or corrupt media, or a limit (such as duration) exceeded | Check the file plays and is within limits |
INSUFFICIENT_CREDITS | ingest | The balance could not cover the full file once its duration was known | Buy credits, then create a new job |
FETCH_FAILED | ingest | The source URL could not be downloaded (unreachable, an HTTP error, an expired link or token) | Check the URL works from the public internet, then create a new job |
INGEST_FAILED | ingest | The file could not be processed | Create a new job once; if it fails again, contact us with the jobId |
EXTERNAL_AUDIO_FAILED | ingest | A separate audio file could not be processed | Check the audio file and its URL |
VISION_FAILED | vision | Scene analysis failed | Resubmit with processingMode: "vision" |
CONTENT_BLOCKED | vision | The content is not permitted by the acceptable-use policy | See our terms |
TRANSCRIPT_FAILED | transcript | Transcription failed | Resubmit with processingMode: "transcript" |
PROCESSING_FAILED | any | Another failure | Resubmit; contact us if it repeats |
CANCELLED | any | The stage was skipped because you cancelled the job | Nothing |
EXPIRED | any | The job expired before the stage ran | Create a new job |
Resubmitting a single mode after a partial failure means you only pay for the stage you are missing.