mastra-ai/mastra · error

Refusing to use local sandbox path outside configured root:

Error message

Refusing to use local sandbox path outside configured root: ${resolved}

What it means

resolveContainedLocalWorkdir() builds a local sandbox workdir by resolving segments under a configured root and rejects any result that escapes that root (a path-traversal guard). The throw means the requested segments resolved outside the configured sandbox root, so the library refuses to expose that path. resolved !== resolvedRoot and the startsWith check together allow only the root itself or strict subdirectories.

Source

Thrown at mastracode/factory/src/sandbox/workdir.ts:52

  if (sandbox.provider === 'local' && typeof wd === 'string' && wd.length > 0) {
    const [, name] = repoFullName.split('/', 2);
    return resolveContainedLocalWorkdir(wd, sanitizeSegment(name || 'repo'));
  }
  return undefined;
}

/** `<home>/<repo>` — where a remote VM's default-cwd clone lands. */
export function remoteWorkdirFromHome(home: string, repoFullName: string): string {
  const [, name] = repoFullName.split('/', 2);
  return `${home.replace(/\/+$/, '')}/${sanitizeSegment(name || 'repo')}`;
}

/** Resolve a workdir under `root`, refusing any path that escapes the configured root. */
export function resolveContainedLocalWorkdir(root: string, ...segments: string[]): string {
  const resolvedRoot = path.resolve(root);
  const resolved = path.resolve(resolvedRoot, ...segments);
  if (resolved !== resolvedRoot && resolved.startsWith(`${resolvedRoot}${path.sep}`)) return resolved;
  throw new Error(`Refusing to use local sandbox path outside configured root: ${resolved}`);
}

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Sanitize the input segments (strip/normalize '..', validate repo name characters) before calling resolveContainedLocalWorkdir.
  2. Set the sandbox root configuration to the actual parent of the workspace you expect so the resolved path stays inside it.
  3. Normalize with path.resolve(path.normalize(...)) and check containment yourself to debug which segment escapes.
  4. If you truly need a path outside the root, move/copy the workspace inside the configured root rather than bypassing the guard.

Example fix

// before
deriveLocalWorkdir(root, '../../etc/passwd'); // escapes root -> throws

// after
const safeName = repoFullName.replace(/[^a-zA-Z0-9._-]/g, '-');
deriveLocalWorkdir(root, safeName); // stays under root
Defensive patterns

Strategy: validation

Validate before calling

import path from 'node:path';
function isInsideRoot(root: string, ...segments: string[]): boolean {
  const resolvedRoot = path.resolve(root);
  const resolved = path.resolve(resolvedRoot, ...segments);
  return resolved === resolvedRoot || resolved.startsWith(resolvedRoot + path.sep);
}
// call resolveContainedLocalWorkdir only if isInsideRoot(root, ...segments)

Type guard

function isContainedPath(root: string, candidate: string): boolean {
  const rel = path.relative(path.resolve(root), path.resolve(candidate));
  return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));
}

Try / catch

let workdir: string;
try {
  workdir = resolveContainedLocalWorkdir(root, repoFullName);
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Refusing to use local sandbox path')) {
    throw new Error(`Repo path '${repoFullName}' escapes sandbox root '${root}'; sanitize segments or fix root config`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling resolveContainedLocalWorkdir (directly or via deriveLocalWorkdir) with segments such as '../..' or a repoFullName containing traversal so that path.resolve lands outside the configured root; on Windows, segments that change drive or case-mismatched roots.

Common situations: Repo names with '..' or unusual characters passed as path segments; a configured root that differs in casing/separator from what segments assume (Windows drive letters, UNC paths); symlinked root directory making resolved paths differ; users configuring a workspace outside the sandbox root.

Related errors


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