Error handling
Strict vs non-strict exec, CommandError, SandboxError, and ExecConnectionError.
Strict mode (default)
By default, sb.exec() throws CommandError if the command exits with a non-zero code. This is "strict mode" — it mirrors how shell set -e works:
import { CommandError } from "@alineo-labs/sandbox";
const sb = await client.sandbox({
image: "debian:bookworm-slim",
resources: { cpu: "500m", memory: "256Mi" },
});
try {
await sb.exec("echo 'about to fail'").pipe(process.stdout);
await sb.exec("exit 42"); // throws CommandError
await sb.exec("echo 'this never runs'");
} catch (e) {
if (e instanceof CommandError) {
console.error(`CommandError: exit ${e.exitCode} — "${e.command}"`);
// CommandError: exit 42 — "exit 42"
}
} finally {
await sb.close();
}CommandError properties:
exitCode: number— the process exit codecommand: string— the command stringsandboxId: string— which sandbox it ran in
Non-strict mode
Pass { strict: false } to get the exit code in the result instead of throwing:
const { exitCode } = await sb.exec("test -f /etc/hosts", { strict: false });
if (exitCode === 0) {
console.log("file exists");
} else {
console.log("file missing");
}This is useful for commands where a non-zero exit is a valid outcome (like test, grep, diff).
Checking exit code and branching
Combine non-strict exec with conditional logic:
const sb = await client.sandbox({
image: "debian:bookworm-slim",
resources: { cpu: "500m", memory: "256Mi" },
});
try {
const { exitCode } = await sb.exec("exit 1", { strict: false });
if (exitCode === 0) {
await sb.exec("echo success").pipe(process.stdout);
} else {
await sb.exec("echo 'command failed, handled gracefully'").pipe(process.stdout);
}
} finally {
await sb.close();
}Or use when from @alineo-labs/workflow for the same pattern in a builder:
sb.exec("exit 1", { strict: false });
sb.when(
(ctx) => ctx.exitCode === 0,
(sb) => sb.exec("echo success"),
(sb) => sb.exec("echo failure"),
);Other error types
SandboxError
Thrown when a sandbox fails to create, boot, or reach Running state:
import { SandboxError } from "@alineo-labs/sandbox";
try {
const sb = await client.sandbox({
image: "nonexistent:latest",
resources: { cpu: "500m", memory: "256Mi" },
});
} catch (e) {
if (e instanceof SandboxError) {
console.error(`SandboxError: ${e.message}`, e.sandboxId ?? "");
}
}SandboxError.sandboxId may be set if the container was assigned an ID before failing.
ExecConnectionError
Thrown when execd inside the sandbox never becomes ready. The container is running from OpenSandbox's perspective, but the exec daemon isn't accepting connections after the retry window:
import { ExecConnectionError } from "@alineo-labs/sandbox";
try {
await sb.exec("echo test");
} catch (e) {
if (e instanceof ExecConnectionError) {
console.error(`ExecConnectionError: ${e.message}`);
// execd not ready for sandbox <id>
}
}Error hierarchy
Error
└── WorkflowError
├── SandboxError — container failed to start or reach Running
├── ExecConnectionError — execd not ready after retry window
└── CommandError — non-zero exit code (strict mode)Import from @alineo-labs/sandbox:
import {
CommandError,
SandboxError,
ExecConnectionError,
WorkflowError,
} from "@alineo-labs/sandbox";Catching all alineo errors
Use WorkflowError as the base class to catch any alineo-specific error:
import { WorkflowError } from "@alineo-labs/sandbox";
try {
await sb.exec("cmd");
} catch (e) {
if (e instanceof WorkflowError) {
console.error("alineo error:", e.message);
} else {
throw e; // re-throw unexpected errors
}
}