Error Reference
All ViralSync API errors follow a consistent JSON format. This page lists every error code, its HTTP status, and how to resolve it.
Error response format
{
"error": "Human-readable description of the error.",
"code": "MACHINE_READABLE_CODE"
}
error— A description suitable for logging or displaying to technical users.code— A stable, machine-readable identifier you can use in your application logic.
HTTP status codes
| Status | Meaning |
|---|---|
400 | Bad Request — validation error in the request body or parameters |
401 | Unauthorized — API key is missing, invalid, or revoked |
402 | Payment Required — quota or plan limit exceeded |
403 | Forbidden — your plan does not allow this operation |
404 | Not Found — the requested resource does not exist |
409 | Conflict — invalid state transition or concurrency limit hit |
429 | Too Many Requests — rate limit exceeded |
500 | Internal Server Error — unexpected server-side failure |
503 | Service Unavailable — render infrastructure temporarily unavailable |
Error code catalog
Authentication errors
| Code | Status | Description | Resolution |
|---|---|---|---|
UNAUTHORIZED | 401 | API key is missing or invalid. | Ensure the x-api-key header is set with a valid key from Dashboard → Settings → API Keys. |
API_KEY_REVOKED | 401 | The API key has been revoked. | Generate a new API key in the dashboard. |
FORBIDDEN | 403 | Your plan does not allow this operation. Most commonly: attempting to use the REST API on a Free plan. | Upgrade to Pro or higher to access the API. |
Quota errors
| Code | Status | Description | Resolution |
|---|---|---|---|
RENDER_QUOTA_EXCEEDED | 402 | Monthly render minute limit reached. | Wait for the monthly reset on the 1st, or upgrade your plan. |
RENDER_QUOTA_DAILY_EXCEEDED | 402 | Free-plan daily cap (5 min/day) reached. | Wait until midnight UTC for the daily reset, or upgrade. |
CONCURRENCY_LIMIT_EXCEEDED | 409 | Maximum concurrent render jobs already running. Your plan allows 1 (Free), 3 (Pro), or 6 (Business) simultaneous jobs. | Wait for a running job to complete before submitting a new one. |
STORAGE_QUOTA_EXCEEDED | 402 | Asset storage limit reached. | Delete unused media assets or upgrade to a plan with more storage. |
Render job validation errors
| Code | Status | Description | Resolution |
|---|---|---|---|
INVALID_MOVIE_JSON | 400 | The movie object failed schema validation. | Check that all required fields are present: scenes (array, at least 1 element), each scene has a unique id and duration > 0, each layer has id, type, startTime, duration, zIndex, position, and size. |
PLAN_RESOLUTION_EXCEEDED | 400 | The width × height exceeds your plan's maximum resolution. | Reduce canvas dimensions or upgrade. Free: 720p max, Pro: 1080p max, Business: 1440p max. |
PLAN_DURATION_EXCEEDED | 400 | Total scene duration exceeds your plan's per-job limit. | Reduce the total video length or upgrade. Free/Pro: 10 min max, Business: 20 min max. |
MISSING_PROJECT_ID | 400 | projectId field is missing or empty. | Include a valid projectId from Dashboard → Projects. |
INVALID_KIND | 400 | kind field is missing or not "movie". | Set "kind": "movie" in your request body. |
Asset errors
| Code | Status | Description | Resolution |
|---|---|---|---|
ASSET_NOT_FOUND | 400 | A layer's source URL returned a non-200 HTTP response when the render worker attempted to fetch it. | Verify the URL is publicly accessible. Try curl -I YOUR_URL to confirm it returns 200 OK. |
ASSET_DOWNLOAD_FAILED | 500 | The source URL was reachable but the download failed (network timeout, partial response, etc.). | Retry the job. If the issue persists, move the asset to a more reliable CDN. |
ASSET_FORMAT_UNSUPPORTED | 400 | The downloaded file is in a format FFmpeg cannot process. | Use MP4/H.264 for video, JPEG/PNG/WebP for images, MP3/AAC for audio. |
Render execution errors
| Code | Status | Description | Resolution |
|---|---|---|---|
SCENE_RENDER_FAILED | 500 | FFmpeg failed while rendering a specific scene. The scene's layer configuration may contain conflicting values. | Check layer transform values (especially opacity, scale). Ensure startTime + duration ≤ scene.duration for all layers. |
ASSEMBLY_FAILED | 500 | FFmpeg failed to concatenate the rendered scene clips. | Usually a transient infrastructure issue. Retry the job. If it persists, contact support with the jobId. |
RENDER_TIMEOUT | 500 | A scene or assembly job exceeded the 30-minute hard timeout. | Reduce scene complexity. Break very long videos into multiple shorter jobs. |
FFMPEG_FILTER_ERROR | 500 | An invalid FFmpeg filter graph was generated from your layer configuration. | Review transform values and layer properties. Zero-dimension layers (e.g. size: { width: 0, height: 0 }) are valid only for audio layers. |
NO_OUTPUT_PRODUCED | 500 | The render completed but produced no output file. | Ensure at least one scene has visible layers and duration > 0. |
Job management errors
| Code | Status | Description | Resolution |
|---|---|---|---|
JOB_NOT_FOUND | 404 | The requested job does not exist or belongs to a different account. | Verify the jobId is correct and was created with the same API key. |
INVALID_TRANSITION | 409 | Attempted to cancel or modify a job that is already in a terminal state (done, failed, cancelled). | Check status before attempting state transitions. Terminal jobs cannot be modified. |
JOB_CANNOT_BE_DELETED | 400 | Attempted to delete a job that is still running. | Cancel the job first (POST /v1/jobs/{jobId}/cancel), then delete it. |
Rate limit errors
| Code | Status | Description | Resolution |
|---|---|---|---|
RATE_LIMITED | 429 | Too many API requests within the sliding window. All plans share a limit of 120 requests per 60 seconds per API key. | Wait for the number of seconds in the Retry-After response header, then retry. Implement exponential backoff for automated systems. |
Infrastructure errors
| Code | Status | Description | Resolution |
|---|---|---|---|
RENDER_PROVIDER_UNAVAILABLE | 503 | The render infrastructure (Modal, Cloud Run, etc.) is temporarily unavailable. | Retry after 30–60 seconds. Check status.viralsync.io for active incidents. |
INTERNAL_ERROR | 500 | An unexpected server-side error occurred. | Retry once. If the error persists, contact support with the jobId and the full error response. |
Retry guidance
| Error type | Safe to retry immediately? | Recommended action |
|---|---|---|
5xx server errors | Yes, after 5–10 seconds | Retry up to 3 times with exponential backoff |
503 RENDER_PROVIDER_UNAVAILABLE | Yes, after 30 seconds | Check status page; retry when infrastructure is healthy |
429 RATE_LIMITED | Yes, after Retry-After seconds | Always honour the Retry-After header |
409 CONCURRENCY_LIMIT_EXCEEDED | Yes, after a running job completes | Poll GET /v1/jobs to find when a slot opens |
4xx validation errors | No | Fix the request payload before retrying |
401 / 403 auth errors | No | Fix the API key or plan before retrying |
402 quota errors | No | Wait for reset or upgrade plan |
Webhook error events
When a job fails, ViralSync also delivers a webhook event to your callbackUrl (if configured):
{
"jobId": "job_a1b2c3d4e5f6",
"status": "failed",
"progress": 0.33,
"error": "SCENE_RENDER_FAILED: FFmpeg exited with code 1 on scene_2",
"outputUrl": null
}
See Webhooks → for the full event reference.