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

  1. 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 '..'.
  2. Use paths copied verbatim from the `files` inventory array instead of computing them elsewhere.
  3. 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

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.