Egonex-AI/Understand-Anything · error
Invalid input: analysisPaths entry escapes projectRoot: ${ra
Error message
Invalid input: analysisPaths entry escapes projectRoot: ${rawPath} What it means
After confirming an analysisPaths entry is relative, selectAnalysisFiles() normalizes it to POSIX separators and rejects it if it is empty after normalization or contains any '..' segment. This blocks path entries that would climb out of projectRoot (e.g. "../secrets.json" or "src/../../etc/passwd"), keeping the extractor from reading files outside the analyzed project.
Source
Thrown at understand-anything-plugin/skills/understand/extract-import-map.mjs:139
}
filesByPath.set(toPosix(file.path), file);
}
const selected = [];
const seen = new Set();
for (const rawPath of analysisPaths) {
if (typeof rawPath !== 'string' || rawPath.length === 0) {
throw new Error('Invalid input: every analysisPaths entry must be a non-empty string');
}
// Use the host's path semantics here. On POSIX, backslashes and drive-like
// prefixes are ordinary project-relative filename characters; on Windows,
// path.isAbsolute also rejects drive-rooted and root-relative paths.
if (isAbsolute(rawPath)) {
throw new Error(`Invalid input: analysisPaths entry must be project-relative: ${rawPath}`);
}
const path = toPosix(rawPath);
if (!path || path.split('/').some(part => part === '..')) {
throw new Error(`Invalid input: analysisPaths entry escapes projectRoot: ${rawPath}`);
}
const file = filesByPath.get(path);
if (!file) {
throw new Error(`Invalid input: analysisPaths entry is not present in files: ${rawPath}`);
}
if (!seen.has(path)) {
seen.add(path);
selected.push(file);
}
}
return selected;
}
// ECMAScript relational string comparison is lexicographic over UTF-16 code
// units, so path ordering is stable across ICU versions, locales, and hosts.
function comparePaths(a, b) {
if (a === b) return 0;
return a < b ? -1 : 1;View on GitHub (pinned to 07edf82a04)
Solutions
- Rewrite each entry so it stays inside projectRoot with no '..' segments; resolve against the correct root first, then take path.relative(projectRoot, resolved) and verify it does not start with '..'.
- Use paths copied verbatim from the `files` inventory array instead of computing them elsewhere.
- Reject or skip out-of-root files in the calling tool before generating the input JSON.
Example fix
// before
analysisPaths: ["../shared/lib.ts"]
// after
const rel = path.relative(projectRoot, path.resolve(projectRoot, userPath));
if (rel.startsWith('..')) throw new Error(`${userPath} is outside projectRoot`);
analysisPaths: [rel.split(path.sep).join('/')] Defensive patterns
Strategy: validation
Validate before calling
function staysInRoot(p, projectRoot) {
const rel = relative(projectRoot, resolve(projectRoot, p));
return rel !== '' && !rel.startsWith('..') && !resolve(projectRoot, p).startsWith(projectRoot + '..');
}
const safePaths = analysisPaths.filter(p => staysInRoot(p, projectRoot)); Type guard
const isInsideProject = (p, root) => { const rel = relative(root, resolve(root, p)); return rel !== '' && !rel.startsWith('..') && !isAbsolute(rel); }; Try / catch
try {
await runExtractor(input);
} catch (err) {
if (String(err.message).includes('analysisPaths entry escapes projectRoot')) {
input.analysisPaths = input.analysisPaths.filter(p => isInsideProject(p, projectRoot));
await runExtractor(input);
} else throw err;
} Prevention
- Resolve user-supplied paths against projectRoot and recompute relative(projectRoot, resolved) before use.
- Drop '..'-containing entries at the tool boundary; log and skip instead of forwarding them.
- Never concatenate root + user path; use path.resolve/path.relative.
When it happens
Trigger: Passing an analysisPaths entry like "../other-package/src/index.ts", "a/../b/../../x.ts", or a path that normalizes to empty ("./", "."). Also triggered on POSIX by entries mixing separators in ways that produce '..' segments after split.
Common situations: An incremental caller computes changed files relative to the wrong root (repo root vs project root), producing '..' segments; a template or config interpolates a path like "${root}/${rel}" where rel already contains ".."; hand-written input JSON with "./src" style entries that normalize to empty.
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
AI-assisted analysis of Egonex-AI/Understand-Anything@07edf82a04 (2026-09-07).
Data as JSON: /api/errors/4a9da8aeb61439ea.
Report an issue: GitHub.