Skip to main content
When a request fails, the Varo Cloud API returns a JSON error object with a machine-readable code and a human-readable message so your application can handle failures programmatically and surface clear feedback to users.

Error Response Format

All error responses share the same envelope structure. The top-level error object always contains code, message, and request_id. For validation failures, a details array is also included with field-level information:
{
  "error": {
    "code": "validation_error",
    "message": "The request body contains invalid fields.",
    "details": [
      {
        "field": "environment",
        "issue": "must be one of: development, staging, production"
      }
    ],
    "request_id": "req_abc123"
  }
}
Include the request_id value when contacting Varo Cloud support — it allows the support team to trace and resolve your request quickly.

HTTP Status Codes

The API uses standard HTTP status codes to indicate the outcome of every request.
StatusMeaning
200 OKThe request succeeded and the response body contains the requested data.
201 CreatedA new resource was successfully created. The response body contains the created resource.
204 No ContentThe request succeeded but there is no response body (for example, a successful DELETE).
400 Bad RequestThe request was malformed — for example, invalid JSON syntax or a missing required header.
401 UnauthorizedThe API key is missing, invalid, or has been revoked.
403 ForbiddenThe API key is valid but does not have permission to perform this action.
404 Not FoundThe requested resource does not exist or you do not have access to it.
409 ConflictThe request conflicts with the current state — for example, creating a resource with a name that already exists.
422 Unprocessable EntityThe request was well-formed but failed validation. Check the error.details array for field-level issues.
429 Too Many RequestsYou have exceeded the rate limit for your API key.
500 Internal Server ErrorAn unexpected error occurred on Varo Cloud’s servers. This is not caused by your request.
503 Service UnavailableVaro Cloud is temporarily unavailable, typically due to planned maintenance or an active incident.

Error Codes

The error.code field contains a stable, machine-readable string that identifies the type of failure. Use this value in your error-handling logic rather than parsing the human-readable message.
CodeTypical HTTP StatusDescription
unauthorized401API key is missing or invalid.
forbidden403API key is valid but lacks the required permission.
not_found404The requested resource does not exist.
invalid_request400The request is malformed or missing required parameters.
validation_error422One or more fields in the request body failed validation.
conflict409The operation conflicts with existing data or resource state.
rate_limited429The API key has exceeded its request quota.
server_error500An unexpected internal error occurred.
service_unavailable503The service is temporarily offline or undergoing maintenance.

Handling Validation Errors

When the API returns a validation_error, the error.details array contains one entry per invalid field, each with a field name and an issue description. Iterate over details to surface actionable feedback:
const res = await fetch('https://inference.varo.cloud/v1/deployments', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(payload)
});

if (!res.ok) {
  const { error } = await res.json();

  if (error.code === 'validation_error') {
    error.details.forEach(d => console.error(`${d.field}: ${d.issue}`));
  }

  throw new Error(error.message);
}
This pattern lets you map error.details directly onto form field errors or structured log entries without relying on string-matching the human-readable message.

Retries and Rate Limiting

On a 429 Too Many Requests response, do not retry immediately. Read the X-RateLimit-Reset header, which contains a Unix timestamp indicating when your quota resets, and wait until that time before sending another request.On 500 Internal Server Error or 503 Service Unavailable responses, use exponential backoff starting at 1 second. These errors are typically transient and resolve quickly, but hammering the API during an incident will delay recovery and exhaust your rate limit.
The following snippet demonstrates a simple retry helper with exponential backoff for server-side errors and respect for the rate-limit reset time:
async function fetchWithRetry(url, options, maxRetries = 4) {
  let delay = 1000; // start at 1 second

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const res = await fetch(url, options);

    // Success or a client error that won't benefit from a retry
    if (res.ok || (res.status >= 400 && res.status < 500 && res.status !== 429)) {
      return res;
    }

    if (res.status === 429) {
      // Respect the rate-limit reset timestamp
      const resetAt = res.headers.get('X-RateLimit-Reset');
      const waitMs = resetAt
        ? Math.max(0, Number(resetAt) * 1000 - Date.now())
        : delay;
      console.warn(`Rate limited. Retrying after ${waitMs}ms.`);
      await new Promise(resolve => setTimeout(resolve, waitMs));
    } else {
      // 500 / 503 — exponential backoff with jitter
      const jitter = Math.random() * 500;
      console.warn(`Server error ${res.status}. Retrying in ${delay + jitter}ms.`);
      await new Promise(resolve => setTimeout(resolve, delay + jitter));
      delay *= 2; // double the delay for the next attempt
    }
  }

  throw new Error(`Request failed after ${maxRetries} retries: ${url}`);
}