Error Reference
Error codes, response formats, and troubleshooting for the Protobox CLI and SDK
Every error from the Protobox API follows a consistent format. This page documents the error codes, how they surface in the CLI and SDK, and how to fix the common ones.
Error Response Format
When an API request fails, the response body has this shape:
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Tool with ID 695d6957e21c0ceb325c394d not found",
"details": null
},
"timestamp": "2026-03-21T14:30:00.000Z"
}| Field | What it tells you |
|---|---|
error.code | Machine-readable error type — branch on this in code |
error.message | Human-readable explanation, often with the resource type and ID |
error.details | Extra context — field-level validation errors, billing limits, dependencies |
Error Codes
| HTTP | Code | Common Cause | Fix |
|---|---|---|---|
| 400 | VALIDATION_ERROR | Missing field, wrong type, malformed JSON | Check field types and required fields against the API docs |
| 401 | AUTHENTICATION_ERROR | Expired or missing API key, invalid JWT | Re-authenticate with protobox login, or set a key with protobox config set apiKey <key> |
| 402 | BILLING_LIMIT_EXCEEDED | Workspace hit a tier limit or usage quota | Upgrade your plan or wait for the period to reset |
| 403 | AUTHORIZATION_ERROR | Wrong workspace, insufficient role | Verify with protobox auth status and check your role |
| 404 | NOT_FOUND | Resource deleted, wrong ID, or in another workspace | Verify the ID with protobox <resource> list |
| 409 | CONFLICT_ERROR | Duplicate name, or active dependencies | Rename, or remove dependents first |
| 429 | RATE_LIMIT_ERROR | Too many requests in a short window | Wait and retry — the SDK backs off automatically |
| 5xx | SERVER_ERROR | Server-side or transient infrastructure issue | Retry once; if it persists, report it with the requestId |
Validation Error Details
Validation errors can include field-level information:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"details": {
"fieldErrors": {
"name": ["name must be a string", "name should not be empty"],
"type": ["type must be one of: http, javascript, code"]
}
}
}
}CLI Error Format
The CLI translates API errors into colored terminal output:
✗ Error: Tool with ID 695d6957e21c0ceb325c394d not found
Code: NOT_FOUND (404)With --json, errors are returned as structured JSON and the exit code is non-zero — so set -e and if checks work in scripts.
protobox tools get 695d6957e21c0ceb325c394d --jsonSDK Error Handling
Every SDK error extends the base ChanlError class. (The product is Protobox; this internal class name is retained from the shared SDK lineage.)
Basic try/catch
import { ProtoboxSDK, ChanlError, NotFoundError, ValidationError } from '@protoboxai/sdk';
const client = new ProtoboxSDK({
baseUrl: 'https://platform.protobox.ai',
apiKey: process.env.PROTOBOX_API_KEY,
});
try {
await client.tools.get('nonexistent-id');
} catch (error) {
if (error instanceof NotFoundError) {
console.log(error.resourceType, error.resourceId);
} else if (error instanceof ValidationError) {
console.log(error.fieldErrors);
console.log(error.getFieldErrors('name'));
console.log(error.hasFieldError('name'));
} else if (error instanceof ChanlError) {
console.log(error.code, error.statusCode, error.message, error.requestId);
}
}Error Class Hierarchy
ChanlError (base)
├── NotFoundError 404 NOT_FOUND
├── ValidationError 400 VALIDATION_ERROR
├── AuthenticationError 401 AUTHENTICATION_ERROR
├── AuthorizationError 403 AUTHORIZATION_ERROR
├── ConflictError 409 CONFLICT_ERROR
├── RateLimitError 429 RATE_LIMIT_ERROR
├── ServerError 5xx SERVER_ERROR
├── NetworkError --- NETWORK_ERROR
└── TimeoutError --- TIMEOUT_ERRORType Guards
import {
isChanlError,
isNotFoundError,
isValidationError,
isAuthenticationError,
} from '@protoboxai/sdk';
try {
await client.tools.execute(toolId, { order_id: 'ORDER-12345' });
} catch (error) {
if (isNotFoundError(error)) {
console.log(`${error.resourceType} ${error.resourceId} not found`);
} else if (isAuthenticationError(error)) {
client.updateAuth({ apiKey: getNewApiKey() });
} else if (isChanlError(error)) {
console.error(`[${error.code}] ${error.message}`);
}
}Serialization
Every ChanlError is JSON-serializable for logging:
try {
await client.tools.create({ name: '' } as never);
} catch (error) {
if (isChanlError(error)) {
logger.error(error.toJSON());
}
}Retry Configuration
The SDK retries failed requests automatically. By default:
- Max retries: 3
- Initial delay: 1000ms
- Backoff multiplier: 2x (1s, 2s, 4s)
Only retryable failures retry — network errors, timeouts, and 429/5xx. Client errors (400, 401, 403, 404, 409) never retry.
const client = new ProtoboxSDK({
baseUrl: 'https://platform.protobox.ai',
apiKey: process.env.PROTOBOX_API_KEY,
retry: { maxRetries: 5, retryDelay: 500, backoffMultiplier: 3 },
});
// Disable retries
const noRetry = new ProtoboxSDK({
baseUrl: 'https://platform.protobox.ai',
apiKey: process.env.PROTOBOX_API_KEY,
retry: { maxRetries: 0, retryDelay: 0, backoffMultiplier: 1 },
});Common Scenarios
Getting Help
If you hit an error that isn't listed here:
- Capture the request ID —
error.requestIdin the SDK, or--jsonoutput from the CLI. - Check API status with
protobox health. - Include the error code, message, and request ID when you reach out.