Errors and retries

Motioness fails loud — every error has a stable error_code you can branch on, and a request_id for support tickets.

HTTP status codes

StatusWhenBody
202Generation in flight{ status: 'pending', asset_id, eta_seconds }
400Malformed proxy URL or body validation failed{ error: '...' }
403Unknown project key, origin not allowlisted, or invalid signature{ error: '...' }
404Asset not found / not owned{ error: 'not found' }
413Source > 10 MB{ error: 'file exceeds 10 MB limit' }
415Source not png/jpg/webp{ error: 'unsupported type: ...' }
429Monthly quota exhausted{ error: 'monthly limit reached', upgrade_url }
502Last generation failed terminally{ error: 'last generation failed', asset_id, hint: 'POST /api/v1/regenerate/...' }

Error codes (in asset.failed events)

error_code is the stable identifier; error_msg is human-readable.

CodeMeaningAction
vision_blockedSource rejected by vision model (NSFW, copyright)Use a different source
vision_timeoutVision call exceeded 30sRetry; if persistent, simplify the source
source_unfetchable4xx/5xx fetching the source URLCheck the URL is publicly reachable
source_too_largeSource > 10 MBResize or upload via /api/v1/upload
source_unsupportedSource is svg / mp4 / unknown content-typeRe-encode to png/jpg/webp
i2v_failedImage-to-video model erroredRetry with regenerate; if persistent, lower motion
i2v_timeouti2v exceeded 5 minutesRetry; lower dur_seconds
merge_failedLoop stitching failedTry mode=animate-in instead
r2_write_failedR2 write erroredAuto-retried; if persistent, contact support
quota_exceededMonthly limit hit mid-flightUpgrade or wait for reset
pipeline_stalledCron reconciler gave up after 10 minRegenerate; if persistent, contact support

Built-in retry mechanisms

You don't need to handle transient errors yourself. Three independent mechanisms recover automatically:

1. Per-stage retry envelope

Transient errors (Replicate 5xx/429, R2 5xx, timeouts) retry up to 3 attempts per stage with [0s, 1s, 4s] backoff. Permanent errors (Replicate 4xx, content-type issues, quota) fail loud.

You'll see retry_scheduled events on SSE and asset.retry_scheduled webhooks when this fires.

2. Cron reconciler

A cron job runs every minute:

  • Reconcile assets stuck pending for 5–10 minutes by querying Replicate directly.
  • Mark assets stuck pending for >10 minutes as failed with error_code: pipeline_stalled.

If a Replicate webhook never lands (network blip, signature mismatch on Motioness's side, etc.), the cron is the safety net.

3. Webhook delivery retries

Outbound webhooks retry on 30s, 2m, 10m, 30m, 2h. After 5 failed attempts the delivery is dead; redeliver from the dashboard or via POST /api/projects/:id/webhooks/deliveries/:deliveryId/redeliver.

What to do on each status

Normal first-hit response. The Retry-After header tells you how many seconds the server estimates for completion. The X-Motioness-Eta-Ms header gives a more precise estimate.

Either:

  • Poll the same URL again after Retry-After.
  • Subscribe via SSE: GET /v1/{key}/events/{asset_id}.
  • Use ?wait_ms=8000 to long-poll up to 8 seconds.

Add your origin to allowed_origins (Project → Settings → Proxy), or switch to signed mode.

Subdomain matching is automatic: https://acme.com accepts *.acme.com.

Signing-mode-only. Common causes:

  • You're signing with the wrong tuple. Must be ${projectKey}:${srcUrl}:${exp} exactly.
  • exp already passed. Stick to TTLs >= 60s.
  • You used base64 instead of base64url for the source. Check for + / / characters.
  • The signing secret was rotated and the URL is signed with the old one.

Free tier: 5 generations/month. Pro: 100. Team: 500.

The error response includes upgrade_url pointing to the pricing page. After upgrade, generations resume immediately.

If you're on Pro+ and seeing this with error: "overage disabled", enable overage in Project → Settings → Billing.

The asset's last generation hit a permanent error (vision-blocked, i2v failure, etc.). The hint in the response tells you to call regenerate. Inspect asset.failed event to see error_code, then either:

  • Adjust the source (most vision_* and source_* errors require this).
  • Retry with different opts: POST /api/assets/:id/regenerate with new motion / prompt / seed.

Debugging with X-Request-Id

Every response carries X-Request-Id. Echo it back to support tickets — we can pull the full event log with one query.

To set your own, send X-Request-Id: req_my_correlation_id on the request. The server echoes it if it matches ^[\w-]{4,64}$, otherwise mints req_<8-hex>.

Ask a question... ⌘I