yamadashy/repomix · error · PathScopeError
Path "${input}" resolves outside workspace root.
Error message
Path "${input}" resolves outside workspace root. What it means
After lexical checks pass, resolveWithinRoot resolves the candidate with path.resolve and verifies it remains inside the workspace root via isInside. If a relative-but-tricky input (symlinks in the middle, weird separators, overlapping names like 'root-evil') resolves outside root, this PathScopeError is thrown.
Source
Thrown at src/mcp/pathScope.ts:73
): Promise<string> => {
const rootResolved = path.resolve(root);
if (input === '' || input === '.') {
return rootResolved;
}
// Reject anything that escapes the workspace root — absolute/drive/UNC, a "~"
// home ref, or any ".." segment. A redundant leading "./" or ".\" is allowed.
if (isEscapingPath(input)) {
throw new PathScopeError(
`Path "${input}" must be relative to workspace root — no "/", "~/", "../", drive, or ".." segment. Use e.g. "src/index.ts" or "." for whole workspace.`,
);
}
const candidate = path.resolve(rootResolved, input);
if (!isInside(rootResolved, candidate)) {
throw new PathScopeError(`Path "${input}" resolves outside workspace root.`);
}
// Resolve symlinks to catch a link inside root that points back out. If a path
// can't be resolved via realpath (e.g. the target does not exist yet, or the
// root itself can't be stat'd), fall back to the lexical path — it is already
// confined lexically above.
let realRoot: string;
try {
realRoot = (await deps.realpath(rootResolved)) as string;
} catch {
realRoot = rootResolved;
}
let realCandidate: string;
try {
realCandidate = (await deps.realpath(candidate)) as string;
} catch {
return candidate;
}View on GitHub (pinned to f465ad9093)
Solutions
- Use a plain relative path under the workspace root
- Remove or relocate symlinks inside the workspace that point outside it
- Verify with path.resolve yourself which absolute path results and adjust the input
- If this blocks a legitimate layout, restructure so the target lives inside the root
Example fix
// before (intermediate symlink out of root) resolveWithinRoot(root, 'vendor/link/../secret.txt') // after resolveWithinRoot(root, 'src/actual-file.ts')
Defensive patterns
Strategy: validation
Validate before calling
import path from 'node:path';
const candidate = path.resolve(root, input);
if (candidate !== root && !candidate.startsWith(root + path.sep)) {
throw new Error(`path escapes workspace root: ${input}`);
} Try / catch
try {
const abs = await resolveWithinRoot(root, input);
} catch (err) {
if (err instanceof PathScopeError && err.message.includes('resolves outside')) {
console.error(`${input} normalizes outside the root; inspect intermediate symlinks.`);
} else throw err;
} Prevention
- Avoid symlinked intermediate directories inside the workspace pointing outside
- Lexically pre-check resolved paths against root before calls
- Watch out for sibling directories whose names share root's prefix
- Run `find . -type l` periodically to audit workspace symlinks
When it happens
Trigger: Input passes isEscapingPath but path.resolve(root, input) lands outside root — e.g. after normalization of unusual segments — or an intermediate symlink points out of the root.
Common situations: Agents submitting crafted relative paths; directories whose names share a prefix with root; intermediate symlinked dirs inside the workspace pointing elsewhere on disk.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- Path "${input}" must be relative to workspace root — no "/",
- In remote mode, --config must be an absolute path to avoid l
- Refusing to trust ${configName}: the remote repository's con
- Refusing to trust ${configName}: it resolves outside the clo
- Remote config not trusted
AI-assisted analysis of yamadashy/repomix@f465ad9093 (2026-08-29).
Data as JSON: /api/errors/74b76e8d5e8eda11.
Report an issue: GitHub.