langchain-ai/langchain · error · ValueError
Runnable {dep} has no last node
Error message
Runnable {dep} has no last node What it means
Companion check in `RunnableEachBase.get_graph()`: after extending a dependency's trimmed sub-graph, a last node must exist so an edge can connect to the output schema node. If the dependency graph has a first node but no last node, a `ValueError` is raised. This points to a dependency whose `get_graph()` builds a graph with no terminal node.
Source
Thrown at libs/core/langchain_core/runnables/base.py:5109
from langchain_core.runnables.graph import Graph # noqa: PLC0415
graph = Graph()
input_node = graph.add_node(self.get_input_schema(config))
output_node = graph.add_node(self.get_output_schema(config))
for dep in deps:
dep_graph = dep.get_graph()
dep_graph.trim_first_node()
dep_graph.trim_last_node()
if not dep_graph:
graph.add_edge(input_node, output_node)
else:
dep_first_node, dep_last_node = graph.extend(dep_graph)
if not dep_first_node:
msg = f"Runnable {dep} has no first node"
raise ValueError(msg)
if not dep_last_node:
msg = f"Runnable {dep} has no last node"
raise ValueError(msg)
graph.add_edge(input_node, dep_first_node)
graph.add_edge(dep_last_node, output_node)
else:
graph = super().get_graph(config)
return graph
@override
def __eq__(self, other: object) -> bool:
if isinstance(other, RunnableLambda):
if hasattr(self, "func") and hasattr(other, "func"):
return self.func == other.func
if hasattr(self, "afunc") and hasattr(other, "afunc"):
return self.afunc == other.afunc
return False
return False
__hash__ = None # type: ignore[assignment]View on GitHub (pinned to e32fa9a52e)
Solutions
- Simplify the custom `get_graph` to a single node: `g = Graph(); g.add_node('dep', self); return g`.
- Ensure the graph ends with a node that has no outgoing edges (a definite terminal).
- Test the dependency graph directly: `g = dep.get_graph(); g.trim_first_node(); g.trim_last_node(); assert g.last_node() is not None`.
- Wrap the dependency in `RunnableLambda` to get a known-good graph.
Example fix
// before
class Dep(Runnable):
def get_graph(self, config=None):
g = Graph()
g.add_edge(g.add_node('a', self), g.add_node('b', self))
return g # may lack a resolvable last node after trims
// after
class Dep(Runnable):
def get_graph(self, config=None):
g = Graph()
g.add_node('Dep', self)
return g Defensive patterns
Strategy: validation
Validate before calling
def dep_has_terminal(dep) -> bool:
g = dep.get_graph()
g.trim_first_node()
return g.last_node() is not None or not g.nodes Try / catch
try:
g = mapped.get_graph()
except ValueError as e:
if 'has no last node' in str(e):
# simplify the dep's graph to a single node
raise
raise Prevention
- Build custom graphs ending in a definite terminal node.
- Prefer one-node graphs for leaf runnables.
- Assert graph.last_node() in custom get_graph tests.
When it happens
Trigger: A dependency of a `.map()`ed runnable whose hand-built `Graph` never establishes a terminal node (e.g. only edges added, or nodes added in an order the graph cannot resolve), then calling `.get_graph()` on the `RunnableEach`.
Common situations: Custom runnables constructing `Graph` objects manually with `add_edge` before `add_node`; partial `get_graph` overrides copied from old examples; graph visualization tooling in notebooks.
Related errors
- Runnable {dep} has no first node
- Runnable {step} has no first node
- Runnable {step} has no last node
- RunnableEach does not support astream_events yet.
- RunnableSequence must have at least {_RUNNABLE_SEQUENCE_MIN_
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/5367ad2fc10ebb03.
Report an issue: GitHub.