langchain-ai/langchain · error · ValueError

Node with id {id} already exists

Error message

Node with id {id} already exists

What it means

`Graph.add_node` in `langchain_core.runnables.graph` rejects adding a node whose explicit `id` collides with an id already present in `self.nodes`, raising `ValueError`. Ids must be unique within a graph because edges reference nodes by id.

Source

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

        *,
        metadata: dict[str, Any] | None = None,
    ) -> Node:
        """Add a node to the graph and return it.

        Args:
            data: The data of the node.
            id: The id of the node.
            metadata: Optional metadata for the node.

        Returns:
            The node that was added to the graph.

        Raises:
            ValueError: If a node with the same id already exists.
        """
        if id is not None and id in self.nodes:
            msg = f"Node with id {id} already exists"
            raise ValueError(msg)
        id_ = id or self.next_id()
        node = Node(id=id_, data=data, metadata=metadata, name=node_data_str(id_, data))
        self.nodes[node.id] = node
        return node

    def remove_node(self, node: Node) -> None:
        """Remove a node from the graph and all edges connected to it.

        Args:
            node: The node to remove.
        """
        self.nodes.pop(node.id)
        self.edges = [
            edge for edge in self.edges if node.id not in {edge.source, edge.target}
        ]

    def add_edge(
        self,

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Omit the `id` argument and let `graph.next_id()` assign a fresh id.
  2. Namespace explicit ids uniquely (e.g. `f"{prefix}_{i}"`) when adding nodes in loops or after `extend()`.
  3. Before adding, check `if node_id in graph.nodes:` and either reuse the existing node or pick a new id.

Example fix

# before
for step in steps:
    graph.add_node(data=step, id=0)  # same id each loop

# after
for step in steps:
    graph.add_node(data=step)  # auto id via next_id()
Defensive patterns

Strategy: validation

Validate before calling

if node_id in graph.nodes:
    node = graph.nodes[node_id]  # reuse
else:
    node = graph.add_node(data=data, id=node_id)

Try / catch

try:
    node = graph.add_node(data=data, id=nid)
except ValueError as e:
    if "already exists" in str(e):
        node = graph.nodes[nid]
    else:
        raise

Prevention

When it happens

Trigger: Calling `graph.add_node(data=..., id=0)` twice with the same id; programmatically generated graphs reusing loop indices as ids across iterations; merging subgraphs manually where prefixed ids were expected to differ but the prefix was empty (`Graph.extend` with `prefix=""`), then re-adding nodes.

Common situations: Custom visualization or introspection code that walks a runnable and builds a `Graph` by hand; copying example code that adds start/end nodes with fixed ids inside a loop; calling `.add_node()` on nodes already inserted via `extend()` using overlapping numeric ids (since auto-generated `next_id()` counts up, explicit low ids easily collide).

Related errors


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