Back to Denoland

Error handling

examples/sandbox/error_handling.md

latest1.9 KB
Original Source

Handling sandbox command failures explicitly gives you predictable recovery paths:

ts
import { Sandbox } from "@deno/sandbox";

await using sandbox = await Sandbox.create();

// Commands throw by default on non-zero exit
try {
  await sandbox.sh`exit 1`;
} catch (error) {
  console.log("Command failed:", error);
}

// Use noThrow() to handle errors manually
const result = await sandbox.sh`exit 1`.noThrow();
console.log("Exit code:", result.status.code); // → 1
console.log("Success:", result.status.success); // → false

Deno Sandbox commands throw on any non-zero exit, so wrapping them in try/catch lets you surface clean error messages or trigger fallback logic instead of crashing the entire workflow.

When you want to inspect failures without throwing, .noThrow() returns the full status object, so you can branch on status.code or status.success, log diagnostics, or retry specific commands without losing context. This pattern is essential for robust automation where commands might fail due to user input, transient network issues, or missing dependencies.

Custom error classes

You can handle errors with custom error classes in a sandbox.

Catching SandboxCommandError lets you differentiate sandbox command failures from other exceptions. When the error is the SandboxCommandError class, you can read structured fields such as error.code or format error.message to decide whether to retry, escalate, or map exit codes to your own domain-specific errors:

ts
import { Sandbox, SandboxCommandError } from "@deno/sandbox";

await using sandbox = await Sandbox.create();

try {
  await sandbox.sh`exit 42`;
} catch (error) {
  if (error instanceof SandboxCommandError) {
    console.log("Exit code:", error.code); // → 42
    console.log("Error message:", error.message);
  }
}

This makes it easier to build higher-level automation that reacts intelligently to known failure modes instead of treating every thrown error the same.