{"record":{"id":"6e8f7dbb2f14048c","repo":"Egonex-AI/Understand-Anything","slug":"invalid-assembled-graph","errorCode":null,"errorMessage":"Invalid assembled graph","messagePattern":"Invalid assembled graph","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"understand-anything-plugin/skills/understand/validate-incremental-symbols.mjs","lineNumber":325,"sourceCode":"  // Git compares normalized contents, including repository clean/EOL rules.\n  if (paths.length) git(projectRoot, [\n    'diff', '--quiet', '--no-ext-diff', plan.headCommit, '--', ...paths.map(path => `:(literal)${path}`),\n  ]);\n  return { plan, baseline };\n}\n\nexport async function validateIncrementalSymbols(projectRoot, { graph, intermediateDir } = {}) {\n  const core = await getCore();\n  intermediateDir ??= join(core.resolveUaDir(projectRoot), 'intermediate');\n  const reportPath = join(intermediateDir, 'incremental-symbol-report.json');\n  const report = { version: 1, ok: false, files: [], unresolvedFiles: [], errors: [] };\n  const graphFromDisk = graph === undefined;\n  try {\n    const { plan, baseline } = loadSymbolContext(projectRoot, intermediateDir);\n    report.baseCommit = plan.baseCommit;\n    report.headCommit = plan.headCommit;\n    graph ??= readJson(join(intermediateDir, 'assembled-graph.json'));\n    if (!Array.isArray(graph.nodes) || !Array.isArray(graph.edges)) throw new Error('Invalid assembled graph');\n    report.graphHash = createHash('sha256').update(JSON.stringify(graph)).digest('hex');\n    let parser;\n    const evidenceByPath = new Map();\n    const parseHead = async path => {\n      if (evidenceByPath.get(path)?.head) return evidenceByPath.get(path).head;\n      if (!parser) {\n        parser = new core.TreeSitterPlugin(core.builtinLanguageConfigs.filter(config => config.treeSitter));\n        await parser.init();\n      }\n      // :./ keeps git-show relative to projectRoot, including monorepo subdirectories.\n      const headContent = git(projectRoot, ['show', `${plan.headCommit}:./${path}`]);\n      const evidence = { head: parser.analyzeFileStrict(path, headContent) };\n      evidenceByPath.set(path, evidence);\n      return evidence.head;\n    };\n    const parseRevisions = async path => {\n      await parseHead(path);\n      const evidence = evidenceByPath.get(path);","sourceCodeStart":307,"sourceCodeEnd":343,"githubUrl":"https://github.com/Egonex-AI/Understand-Anything/blob/07edf82a04371b6f69779b067bdc8a1a8753a9db/understand-anything-plugin/skills/understand/validate-incremental-symbols.mjs#L307-L343","documentation":"`validateIncrementalSymbols` loads `assembled-graph.json` (unless a graph was passed in) and requires both `graph.nodes` and `graph.edges` to be arrays before hashing and validating it. If either is missing or not an array, the graph is structurally unusable and it throws 'Invalid assembled graph'.","triggerScenarios":"Calling `validateIncrementalSymbols` when `assembled-graph.json` in the intermediate directory is absent-but-replaced by malformed JSON output, truncated, or written without `nodes`/`edges` array fields — or when a caller passes a `graph` argument lacking those arrays.","commonSituations":"The graph-assembly agent crashed mid-write leaving a partial file; disk-full truncated the JSON; an older schema stored nodes under a different key; a caller passed a hand-built object like `{}` instead of a full graph.","solutions":["Regenerate `assembled-graph.json` by re-running the graph assembly step.","Validate the JSON shape: it must contain `nodes: []` and `edges: []` (`jq '.nodes|type, .edges|type' assembled-graph.json`).","If passing a graph programmatically, ensure it includes array-valued `nodes` and `edges`.","Check disk space / write errors if the file appears truncated, and re-run assembly after cleanup."],"exampleFix":"// before: passing a bare object\nawait validateIncrementalSymbols({ projectRoot, intermediateDir, graph: {} });\n\n// after: pass a complete graph or let it load from disk\nconst graph = JSON.parse(readFileSync(join(intermediateDir, 'assembled-graph.json'), 'utf8'));\nif (!Array.isArray(graph.nodes) || !Array.isArray(graph.edges)) throw new Error('bad graph');\nawait validateIncrementalSymbols({ projectRoot, intermediateDir, graph });","handlingStrategy":"type-guard","validationCode":"const graph = JSON.parse(readFileSync(join(intermediateDir,'assembled-graph.json'),'utf8'));\nif (!Array.isArray(graph.nodes) || !Array.isArray(graph.edges)) {\n  await rerunGraphAssembly();\n}","typeGuard":"function isValidGraph(g) {\n  return g != null && typeof g === 'object'\n    && Array.isArray(g.nodes) && Array.isArray(g.edges);\n}","tryCatchPattern":"try {\n  await validateIncrementalSymbols({ projectRoot, intermediateDir });\n} catch (err) {\n  if (err.message === 'Invalid assembled graph') {\n    await rerunGraphAssembly(); // rebuild assembled-graph.json\n  } else throw err;\n}","preventionTips":["Write assembled-graph.json atomically (temp file + rename) so crashes never leave partial output.","Validate graph JSON shape right after assembly.","Check disk space before large graph writes.","When passing a graph programmatically, run a shape guard first."],"tags":["graph","schema-validation","incremental-analysis"],"backgroundTag":"schema-validation-failed","analyzedSha":"07edf82a04371b6f69779b067bdc8a1a8753a9db","analyzedAt":"2026-09-07T23:20:10.829Z","contentChangedAt":"2026-09-07T23:20:10.829Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}