{"record":{"id":"9db7a869f6be0c72","repo":"mastra-ai/mastra","slug":"edge-references-unknown-node-edge-target","errorCode":null,"errorMessage":"Edge references unknown node: ${edge.target}","messagePattern":"Edge references unknown node: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/rag/src/graph-rag/index.ts","lineNumber":157,"sourceCode":"\n    const graph = new GraphRAG(snapshot.dimension, snapshot.threshold);\n\n    for (const node of snapshot.nodes ?? []) {\n      // Route through addNode so embedding presence and dimension are validated\n      // at load time rather than failing later inside query().\n      graph.addNode({\n        ...node,\n        ...(node.embedding ? { embedding: [...node.embedding] } : {}),\n        ...(node.metadata ? { metadata: structuredClone(node.metadata) } : {}),\n      });\n    }\n\n    for (const edge of snapshot.edges ?? []) {\n      if (!graph.nodes.has(edge.source)) {\n        throw new Error(`Edge references unknown node: ${edge.source}`);\n      }\n      if (!graph.nodes.has(edge.target)) {\n        throw new Error(`Edge references unknown node: ${edge.target}`);\n      }\n    }\n\n    // Assign directly rather than via addEdge: the serialized edge list already\n    // contains both directions, and addEdge would add the reverse edge again.\n    graph.edges = (snapshot.edges ?? []).map(edge => ({ ...edge }));\n\n    return graph;\n  }\n\n  clear(): void {\n    this.nodes.clear();\n    this.edges = [];\n  }\n\n  updateNodeContent(id: string, newContent: string): void {\n    const node = this.nodes.get(id);\n    if (!node) {","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/rag/src/graph-rag/index.ts#L139-L175","documentation":"Same integrity check as the source-side one: deserialize() also verifies that edge.target exists among the restored nodes before assigning the edge list. A snapshot with an edge pointing at a nonexistent target is rejected because queries and random walks would traverse to missing nodes.","triggerScenarios":"GraphRAG.deserialize(snapshot) with an edge whose target id is absent from snapshot.nodes — typically from hand-edited/pruned snapshots, id remapping, or a snapshot merged from incompatible graphs.","commonSituations":"Deleting a node's entry in persisted JSON while keeping its edges; exporting edges but a subset of nodes; id scheme changes (e.g. numeric to hash ids) applied only to nodes.","solutions":["Filter or repair edges whose target is missing from snapshot.nodes before deserializing.","Regenerate the snapshot via serialize() from a consistent in-memory graph.","Apply id migrations to both nodes and edges together.","Run a referential-integrity check (Set of node ids) on snapshots before loading them."],"exampleFix":"// before\nconst graph = GraphRAG.deserialize(savedSnapshot);\n// after\nconst ids = new Set(savedSnapshot.nodes.map(n => n.id));\nfor (const e of savedSnapshot.edges) {\n  if (!ids.has(e.target)) throw new Error(`snapshot corrupt: edge target ${e.target} missing`);\n}\nconst graph = GraphRAG.deserialize(savedSnapshot);","handlingStrategy":"validation","validationCode":"const ids = new Set(snapshot.nodes.map(n => n.id));\nconst dangling = snapshot.edges.filter(e => !ids.has(e.target));\nif (dangling.length) throw new Error(`Edges with unknown target: ${dangling.map(e => e.target).join(',')}`);","typeGuard":"const edgesHaveKnownTargets = (s: GraphRAGSnapshot): boolean => {\n  const ids = new Set(s.nodes.map(n => n.id));\n  return s.edges.every(e => ids.has(e.target));\n};","tryCatchPattern":"try {\n  const graph = GraphRAG.deserialize(snapshot);\n} catch (e) {\n  if ((e as Error).message.startsWith('Edge references unknown node')) {\n    snapshot.edges = snapshot.edges.filter(e =>\n      snapshot.nodes.some(n => n.id === e.target));\n    // retry deserialize\n  } else throw e;\n}","preventionTips":["Apply id migrations to nodes and edges together","Filter both source and target when sanitizing edges","Prefer serialize()/deserialize() round-trips over manual JSON edits","Run an integrity check on load: every edge endpoint must exist in nodes"],"tags":["serialization","graph-integrity","rag","dangling-reference"],"backgroundTag":"dangling-reference","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}