mastra-ai/mastra · error

StdioCodeModeTransport requires a sandbox

Error message

StdioCodeModeTransport requires a sandbox

What it means

StdioCodeModeTransport runs model-authored code in a child process, which by definition requires a sandbox handle. Its run() throws if the opts.sandbox field is absent, because there is no safe way to spawn the program without one.

Source

Thrown at packages/core/src/tools/code-mode/transport.ts:31

import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { pathToFileURL } from 'node:url';

import { SandboxFeatureNotSupportedError } from '../../workspace/errors';
import { buildRunner, buildProgramModule, FRAME_PREFIX } from './runner';
import { sanitizeToolId } from './stub-generator';
import type { CodeModeRunnerFrame, CodeModeToolResult, CodeModeTransport } from './types';

/**
 * Default transport: writes the runner to a temp dir, spawns
 * `node <runner>`, and bridges RPC over stdio.
 */
export class StdioCodeModeTransport implements CodeModeTransport {
  async run(opts: Parameters<CodeModeTransport['run']>[0]): Promise<CodeModeToolResult> {
    const { sandbox, program, toolIds, dispatch, timeout, abortSignal, onExternalCall, onExternalResult } = opts;

    if (!sandbox) {
      throw new Error('StdioCodeModeTransport requires a sandbox');
    }
    if (!sandbox.processes) {
      throw new SandboxFeatureNotSupportedError('processes');
    }

    const externals = toolIds.map(toolId => ({ toolId, externalName: sanitizeToolId(toolId) }));
    const allowList = new Set(toolIds);

    const dir = await mkdtemp(join(tmpdir(), 'mastra-code-mode-'));
    const suffix = randomBytes(4).toString('hex');
    // The model's TypeScript program is written to its own .ts module; node
    // strips the type annotations when the runner imports it (see the
    // --experimental-strip-types flag on the spawn below).
    const programPath = join(dir, `program-${suffix}.ts`);
    await writeFile(programPath, buildProgramModule(program), 'utf8');
    const runnerSource = buildRunner({ programModule: pathToFileURL(programPath).href, externals });
    const runnerPath = join(dir, `runner-${suffix}.mjs`);
    await writeFile(runnerPath, runnerSource, 'utf8');

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Pass a sandbox in the run options, e.g. resolve it via workspace.resolveSandbox({ requestContext }) or use new LocalSandbox().
  2. If using createCodeMode, provide sandbox: new LocalSandbox() or run within a sandbox-providing workspace (see error 1821).
  3. Assert sandbox presence at the call site before invoking the transport.

Example fix

// before
await transport.run({ program, toolIds, dispatch, timeout });
// after
await transport.run({ sandbox: new LocalSandbox(), program, toolIds, dispatch, timeout });
Defensive patterns

Strategy: validation

Validate before calling

if (!opts.sandbox) throw new Error('StdioCodeModeTransport.run requires opts.sandbox');
await transport.run({ ...opts, sandbox: opts.sandbox ?? new LocalSandbox() });

Type guard

function hasSandbox(o: { sandbox?: unknown }): o is { sandbox: NonNullable<unknown> } {
  return o.sandbox != null;
}

Try / catch

try {
  await transport.run(opts);
} catch (e) {
  if (String(e.message).includes('requires a sandbox')) {
    await transport.run({ ...opts, sandbox: new LocalSandbox() });
  } else throw e;
}

Prevention

When it happens

Trigger: Invoking StdioCodeModeTransport.run (directly or through createCodeMode) with opts where sandbox is undefined, e.g. building a custom transport pipeline and forgetting to pass the sandbox resolved from a workspace.

Common situations: Custom Code Mode wiring that bypasses createCodeMode's sandbox resolution; conditionally-constructed option objects where sandbox is dropped; refactors that moved sandbox resolution out of the call site.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/a3474136cef7c371. Report an issue: GitHub.