Workspace
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"
}| Field | Type | Description |
|---|---|---|
success | boolean | Always false for errors |
error | string | Machine-readable error code |
message | string | Human-readable explanation |
Authentication errors
| HTTP | Error code | Cause | Fix |
|---|---|---|---|
| 401 | unauthorized | Missing or invalid API credentials | Check X-Client-ID and X-Client-Secret headers |
| 401 | token_expired | Workspace token has expired (30-day TTL) | Generate a new token via the API Access endpoint |
| 403 | forbidden | Valid credentials but insufficient permissions | Verify you own the workspace or have namespace access |
Quota & limit errors
| HTTP | Error code | Cause | Fix |
|---|---|---|---|
| 403 | SANDBOX_LIMIT_REACHED | Maximum workspace count reached for your plan | Delete unused workspaces or upgrade your plan |
| 403 | POOL_LIMIT_REACHED | Owned pool (total resources) exhausted | Reduce resource allocations or delete workspaces |
| 403 | RUNNING_POOL_REACHED | Running pool (active resources) exhausted | Stop a running workspace or upgrade your plan |
| 403 | quota_exceeded | Resource request exceeds plan per-workspace limits | Reduce requested CPU, memory, or disk |
| 503 | quota_unavailable | Plan resolution failed temporarily | Retry the request in a few seconds |
Handling quota errors
try {
await ws.start('ws_a1b2c3d4');
} catch (err) {
if (err.code === 'RUNNING_POOL_REACHED') {
// List running workspaces and stop one
const list = await ws.list({ status: 'running' });
await ws.stop(list[0].id);
// Retry
await ws.start('ws_a1b2c3d4');
}
}Resource errors
| HTTP | Error code | Cause | Fix |
|---|---|---|---|
| 400 | bad_request | Invalid parameters (e.g., negative CPU, invalid image) | Check request body against the API reference |
| 400 | validation_error | Request body fails schema validation | Review required fields and types |
| 400 | invalid_image | Requested image does not exist | Use the Images API to list available images |
| 400 | invalid_resources | CPU, memory, or disk outside allowed range | Check plan limits on the Pricing page |
State errors
| HTTP | Error code | Cause | Fix |
|---|---|---|---|
| 409 | invalid_state | Operation not allowed in current workspace state | Check workspace status before the operation |
| 409 | must_be_running | Operation requires the workspace to be running | Start the workspace first |
| 409 | must_be_stopped | Operation requires the workspace to be stopped | Stop the workspace first |
| 409 | must_be_paused | Operation requires the workspace to be paused | Pause the workspace first |
State machine
┌── pause ──► Paused ──► resume ──┐
│ │
Created ──► Starting ──► Running ──► Stopping ──► Stopped
│ │ │
│ └── restart ──► Starting│
│ │
└────────── destroy ◄────────────────┘Valid transitions:
| From | Allowed actions |
|---|---|
created | start, destroy |
starting | - (wait for running) |
running | stop, restart, pause, destroy |
stopping | - (wait for stopped) |
stopped | start, destroy |
paused | resume, destroy |
Not found errors
| HTTP | Error code | Cause | Fix |
|---|---|---|---|
| 404 | not_found | Workspace ID doesn't exist or was deleted | Verify the workspace ID; it may have been auto-deleted (TTL/remove_on_exit) |
| 404 | snapshot_not_found | Referenced snapshot doesn't exist | List snapshots to find valid IDs |
| 404 | workload_not_found | Referenced workload doesn't exist | List workloads to find valid IDs |
VM errors
| HTTP | Error code | Cause | Fix |
|---|---|---|---|
| 500 | server_error | Unexpected error in the VM backend | Retry the request; if persistent, contact support |
| 502 | vm_unavailable | VM host is unreachable | The workspace may be migrating; retry after a few seconds |
| 504 | vm_timeout | VM operation timed out | The workspace may be under heavy load; retry with backoff |
Rate limiting
| HTTP | Error code | Cause | Fix |
|---|---|---|---|
| 429 | rate_limited | Too many requests in a short period | Wait 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 { Workspace, OblienError } from 'oblien/workspace';
try {
const result = await ws.create({ image: 'node-20' });
} catch (err) {
if (err instanceof OblienError) {
console.error(`[${err.code}] ${err.message}`);
console.error(`HTTP Status: ${err.status}`);
switch (err.code) {
case 'SANDBOX_LIMIT_REACHED':
// Handle workspace limit
break;
case 'RUNNING_POOL_REACHED':
// Handle running pool limit
break;
case 'quota_exceeded':
// Handle resource quota
break;
case 'invalid_state':
// Handle state conflict
break;
default:
// Unknown error
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.code === 'rate_limited';
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 workspace = await withRetry(() => ws.create({ image: 'node-20' }));The SDK has built-in retry logic for transient errors. You can configure it when initializing the client. See SDK Setup for details.