langchain-ai/langchain · error · ValueError

Target node {target.id} not in graph

Error message

Target node {target.id} not in graph

What it means

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.

Source

Thrown at libs/core/langchain_core/runnables/graph.py:379

        Args:
            source: The source node of the edge.
            target: The target node of the edge.
            data: Optional data associated with the edge.
            conditional: Whether the edge is conditional.

        Returns:
            The edge that was added to the graph.

        Raises:
            ValueError: If the source or target node is not in the graph.
        """
        if source.id not in self.nodes:
            msg = f"Source node {source.id} not in graph"
            raise ValueError(msg)
        if target.id not in self.nodes:
            msg = f"Target node {target.id} not in graph"
            raise ValueError(msg)
        edge = Edge(
            source=source.id, target=target.id, data=data, conditional=conditional
        )
        self.edges.append(edge)
        return edge

    def extend(
        self, graph: Graph, *, prefix: str = ""
    ) -> tuple[Node | None, Node | None]:
        """Add all nodes and edges from another graph.

        Note this doesn't check for duplicates, nor does it connect the graphs.

        Args:
            graph: The graph to add.
            prefix: The prefix to add to the node ids.

        Returns:

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Ensure the target node is added before the edge; add start/end sentinel nodes explicitly.
  2. After `remove_node`, also remove or rebuild edges that referenced it before adding new ones.
  3. Keep id types consistent (all ints or all strings), especially after (de)serializing graphs.

Example fix

# before
end = Node(id="end", data=END)
graph.add_edge(start, end)  # end never added

# after
end = graph.add_node(data=END)
graph.add_edge(start, end)
Defensive patterns

Strategy: validation

Validate before calling

assert target.id in graph.nodes, f"target {target.id} missing"
graph.add_edge(source, target)

Prevention

When it happens

Trigger: `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`).

Common situations: 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.

Related errors


AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14). Data as JSON: /api/errors/3b8674e83d75c016. Report an issue: GitHub.