{"record":{"id":"67e86b6b1b3be0ab","repo":"Egonex-AI/Understand-Anything","slug":"invalid-input-analysispaths-entry-must-be-project","errorCode":null,"errorMessage":"Invalid input: analysisPaths entry must be project-relative: ${rawPath}","messagePattern":"Invalid input: analysisPaths entry must be project-relative: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"understand-anything-plugin/skills/understand/extract-import-map.mjs","lineNumber":135,"sourceCode":"  const filesByPath = new Map();\n  for (const file of files) {\n    if (!file || typeof file.path !== 'string' || file.path.length === 0) {\n      throw new Error('Invalid input: every files entry must contain a non-empty path');\n    }\n    filesByPath.set(toPosix(file.path), file);\n  }\n\n  const selected = [];\n  const seen = new Set();\n  for (const rawPath of analysisPaths) {\n    if (typeof rawPath !== 'string' || rawPath.length === 0) {\n      throw new Error('Invalid input: every analysisPaths entry must be a non-empty string');\n    }\n    // Use the host's path semantics here. On POSIX, backslashes and drive-like\n    // prefixes are ordinary project-relative filename characters; on Windows,\n    // path.isAbsolute also rejects drive-rooted and root-relative paths.\n    if (isAbsolute(rawPath)) {\n      throw new Error(`Invalid input: analysisPaths entry must be project-relative: ${rawPath}`);\n    }\n    const path = toPosix(rawPath);\n    if (!path || path.split('/').some(part => part === '..')) {\n      throw new Error(`Invalid input: analysisPaths entry escapes projectRoot: ${rawPath}`);\n    }\n    const file = filesByPath.get(path);\n    if (!file) {\n      throw new Error(`Invalid input: analysisPaths entry is not present in files: ${rawPath}`);\n    }\n    if (!seen.has(path)) {\n      seen.add(path);\n      selected.push(file);\n    }\n  }\n  return selected;\n}\n\n// ECMAScript relational string comparison is lexicographic over UTF-16 code","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/Egonex-AI/Understand-Anything/blob/07edf82a04371b6f69779b067bdc8a1a8753a9db/understand-anything-plugin/skills/understand/extract-import-map.mjs#L117-L153","documentation":"extract-import-map.mjs validates every entry of the optional `analysisPaths` input array through selectAnalysisFiles(). Each entry must be a project-relative path (e.g. \"src/index.ts\"), not an absolute one. The script throws this error when path.isAbsolute(rawPath) is true, because selective analysis is only defined over files already listed in the `files` inventory, which uses project-relative paths; absolute paths would bypass that contract and could point outside projectRoot.","triggerScenarios":"Calling the script with input JSON whose analysisPaths contains an absolute path such as \"/home/user/project/src/index.ts\" or \"C:\\\\proj\\\\src\\\\index.ts\" (on Windows, path.isAbsolute also rejects root-relative paths like \"/src/index.ts\" and drive-rooted ones like \"C:src\"). Any tool or agent that passes filesystem-absolute paths instead of the project-relative paths used in the `files` array triggers it.","commonSituations":"An incremental-run caller builds analysisPaths from its own CLI arguments or editor-absolute file paths instead of from scan-result inventory paths; a Windows developer passes drive-lettered paths; a script joins projectRoot into the entry before writing the input JSON (e.g. path.join(projectRoot, relPath)) making it absolute.","solutions":["Convert each analysisPaths entry to a project-relative path before writing the input JSON: path.relative(projectRoot, absPath) with forward slashes.","Reuse the exact `path` values from the `files` array of the same input (they are already project-relative and guaranteed to match).","On Windows, strip drive-letter/root prefixes or ensure entries like \"src/index.ts\" rather than \"/src/index.ts\" or \"C:\\\\src\\\\index.ts\"."],"exampleFix":"// before\nconst input = { projectRoot, files, analysisPaths: changedFiles.map(f => f.absolutePath) };\n// after\nconst input = { projectRoot, files, analysisPaths: changedFiles.map(f => path.relative(projectRoot, f.absolutePath).split(path.sep).join('/')) };","handlingStrategy":"validation","validationCode":"import { isAbsolute, relative, sep } from 'node:path';\nfunction assertProjectRelative(p, projectRoot) {\n  if (typeof p !== 'string' || p.length === 0) throw new Error('empty path');\n  if (isAbsolute(p)) throw new Error(`must be project-relative: ${p}`);\n  const rel = relative(projectRoot, p);\n  if (rel.startsWith('..')) throw new Error(`escapes projectRoot: ${p}`);\n}","typeGuard":"const isProjectRelative = (p) => typeof p === 'string' && p.length > 0 && !isAbsolute(p);","tryCatchPattern":"try {\n  await runExtractor(input);\n} catch (err) {\n  if (String(err.message).includes('analysisPaths entry must be project-relative')) {\n    input.analysisPaths = input.analysisPaths.map(p => relative(projectRoot, p).split(sep).join('/'));\n    await runExtractor(input);\n  } else throw err;\n}","preventionTips":["Always derive analysisPaths from the files inventory's `path` fields rather than from absolute filesystem paths.","Normalize with path.relative(projectRoot, ...) and forward slashes before writing the input JSON.","Unit-test input builders on both POSIX and Windows path shapes."],"tags":["invalid-argument","path-validation","cli-input"],"backgroundTag":"invalid-argument-value","analyzedSha":"07edf82a04371b6f69779b067bdc8a1a8753a9db","analyzedAt":"2026-09-07T23:20:10.829Z","contentChangedAt":"2026-09-07T23:20:10.829Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}