yamadashy/repomix · error · PathScopeError
Path "${input}" must be relative to workspace root — no "/",
Error message
Path "${input}" must be relative to workspace root — no "/", "~/", "../", drive, or ".." segment. Use e.g. "src/index.ts" or "." for whole workspace. What it means
MCP path scoping: resolveWithinRoot rejects any input path that lexically escapes the workspace root — absolute paths, drive/UNC paths, '~/...' home refs, or any '..' segment — throwing PathScopeError before any fs access. This is a security guard keeping MCP tool calls confined to the workspace.
Source
Thrown at src/mcp/pathScope.ts:65
* Rejected: absolute paths ("/x", "C:\x", "\x", UNC), "~" home refs, and any
* ".." traversal segment (either separator). Symlink escapes are caught via
* realpath. Returns the resolved absolute path (realpath when the target exists).
*/
export const resolveWithinRoot = async (
root: string,
input: string,
deps: { realpath: RealpathFn } = { realpath: (p) => fs.realpath(p) },
): 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 {View on GitHub (pinned to f465ad9093)
Solutions
- Pass workspace-root-relative paths, e.g. 'src/index.ts' or '.' for the whole workspace
- Strip any leading home or drive prefix from the path before calling
- Resolve the path against the workspace root yourself and re-submit the relative form
- If the target genuinely lives outside the root, launch/restart the MCP server with that directory as the root
Example fix
// before resolveWithinRoot(root, '/home/me/project/src/index.ts') // after resolveWithinRoot(root, 'src/index.ts')
Defensive patterns
Strategy: validation
Validate before calling
const isSafeRelative = (p: string) =>
p !== '' && !p.startsWith('/') && !p.startsWith('~') && !/^[a-zA-Z]:/.test(p) &&
!p.split(/[\\/]/).includes('..');
if (!isSafeRelative(input)) throw new Error('path must be relative to workspace root'); Try / catch
try {
const abs = await resolveWithinRoot(root, input);
} catch (err) {
if (err instanceof PathScopeError) {
console.error(`Rejected path ${input}; send a workspace-relative path like src/index.ts.`);
} else throw err;
} Prevention
- Have MCP clients normalize to root-relative paths before tool calls
- Never forward raw absolute paths from previous tool results
- Sanitize '~' and drive prefixes when bridging CLI and MCP usage
- Document in tool schemas that paths are workspace-relative
When it happens
Trigger: An MCP tool call passes an absolute path ('/etc/passwd'), a home-relative path ('~/notes.txt'), a Windows drive path ('C:\\x'), or a path containing '..' to resolveWithinRoot.
Common situations: LLM agents constructing absolute paths from previous tool output; clients on Windows sending drive-qualified paths; callers assuming the MCP server accepts OS-wide paths like the CLI does.
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}" resolves outside workspace root.
- 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/97accc894f3bfec9.
Report an issue: GitHub.