Guides

Error Handling

Error handling in experimental-agent—methods throw typed errors. Error types, try/catch patterns, backend patterns, and sandbox error handling.

Methods throw typed errors. Use try/catch to handle them.

The Pattern

import { createUIMessageStreamResponse } from "ai";

try {
  const stream = await session.stream();
  return createUIMessageStreamResponse({ stream });
} catch (error) {
  return Response.json({ error: (error as Error).message }, { status: 404 });
}

Wrap calls in try/catch and check the error type for specific handling.

Error Types

experimental-agent exports these error classes:

ErrorWhen
SessionNotFoundErrorSession ID doesn't exist
MessageNotFoundErrorMessage ID doesn't exist
SandboxNotFoundErrorSandbox not found
SandboxErrorSandbox operation failed (exec, readFile, etc.)
StorageErrorStorage operation failed
StorageConflictErrorOptimistic locking conflict (e.g. runId mismatch)

Checking Errors

Import error classes and use instanceof in catch blocks:

import {
  SessionNotFoundError,
  StorageError,
} from "experimental-agent";

try {
  const result = await session.history();
  return Response.json(result);
} catch (error) {
  if (error instanceof SessionNotFoundError) {
    return Response.json({ error: "Session not found" }, { status: 404 });
  }
  if (error instanceof StorageError) {
    return Response.json({ error: (error as Error).message }, { status: 500 });
  }
  throw error;
}

Error Handling in Backend Flows

Send and stream

import { createUIMessageStreamResponse } from "ai";
import { myAgent } from "@/agent";

const session = myAgent.session(chatId);
await session.send(message);
const stream = await session.stream();
return createUIMessageStreamResponse({ stream });

If send or stream fails, it throws. Wrap in try/catch at the route level:

try {
  const session = myAgent.session(chatId);
  await session.send(message);
  const stream = await session.stream();
  return createUIMessageStreamResponse({ stream });
} catch (error) {
  return Response.json({ error: (error as Error).message }, { status: 500 });
}

Reconnect to stream

try {
  const stream = await session.stream();
  return createUIMessageStreamResponse({ stream });
} catch (error) {
  return Response.json({ error: (error as Error).message }, { status: 404 });
}

Session history (load messages)

import { SessionNotFoundError } from "experimental-agent";

try {
  const result = await session.history();
  return Response.json(result);
} catch (error) {
  if (error instanceof SessionNotFoundError) {
    return Response.json({ error: "Session not found" }, { status: 404 });
  }
  return Response.json({ error: (error as Error).message }, { status: 500 });
}

Approval resolution

try {
  await session.send({
    type: "approval",
    approval: { approvalId, approved, reason },
  });
  return Response.json({ success: true });
} catch (error) {
  return Response.json({ error: (error as Error).message }, { status: 400 });
}

Consistent response format

import { SessionNotFoundError } from "experimental-agent";

try {
  // ... operation
} catch (error) {
  const status = error instanceof SessionNotFoundError ? 404 : 500;
  return Response.json(
    { error: (error as Error).message, code: (error as Error).name },
    { status }
  );
}

Error Handling in Tools

Tools can throw errors. Thrown errors become tool-result errors and surface as output-error in the stream:

import { tool } from "ai";
import { z } from "zod";

const ReadFile = tool({
  description: "Read a file",
  parameters: z.object({ path: z.string() }),
  execute: async ({ path }) => {
    const content = await fs.readFile(path, "utf-8");
    if (!content) throw new Error("File is empty");
    return content;
  },
});

Use try/catch in execute when you need to transform or handle errors before rethrowing:

execute: async ({ path }) => {
  try {
    return await fs.readFile(path, "utf-8");
  } catch (e) {
    throw new Error(`Failed to read ${path}: ${e instanceof Error ? e.message : String(e)}`);
  }
},

Storage Errors

Storage methods throw on failure.

  • Not found — Return null (e.g. session.get when the session doesn't exist)
  • Conflict — Throw StorageConflictError for optimistic locking failures
  • Other failures — Throw StorageError

See Custom Storage for details.

Sandbox Errors

Sandbox methods throw SandboxError on failure:

import { SandboxError } from "experimental-agent";

try {
  const result = await sandbox.exec({ command: "npm", args: ["install"] });
  console.log(result.stdout, result.stderr, result.exitCode);
} catch (error) {
  if (error instanceof SandboxError) {
    console.error("Sandbox failed:", error.message);
    return;
  }
  throw error;
}

Next Steps