langchain-ai/langchain · error · ValueError
Runnable {dep} has no first node
Error message
Runnable {dep} has no first node What it means
`RunnableEachBase.get_graph()` builds a graph by trimming each dependency runnable's sub-graph and extending it between input/output schema nodes. If a dependency's trimmed graph extends without producing a first node, a `ValueError` is raised — the fan-in/fan-out structure of `RunnableEach` cannot be drawn. Root cause is a dependency with an empty or malformed `get_graph()`.
Source
Thrown at libs/core/langchain_core/runnables/base.py:5106
def get_graph(self, config: RunnableConfig | None = None) -> Graph:
if deps := self.deps:
# Import locally to prevent circular import
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 FalseView on GitHub (pinned to e32fa9a52e)
Solutions
- Fix the dependency's `get_graph()` to return a graph containing at least one node.
- Wrap the mapped runnable's inner function in `RunnableLambda` before `.map()`.
- Check each dependency: `assert dep.get_graph().first_node() is not None`.
- Skip graph rendering for exotic runnables, or register a simple proxy node for them.
Example fix
// before batch = my_custom_runnable.map() # custom get_graph is empty batch.get_graph().draw_ascii() # ValueError // after batch = RunnableLambda(my_fn).map() batch.get_graph().draw_ascii() # ok
Defensive patterns
Strategy: validation
Validate before calling
def deps_stitchable(mapped) -> bool:
for dep in getattr(mapped, 'deps', []):
g = dep.get_graph()
g.trim_first_node()
g.trim_last_node()
if g.nodes:
return True
return len(getattr(mapped, 'deps', [])) == 0 Try / catch
try:
g = mapped.get_graph()
except ValueError as e:
if 'has no first node' in str(e):
# rebuild the mapped runnable around a RunnableLambda
raise
raise Prevention
- Only call .map() on runnables with well-formed get_graph().
- Wrap custom runnables in RunnableLambda before .map().
- Unit-test get_graph() for any runnable used with .map().
When it happens
Trigger: `my_runnable.map()` (which produces a `RunnableEach`) where the bound runnable or a dependency has a broken/empty `get_graph()`, then calling `.get_graph()` or graph visualization on the mapped runnable.
Common situations: Custom `Runnable` subclasses used with `.map()` without a proper `get_graph` override; visualizing batch-processing pipelines; third-party runnables with graph-API incompatibilities.
Related errors
- Runnable {dep} has no last 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/80975427f79d21c4.
Report an issue: GitHub.