{"record":{"id":"3b8674e83d75c016","repo":"langchain-ai/langchain","slug":"target-node-target-id-not-in-graph","errorCode":null,"errorMessage":"Target node {target.id} not in graph","messagePattern":"Target node (.+?) not in graph","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/runnables/graph.py","lineNumber":379,"sourceCode":"\n        Args:\n            source: The source node of the edge.\n            target: The target node of the edge.\n            data: Optional data associated with the edge.\n            conditional: Whether the edge is conditional.\n\n        Returns:\n            The edge that was added to the graph.\n\n        Raises:\n            ValueError: If the source or target node is not in the graph.\n        \"\"\"\n        if source.id not in self.nodes:\n            msg = f\"Source node {source.id} not in graph\"\n            raise ValueError(msg)\n        if target.id not in self.nodes:\n            msg = f\"Target node {target.id} not in graph\"\n            raise ValueError(msg)\n        edge = Edge(\n            source=source.id, target=target.id, data=data, conditional=conditional\n        )\n        self.edges.append(edge)\n        return edge\n\n    def extend(\n        self, graph: Graph, *, prefix: str = \"\"\n    ) -> tuple[Node | None, Node | None]:\n        \"\"\"Add all nodes and edges from another graph.\n\n        Note this doesn't check for duplicates, nor does it connect the graphs.\n\n        Args:\n            graph: The graph to add.\n            prefix: The prefix to add to the node ids.\n\n        Returns:","sourceCodeStart":361,"sourceCodeEnd":397,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/runnables/graph.py#L361-L397","documentation":"The counterpart of the source check: `Graph.add_edge` verifies the target node's id exists in `self.nodes` after checking the source. A missing target id raises `ValueError: Target node ... not in graph`, keeping the edge list consistent with the node table.","triggerScenarios":"`add_edge(a, b)` where `b` was never added, was removed by `remove_node()`, or is a new `Node` instance whose id was expected to match an existing node but does not (e.g. string vs int id `\"1\"` vs `1`).","commonSituations":"Building custom `.get_graph()` implementations that forget the end/exit node; deleting nodes with `remove_node` (which pops the node but leaves dangling edges to fix) and then re-adding edges; id-type mismatches after loading graph descriptions from JSON where keys became strings.","solutions":["Ensure the target node is added before the edge; add start/end sentinel nodes explicitly.","After `remove_node`, also remove or rebuild edges that referenced it before adding new ones.","Keep id types consistent (all ints or all strings), especially after (de)serializing graphs."],"exampleFix":"# before\nend = Node(id=\"end\", data=END)\ngraph.add_edge(start, end)  # end never added\n\n# after\nend = graph.add_node(data=END)\ngraph.add_edge(start, end)","handlingStrategy":"validation","validationCode":"assert target.id in graph.nodes, f\"target {target.id} missing\"\ngraph.add_edge(source, target)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Add end/exit sentinel nodes explicitly in custom get_graph().","Keep node id types consistent (str vs int) across the graph.","Rebuild edges referencing removed nodes after remove_node()."],"tags":["graph","value-error","visualization","langchain-core"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}