VM

Errors

All API responses follow a consistent error format. This page lists every error code, its cause, and how to resolve it.

Error response format

{
  "success": false,
  "error": "error_code",
  "message": "Human-readable description of what went wrong"
}
FieldTypeDescription
successbooleanAlways false for errors
errorstringMachine-readable error code
messagestringHuman-readable explanation

Authentication errors

HTTPError codeCauseFix
401unauthorizedMissing or invalid API credentialsCheck X-Client-ID and X-Client-Secret headers
401token_expiredVM token has expired (30-day TTL)Generate a new token via the API Access endpoint
403forbiddenValid credentials but insufficient permissionsVerify you own the VM or have namespace access

Quota & limit errors

HTTPError codeCauseFix
403SANDBOX_LIMIT_REACHEDMaximum VM count reached for your planDelete unused VMs or upgrade your plan
403POOL_LIMIT_REACHEDOwned pool (total resources) exhaustedReduce resource allocations or delete VMs
403RUNNING_POOL_REACHEDRunning pool (active resources) exhaustedStop a running VM or upgrade your plan
403quota_exceededResource request exceeds plan per-VM limitsReduce requested CPU, memory, or disk
503quota_unavailablePlan resolution failed temporarilyRetry the request in a few seconds

Handling quota errors

try {
  await client.vms.start('ws_a1b2c3d4');
} catch (err) {
  if (err.code === 'RUNNING_POOL_REACHED') {
    // List running vms and stop one
    const list = await client.vms.list({ status: 'running' });
    await client.vms.stop(list[0].id);
    // Retry
    await client.vms.start('ws_a1b2c3d4');
  }
}

Resource errors

HTTPError codeCauseFix
400bad_requestInvalid parameters (e.g., negative CPU, invalid image)Check request body against the API reference
400validation_errorRequest body fails schema validationReview required fields and types
400invalid_imageRequested image does not existUse the Images API to list available images
400invalid_resourcesCPU, memory, or disk outside allowed rangeCheck plan limits on the Pricing page

State errors

HTTPError codeCauseFix
409invalid_stateOperation not allowed in current VM stateCheck VM status before the operation
409must_be_runningOperation requires the VM to be runningStart the VM first
409must_be_stoppedOperation requires the VM to be stoppedStop the VM first
409must_be_pausedOperation requires the VM to be pausedPause the VM first

State machine

Valid transitions:

FromAllowed actions
createdstart, destroy
starting- (wait for running)
runningstop, restart, pause, destroy
stopping- (wait for stopped)
stoppedstart, destroy
pausedresume, destroy

Not found errors

HTTPError codeCauseFix
404not_foundVM ID doesn't exist or was deletedVerify the VM ID; it may have been auto-deleted (TTL/remove_on_exit)
404snapshot_not_foundReferenced snapshot doesn't existList snapshots to find valid IDs
404workload_not_foundReferenced workload doesn't existList workloads to find valid IDs

VM errors

HTTPError codeCauseFix
500server_errorUnexpected error in the VM backendRetry the request; if persistent, contact support
502vm_unavailableVM host is unreachableThe VM may be migrating; retry after a few seconds
504vm_timeoutVM operation timed outThe VM may be under heavy load; retry with backoff

Rate limiting

HTTPError codeCauseFix
429rate_limitedToo many requests in a short periodWait and retry with exponential backoff

Rate limits vary by plan. See the Pricing page for current limits.

Handling errors in the SDK

The SDK throws typed errors that you can catch and inspect:

import {
  OblienError,
  AuthenticationError,
  NotFoundError,
  RateLimitError,
  ValidationError,
  PaymentRequiredError,
  ConflictError,
} from 'oblien';

try {
  const result = await client.vms.create({ image: 'oblien/node:24' });
} catch (err) {
  if (err instanceof OblienError) {
    console.error(`[${err.status}] ${err.message}`);

    if (err instanceof PaymentRequiredError) {
      // Handle vm limit / quota
    } else if (err instanceof ConflictError) {
      // Handle state conflict
    } else if (err instanceof ValidationError) {
      // Handle bad params
    } else if (err instanceof NotFoundError) {
      // VM not found
    } else if (err instanceof RateLimitError) {
      // Rate limited - retry with backoff
    } else {
      throw err;
    }
  }
}

Retry strategy

For transient errors (5xx, timeouts), use exponential backoff:

async function withRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (err) {
      const isRetryable = err.status >= 500 || err instanceof RateLimitError;
      if (!isRetryable || i === maxRetries - 1) throw err;

      const delay = Math.min(1000 * Math.pow(2, i), 10000);
      await new Promise(r => setTimeout(r, delay));
    }
  }
}

// Usage
const vm = await withRetry(() => client.vms.create({ image: 'oblien/node:24' }));

The SDK has built-in retry logic for transient errors. You can configure it when initializing the client. See SDK Setup for details.