Errors
The SandboxError hierarchy, the ErrorResponse shape, and the error code table.
Mode: both.
@sandbox-workers/core distinguishes two kinds of failure:
- Guest errors — the executed code raised an exception, or hit a fuel/output/result limit. These never throw:
runCode()still resolves, with the failure described inresult.error(see Code interpreter). - Transport and request errors — a binding failure, a malformed response, or a non-200 response from the runtime Worker (an invalid path, a missing file, a bad request body, and so on). These are thrown as a
SandboxErrorsubclass.
This page covers the second kind.
The SandboxError hierarchy
Every thrown error is SandboxError or one of its subclasses, all exported by @sandbox-workers/core:
| Class | code |
Extra context fields |
|---|---|---|
SandboxError |
any (base class; also thrown directly for a non-JSON or otherwise malformed error body, with code: "INTERNAL_ERROR") |
— |
FileNotFoundError |
FILE_NOT_FOUND |
path, operation |
FileExistsError |
FILE_EXISTS |
path, operation |
FileTooLargeError |
FILE_TOO_LARGE |
path, operation, maxSize, actualSize |
PermissionDeniedError |
PERMISSION_DENIED |
path, operation |
FileSystemError |
NO_SPACE, IS_DIRECTORY, NOT_DIRECTORY, or FILESYSTEM_ERROR |
path, operation |
ContextNotFoundError |
CONTEXT_NOT_FOUND |
contextId |
ValidationFailedError |
VALIDATION_FAILED |
validationErrors? (an array of { field, message }) |
CodeExecutionError |
CODE_EXECUTION_ERROR |
contextId?, ename?, evalue? |
Binding validation errors
createCodeContext({ binding }) (and default-context resolution for runCode({ binding })) probes the named binding before creating anything, and throws ValidationFailedError with one of these messages when it fails:
| Message | Cause |
|---|---|
Unknown binding 'X' |
No such key in your Worker’s env, or the name doesn’t match /^[A-Za-z_][A-Za-z0-9_]*$/ |
Binding 'X' is not a sandbox-workers runtime Worker |
The binding exists but has no fetch method, or GET /interpreter on it didn’t return { language, engine, contexts } |
Code contexts are not supported by binding 'X' (language) |
The binding is a real runtime Worker, but it reports contexts: false (a stateless-only runtime Worker: Ruby, or one deployed with --stateless) |
Pass a context or a binding |
runCode() was called with neither context nor binding |
This probe runs only on createCodeContext and default-context creation, never on every execution.
Every instance also carries error.code, error.context, error.httpStatus, error.timestamp, and error.operation (getters backed by error.errorResponse, the raw ErrorResponse).
For filesystem failures specifically, error.context.errno carries the Node-style error code (ENOENT, EEXIST, EACCES, EISDIR, ENOTDIR, EFBIG, ENOSPC, ENOTEMPTY, …) alongside the mapped code in the table above.
import { FileNotFoundError } from "@sandbox-workers/core";
try {
await sandbox.readFile("/workspace/missing.txt");
} catch (error) {
if (error instanceof FileNotFoundError) {
console.error(error.code, error.httpStatus, error.context.path);
// "FILE_NOT_FOUND", 404, "/workspace/missing.txt"
} else {
throw error;
}
}
ErrorResponse
The JSON shape every non-200 HTTP response carries, and the shape wrapped by every SandboxError:
interface ErrorResponse {
code: string;
message: string;
context: Record<string, unknown>;
httpStatus: number;
timestamp: string;
operation?: OperationType;
suggestion?: string; // typed for SDK parity; not currently emitted
documentation?: string; // typed for SDK parity; not currently emitted
}
operation, when present, is one of the dotted strings in the exported Operation object (Operation.FILE_READ = "file.read", Operation.FILE_WRITE = "file.write", Operation.FILE_DELETE = "file.delete", Operation.FILE_MOVE = "file.move", Operation.FILE_RENAME = "file.rename", Operation.FILE_STAT = "file.stat", Operation.DIRECTORY_CREATE = "directory.create", Operation.DIRECTORY_LIST = "directory.list", Operation.CODE_EXECUTE = "code.execute", Operation.CODE_CONTEXT_CREATE = "code.context.create", Operation.CODE_CONTEXT_DELETE = "code.context.delete"), typed as OperationType.
Error code table
code |
HTTP status | Meaning |
|---|---|---|
FILE_NOT_FOUND |
404 | Path does not exist |
FILE_EXISTS |
409 | Path already exists (rename/move destination, non-force conflicts) |
PERMISSION_DENIED |
403 | Path escapes /workspace, or the underlying EACCES |
IS_DIRECTORY |
400 | Expected a file, found a directory; also deleteFile() on any directory without recursive: true |
NOT_DIRECTORY |
400 | Expected a directory, found a file |
FILE_TOO_LARGE |
413 | Exceeds the 1 MiB per-file or 16 MiB per-workspace limit |
NO_SPACE |
500 | Workspace entry-count limit (4096) reached |
FILESYSTEM_ERROR |
500 | ENOTEMPTY, any other filesystem error, or any failed mkdir (which always reports this code, regardless of the underlying errno) |
CONTEXT_NOT_FOUND |
404 | Unknown contextId |
VALIDATION_FAILED |
400 | Malformed request (also used with 413/415/405 for request-shape failures) |
CODE_EXECUTION_ERROR |
500 | The engine failed before producing a result |
INTERNAL_ERROR |
500 | Anything else, or a non-JSON response |
See HTTP API for the full set of routes and status codes these errors come from.