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
- Sanitize the input segments (strip/normalize '..', validate repo name characters) before calling resolveContainedLocalWorkdir.
- Set the sandbox root configuration to the actual parent of the workspace you expect so the resolved path stays inside it.
- Normalize with path.resolve(path.normalize(...)) and check containment yourself to debug which segment escapes.
- 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
- Sanitize repo/workspace names (strip '..', control chars) before path composition.
- Keep sandbox root configuration normalized with path.resolve and consistent separators.
- Add tests for traversal inputs ('..', absolute segments) against the workdir resolver.
- Verify symlink targets under the root also stay contained.
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
- Path escapes workspace root: ${inputPath}
- Path escapes workspace root (symlink): ${inputPath}
- Plugin entry must be inside the plugin directory
- Cookie password must be at least 32 characters for SSO. Set
- [MastraAuthGoogle] GOOGLE_COOKIE_PASSWORD is required for Go
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/1c14a2020a1ab87d.
Report an issue: GitHub.