Skip to main content

Error Handling

All API errors follow a consistent format, making it easy to handle failures programmatically.

Error Response Format

Every error response includes:
{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable description of what went wrong",
    "details": {}
  },
  "requestId": "req_abc123"
}
FieldTypeDescription
successbooleanAlways false for errors
error.codestringMachine-readable error code
error.messagestringHuman-readable description
error.detailsobjectAdditional context (optional)
requestIdstringUnique request ID for debugging
Always include the requestId when contacting support — it helps us trace the exact request in our logs.

Job Error Codes

These errors occur when working with jobs, models, and user operations:
CodeHTTP StatusDescription
MODEL_NOT_FOUND404The specified model slug does not exist
MODEL_VERSION_NOT_FOUND404The specified model version does not exist
MODEL_VERSION_NOT_ACTIVE400The model version exists but is not currently active
INVALID_MODEL_SLUG400The model slug format is invalid
MODEL_ACCESS_DENIED403You do not have access to this model
INSUFFICIENT_BALANCE402Your account balance is too low for this job
INVALID_INPUT400The input parameters are invalid or missing
JOB_NOT_FOUND404The specified job ID does not exist
JOB_CANNOT_BE_CANCELLED400The job is in a state that cannot be cancelled
CONCURRENT_JOBS_EXCEEDED429Too many jobs running simultaneously
INVALID_WEBHOOK_URL400The provided webhook URL is not valid
USER_NOT_FOUND404The user account was not found
USER_BANNED403The user account has been banned
USER_INACTIVE403The user account is inactive
UNAUTHORIZED_ACCESS403You are not authorized to perform this action
PUBSUB_PUBLISH_FAILED503Internal message queue failure
INTERNAL_ERROR500An unexpected server error occurred

Authentication Error Codes

These errors occur during authentication and authorization:
CodeHTTP StatusDescription
UNAUTHORIZED401No authentication credentials provided
INVALID_API_KEY401The API key is not valid
API_KEY_INACTIVE401The API key has been deactivated
API_KEY_EXPIRED401The API key has expired
IP_NOT_WHITELISTED403Request IP is not in the allowed list
OPERATION_NOT_ALLOWED403The API key does not have permission for this operation
INVALID_WORKER_SECRET401Invalid worker authentication secret
INVALID_SESSION401The session token is invalid or expired
FORBIDDEN403Access denied
CONFIG_ERROR500Server configuration error

Retry Strategy

Not all errors should be retried. Use the HTTP status code to determine the right approach:

Retryable Errors

1

503 Service Unavailable

Temporary server issue. Retry with exponential backoff:
wait = min(baseDelay × 2^attempt, maxDelay)
Start with 1 second, max 60 seconds, up to 5 attempts.
2

429 Too Many Requests

Rate limit hit. Check the retryAfter field in the response and wait the specified duration before retrying.
{
  "error": {
    "code": "CONCURRENT_JOBS_EXCEEDED",
    "message": "Too many concurrent jobs",
    "details": { "retryAfter": 30 }
  }
}
3

500 Internal Server Error

Unexpected server error. Retry with exponential backoff, but limit attempts. If it persists, contact support.

Non-Retryable Errors

StatusAction
400 Bad RequestFix the request parameters and resubmit
401 UnauthorizedCheck your API key and authentication
402 Payment RequiredAdd funds to your account
403 ForbiddenVerify your permissions and access rights
404 Not FoundCheck the resource ID or model slug

Implementation Examples

async function submitWithRetry(jobData, maxRetries = 5) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch("https://api.muvi.video/v1/jobs/submit", {
      method: "POST",
      headers: {
        "Authorization": "Bearer YOUR_API_KEY",
        "Content-Type": "application/json"
      },
      body: JSON.stringify(jobData)
    });

    if (response.ok) {
      return await response.json();
    }

    const error = await response.json();

    // Non-retryable errors
    if (response.status >= 400 && response.status < 500 && response.status !== 429) {
      throw new Error(`${error.error.code}: ${error.error.message}`);
    }

    // Rate limited — respect retryAfter
    if (response.status === 429) {
      const retryAfter = error.error.details?.retryAfter || 30;
      await new Promise(r => setTimeout(r, retryAfter * 1000));
      continue;
    }

    // Server error — exponential backoff
    const delay = Math.min(1000 * Math.pow(2, attempt), 60000);
    await new Promise(r => setTimeout(r, delay));
  }

  throw new Error("Max retries exceeded");
}

Best Practices

Log Request IDs

Store the requestId from every response for debugging and support requests.

Handle Gracefully

Always check success field before accessing data. Never assume a request succeeded.

Use Estimate First

Call the estimate endpoint before submitting to catch INSUFFICIENT_BALANCE early.

Monitor Error Rates

Track error codes in your application to identify patterns and potential issues.