Reference
Errors
Every reelsdk error is JSON with a stable code and a readable message. A bad request fails with a 4xx before any job starts, and a job that fails answers 422 when the inputs are the problem or 500 when we are, with the job attached.
This page lists every code the API returns, with its HTTP status and what to do about it.
Error shape#
Branch on error.code, which never changes, and show or log error.message, which is written for people. INVALID_REQUEST also lists each bad field in issues, as a path and a message.
{
"error": {
"code": "INVALID_REQUEST",
"message": "video_url: must be an http(s) URL; style: style must be a preset name or a style object",
"issues": [
{ "path": "video_url", "message": "must be an http(s) URL" },
{
"path": "style",
"message": "style must be a preset name or a style object"
}
]
}
}When a job fails, the response carries the job next to the error. Webhooks and GET /v1/jobs/{id} report the same job.error.
{
"error": {
"code": "INPUT_FETCH_FAILED",
"message": "Could not fetch video_url: HTTP 404"
},
"job": {
"id": "job_0hf8no7i1xqwngpyj317",
"op": "captions",
"status": "failed",
"stage": null,
"created_at": "2026-10-26T01:15:26.416Z",
"finished_at": "2026-10-26T01:15:29.195Z",
"outputs": {},
"result": null,
"duration_s": null,
"error": {
"code": "INPUT_FETCH_FAILED",
"message": "Could not fetch video_url: HTTP 404"
},
"usage": {
"output_seconds": 0,
"audio_seconds": 0,
"tts_characters": 0,
"images": 0
},
"poll_url": "https://api.reelsdk.com/v1/jobs/job_0hf8no7i1xqwngpyj317"
}
}Request errors#
These come back before a job starts. Requests rejected with a 4xx never count toward your daily jobs.
| Code | HTTP | When it happens and how to fix it |
|---|---|---|
| INVALID_JSON | 400 | The body is empty or isn't valid JSON. Send a JSON object with Content-Type: application/json. |
| INVALID_REQUEST | 400 | A field failed validation, wait is outside 0 to 300, or an upload has no filename or an empty body. Fix the fields in issues. |
| UNSUPPORTED_LANGUAGE | 400 | A short asked for a language other than en, es, fr, ja, zh or ko. |
| UNSUPPORTED_FILE_TYPE | 400 | An upload's extension isn't one we serve. See file types. |
| CONTENT_LENGTH_REQUIRED | 400 | An upload had no usable Content-Length. Send the whole file instead of a stream. |
| UNAUTHORIZED | 401 | The Authorization: Bearer header is missing or malformed, the key is unknown (invalid API key) or it was revoked. |
| NOT_FOUND | 404 | The job id doesn't exist or belongs to another key (unknown job), a file expired after 7 days, or the route doesn't exist. |
| METHOD_NOT_ALLOWED | 405 | Create endpoints take POST. File URLs take GET or HEAD. |
| PAYLOAD_TOO_LARGE | 413 | A JSON body is over 2 MB or an upload is over 100 MB. |
| RATE_LIMITED | 429 | The key hit a limit, or your IP sent too many bad keys. Wait Retry-After seconds. |
| INTERNAL | 500 | Something broke on our side before the job started. Retry with backoff. |
Job errors: 422#
A 422 means the job ran but its inputs can't produce a video. We don't retry these, and sending the same request again fails the same way.
| Code | HTTP | When it happens and how to fix it |
|---|---|---|
| INPUT_FETCH_FAILED | 422 | We couldn't download an input, as in Could not fetch images[2]: HTTP 403. Check that the URL is public and still valid. |
| INPUT_TOO_LARGE | 422 | An input is over 500 MB, or all inputs together are over 1,000 MB. |
| INPUT_UNSUPPORTED | 422 | A file isn't readable media, an image is over 100 megapixels, a video has no audio to transcribe, or audio or video runs over 15 minutes. |
| INVALID_SPEC | 422 | The request can't be rendered as asked, such as a slideshow that would run past 15 minutes. |
| OUTPUT_TOO_LARGE | 422 | The job wrote more than 8 GB, or its outputs add up to more than 2 GB. Lower the resolution or length. |
| CONTENT_REJECTED | 422 | Shorts only: the image safety filter flagged the scenes. Try a less graphic topic or script. |
| FFMPEG_FAILED | 422 | FFmpeg only: your command exited with an error. The message is the last useful line ffmpeg printed. |
| OUTPUT_MISSING | 422 | A file in ffmpeg outputs wasn't written or is empty. |
| TIMEOUT | 422 | FFmpeg only: the command ran past timeout_s or the 10 minute job limit. |
Job errors: 500#
A 500 means something failed on our side. We already retried the job once before you see it, except after a TIMEOUT, so wait a little before you send it again.
| Code | HTTP | When it happens and how to fix it |
|---|---|---|
| PLAN_FAILED | 500 | Shorts: writing the script failed. |
| IMAGES_FAILED | 500 | Shorts: no scene image could be drawn. |
| TTS_FAILED | 500 | Text to speech failed, or the voiceover's words couldn't be timed for captions. |
| TRANSCRIBE_FAILED | 500 | Transcribing the audio for captions failed. |
| FFMPEG_FAILED | 500 | A slideshow, captions or shorts render failed in ffmpeg. |
| TIMEOUT | 500 | The job hit the 10 minute limit. Split the work or make it shorter. |
| CONTAINER_UNAVAILABLE | 500 | No video worker could start. |
| BUSY | 500 | The video worker was still busy with another job. |
| ENGINE_UNREACHABLE | 500 | The video worker stopped answering. |
| ENGINE_ERROR | 500 | The video worker sent back a response we couldn't read. |
| STORE_FAILED | 500 | Saving the inputs or outputs failed. |
| INTERNAL | 500 | Anything unexpected, including a job interrupted more often than its one retry allows. |
When to retry#
| Status | What to do |
|---|---|
| 400, 401, 404, 405, 413 | Don't retry. Fix the request, the key or the id first. |
| 422 | Don't retry as is. Change the inputs, the command or the topic. |
| 429 | Wait the number of seconds in Retry-After, then send it again. |
| 500 | Retry with exponential backoff, starting at a few seconds. |
Last updated 26 October 2026