langchain-ai/langchain · error · ValueError

Runnable {step} has no first node

Error message

Runnable {step} has no first node

What it means

While building the compute graph for a `RunnableSequence`, each step's own graph has its boundary nodes trimmed (first node trimmed for non-first steps, last node trimmed for non-last steps) and is then spliced in with `graph.extend`. If a step's trimmed graph yields no first node, the sequence cannot be stitched together and a `ValueError` is raised. This almost always means a custom `Runnable` subclass returns an empty or malformed graph from `get_graph()`.

Source

Thrown at libs/core/langchain_core/runnables/base.py:3307

        Raises:
            ValueError: If a `Runnable` has no first or last node.

        """
        # Import locally to prevent circular import
        from langchain_core.runnables.graph import Graph  # noqa: PLC0415

        graph = Graph()
        for step in self.steps:
            current_last_node = graph.last_node()
            step_graph = step.get_graph(config)
            if step is not self.first:
                step_graph.trim_first_node()
            if step is not self.last:
                step_graph.trim_last_node()
            step_first_node, _ = graph.extend(step_graph)
            if not step_first_node:
                msg = f"Runnable {step} has no first node"
                raise ValueError(msg)
            if current_last_node:
                graph.add_edge(current_last_node, step_first_node)

        return graph

    @override
    def __repr__(self) -> str:
        return "\n| ".join(
            repr(s) if i == 0 else indent_lines_after_first(repr(s), "| ")
            for i, s in enumerate(self.steps)
        )

    @overload
    def __or__(
        self, other: Mapping[str, Any]
    ) -> RunnableSerializable[Input, dict[str, Any]]: ...

    @overload

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Override `get_graph()` in your custom `Runnable` to return a graph with at least a real node: `graph = Graph(); graph.add_node('my_runnable', self); return graph`.
  2. Check `len(my_runnable.get_graph().nodes) > 0` before adding it to a sequence.
  3. Wrap the offending runnable in a `RunnableLambda` (`RunnableLambda(fn)`), whose graph implementation is well-formed.
  4. If the runnable is trivially single-node, ensure `trim_first_node()`/`trim_last_node()` leave at least the boundary node the sequence needs.

Example fix

// before
class MyRunnable(Runnable):
    def invoke(self, x, config=None):
        return x
    # get_graph not overridden -> may extend to no first node

// after
class MyRunnable(Runnable):
    def invoke(self, x, config=None):
        return x
    def get_graph(self, config=None):
        graph = Graph()
        graph.add_node('MyRunnable', self)
        return graph
Defensive patterns

Strategy: validation

Validate before calling

from langchain_core.runnables import Runnable

def graph_is_stitchable(step: Runnable) -> bool:
    g = step.get_graph()
    g.trim_first_node()
    g.trim_last_node()
    return bool(g.nodes)

Try / catch

try:
    graph = sequence.get_graph()
except ValueError as e:
    if 'has no first node' in str(e):
        # identify and fix/replace the offending step
        raise
    raise

Prevention

When it happens

Trigger: Embedding a custom `Runnable` whose `get_graph()` returns a `Graph` with no nodes (or only a last node) inside a `RunnableSequence`, then calling `sequence.get_graph()`, `.get_repr()`, or rendering with `LangChain`/`langgraph` visualization tools that call `get_graph().draw_ascii()`/`.print_ascii()`.

Common situations: Writing a lightweight custom `Runnable` and not overriding (or incorrectly overriding) `get_graph()`; a custom runnable whose graph gets fully consumed by `trim_first_node()` because it has a single node; visualizing pipelines containing third-party runnables with broken graph support.

Related errors


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