{"record":{"id":"739ea4873a0a0625","repo":"mastra-ai/mastra","slug":"both-source-and-target-nodes-must-exist","errorCode":null,"errorMessage":"Both source and target nodes must exist","messagePattern":"Both source and target nodes must exist","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/rag/src/graph-rag/index.ts","lineNumber":80,"sourceCode":"    this.dimension = dimension;\n    this.threshold = threshold;\n  }\n\n  // Add a node to the graph\n  addNode(node: GraphNode): void {\n    if (!node.embedding) {\n      throw new Error('Node must have an embedding');\n    }\n    if (node.embedding.length !== this.dimension) {\n      throw new Error(`Embedding dimension must be ${this.dimension}`);\n    }\n    this.nodes.set(node.id, node);\n  }\n\n  // Add an edge between two nodes\n  addEdge(edge: GraphEdge): void {\n    if (!this.nodes.has(edge.source) || !this.nodes.has(edge.target)) {\n      throw new Error('Both source and target nodes must exist');\n    }\n    this.edges.push(edge);\n    // Add reverse edge\n    this.edges.push({\n      source: edge.target,\n      target: edge.source,\n      weight: edge.weight,\n      type: edge.type,\n    });\n  }\n\n  // Helper method to get all nodes\n  getNodes(): GraphNode[] {\n    return Array.from(this.nodes.values());\n  }\n\n  // Helper method to get all edges\n  getEdges(): GraphEdge[] {","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/rag/src/graph-rag/index.ts#L62-L98","documentation":"addEdge requires that both endpoints of an edge already exist as nodes in the graph, because edges are validated against node IDs and a reverse edge is also inserted. If either edge.source or edge.target is not a registered node ID, the edge is rejected. This keeps the graph internally consistent.","triggerScenarios":"Calling addEdge({ source: 'a', target: 'b' }) before addNode was called for 'a' or 'b'; building edges from a separate metadata file whose IDs don't match node IDs; createGraph receiving an edges array referencing pruned/filtered nodes.","commonSituations":"Generating edges from LLM output referencing entity names instead of node IDs; deduplication/filtering that removed nodes after edges were computed; id mismatches like 'doc-1' vs '1' between the node builder and edge builder.","solutions":["Add all nodes with addNode before adding any edges, or ensure createGraph receives complete nodes and matching edges.","Make edge source/target use the exact node.id values (same string, same casing).","Filter edges whose endpoints are missing instead of adding them.","If edges are LLM-generated, map entity names to actual node IDs before calling addEdge."],"exampleFix":"// before\ngraph.addEdge({ source: 'doc1', target: 'doc2' }); // nodes not added yet\n// after\ngraph.addNode({ id: 'doc1', content, embedding: e1 });\ngraph.addNode({ id: 'doc2', content, embedding: e2 });\ngraph.addEdge({ source: 'doc1', target: 'doc2', weight: 0.8 });","handlingStrategy":"validation","validationCode":"const ids = new Set(nodes.map(n => n.id));\nconst dangling = edges.filter(e => !ids.has(e.source) || !ids.has(e.target));\nif (dangling.length) throw new Error(`Edges reference missing nodes: ${dangling.map(e => `${e.source}->${e.target}`).join(', ')}`);","typeGuard":null,"tryCatchPattern":"try {\n  graph.addEdge(edge);\n} catch (e) {\n  if ((e as Error).message === 'Both source and target nodes must exist') {\n    console.warn(`Skipping edge ${edge.source}->${edge.target}: endpoint node missing`);\n    return;\n  }\n  throw e;\n}","preventionTips":["Add all nodes before any edges; build edges only from the final node set.","Use node.id verbatim as edge source/target — never entity labels or display names.","Filter edges after any node pruning/dedup step.","Validate edge endpoints with a Set lookup before addEdge or createGraph."],"tags":["rag","graph-rag","validation","graph-structure"],"backgroundTag":"dangling-graph-edge","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}