Banata

Platform

Error Handling

Understanding Banata API error responses, error codes, and how to handle them in your application.

The Banata API uses standard HTTP status codes and returns structured JSON error responses. This page covers all error types you may encounter and how to handle them.


Error Response Format

All error responses follow this structure:

json
{
  "error": "Human-readable error message",
  "code": "MACHINE_READABLE_CODE",
  "requiredPlan": "pro",
  "currentPlan": "free"
}

The error field is always present. The code, requiredPlan, and currentPlan fields are included when relevant.


HTTP Status Codes

400 — Bad Request

Your request body or query parameters contain invalid data.

json
{ "error": "Invalid weight: 'ultra'. Must be one of: light, medium, heavy" }

Common causes:

  • Invalid enum value for weight, isolation, egressProfile, runtime, or size
  • Invalid maxDurationMs (must be positive number)
  • Invalid region (must be 3 lowercase letters)
  • Proxy/egress configuration mismatch
  • Missing required fields

401 — Unauthorized

The API key is missing, invalid, expired, or revoked.

json
{ "error": "Invalid or missing API key" }

Check that:

  • The Authorization header is present: Authorization: Bearer br_live_...
  • The key is not revoked or expired
  • The key belongs to the correct organization

403 — Forbidden

Your API key lacks the required permission, or the feature is not available on your plan.

Plan feature not available:

json
{
  "error": "Stealth mode is not available on the Free plan. Upgrade to Builder or higher to enable anti-detection.",
  "code": "PLAN_FEATURE_UNAVAILABLE",
  "requiredPlan": "builder",
  "currentPlan": "free"
}

Plan limit exceeded:

json
{
  "error": "maxDurationMs (3600000) exceeds your plan limit of 30 minutes. Current plan: pro",
  "code": "PLAN_LIMIT_EXCEEDED"
}

Permission denied:

json
{
  "error": "Insufficient permissions",
  "code": "PERMISSION_DENIED"
}

404 — Not Found

The requested session does not exist.

json
{ "error": "Session not found" }
json
{ "error": "Sandbox session not found" }

409 — Conflict

The session is in an invalid state for the requested operation.

json
{ "error": "Sandbox is not ready (state: queued)" }
json
{ "error": "Sandbox has no assigned machine" }

This usually means you are trying to execute commands or access files before the sandbox is fully started. Poll the session status until it reaches ready before sending exec/code/fs requests.

429 — Too Many Requests

You have hit a rate limit or usage cap.

Rate limit:

json
{ "error": "Rate limit exceeded. Please try again later." }

The response includes a Retry-After header with the number of seconds to wait.

Concurrent session limit:

json
{ "error": "Concurrent browser session limit reached" }

Monthly quota:

json
{ "error": "Monthly browser hours limit reached" }

502 — Bad Gateway

The request was proxied to a worker but the worker did not respond correctly.

json
{ "error": "Failed to execute command" }

This can happen with sandbox exec/code requests if the sandbox worker is unreachable. Retry the request.

503 — Service Unavailable

Scheduling failed — no machine could be assigned to your session.

json
{
  "error": "Failed to schedule sandbox",
  "code": "SCHEDULING_FAILED",
  "sessionId": "...",
  "reason": "No available machines in the requested region"
}

This is usually transient. Retry after a short delay.


Error Codes Reference

CodeStatusDescription
PLAN_FEATURE_UNAVAILABLE403Feature requires a higher plan. Check requiredPlan field.
PLAN_LIMIT_EXCEEDED403Value exceeds your plan's maximum (e.g., maxDurationMs).
PERMISSION_DENIED403API key does not have the required permission scope.
SCHEDULING_FAILED503No machine could be assigned. Includes reason for debugging.

Handling Errors in Code

With the SDK

typescript
import { BrowserCloud, BanataError } from "@banata-boxes/sdk";
 
const cloud = new BrowserCloud({ apiKey: "br_live_..." });
 
try {
  const { cdpUrl, close } = await cloud.launch({
    stealth: true,
    recording: true,
  });
  // ... use the session
} catch (error) {
  if (error instanceof BanataError) {
    switch (error.code) {
      case "PLAN_FEATURE_UNAVAILABLE":
        console.log(`Upgrade to ${error.requiredPlan} to use this feature`);
        break;
      case "PLAN_LIMIT_EXCEEDED":
        console.log("Reduce maxDurationMs or upgrade your plan");
        break;
      default:
        console.log(`Error ${error.status}: ${error.message}`);
    }
  }
}

With raw HTTP

typescript
const response = await fetch("https://api.boxes.banata.dev/v1/browsers", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${apiKey}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ stealth: true }),
});
 
if (!response.ok) {
  const error = await response.json();
 
  if (response.status === 429) {
    const retryAfter = parseInt(response.headers.get("Retry-After") || "5", 10);
    // Wait retryAfter seconds, then retry
  }
 
  if (error.code === "PLAN_FEATURE_UNAVAILABLE") {
    // Suggest upgrade to error.requiredPlan
  }
 
  throw new Error(error.error);
}

Best Practices

  1. Always check the status code before parsing the response body. A 201 is a successful creation; anything else is an error.

  2. Handle 429 with backoff. Rate limits protect both you and other users. The Retry-After header tells you exactly how long to wait.

  3. Check for PLAN_FEATURE_UNAVAILABLE before retrying. This error won't resolve with retries — you need to either remove the feature flag or upgrade your plan.

  4. Retry 5xx errors. These are almost always transient. Use exponential backoff.

  5. Wait for ready state before executing. Sending exec/code/fs requests to a sandbox in queued or assigning state returns 409. Poll first.


Next Steps