Course Content
Scenario-Based AI Engineering Questions
26 sections · 146 lessons
Scenario – 1: Missing Node Execution
What you need to know
The scenario: a node you added to a LangGraph workflow never runs. There is no error; the output just lacks its contribution.
How LangGraph decides what runs
A LangGraph app is a state graph: nodes are functions that read the shared state and return updates, and edges decide which node runs next. add_node only registers a node. It becomes reachable only when an edge points to it — a normal add_edge, or a conditional edge whose routing function returns that node's name.
The checklist, in order
- Is it wired? — no inbound edge means dead code. Draw the graph and look.
- Does the router match the map? — returning
"search"when the map has"retrieve"sends the run elsewhere. - Did an earlier node short-circuit? — returning to
END, raising, or an early return in a guard clause. - Was its write lost? — the node ran, but a parallel branch overwrote the same key (no reducer, last write wins).
- Did the run stop first? — the recursion limit was hit before the branch was reached.
See it instead of guessing
1from typing import Literal23def route(state) -> Literal["retrieve", "answer"]: # Literal documents the exits4 return "retrieve" if state["needs_docs"] else "answer"56builder.add_conditional_edges("classify", route, {"retrieve": "retrieve", "answer": "answer"})7graph = builder.compile(checkpointer=checkpointer)89print(graph.get_graph().draw_mermaid()) # is "retrieve" connected?10for update in graph.stream(inputs, config, stream_mode="updates"):11 print(list(update)) # names of nodes that actually ranstream_mode="updates" emits each node's state change as it runs, so a missing node is obvious. With a checkpointer, graph.get_state_history(config) replays every step after the fact.
Prevent it
Routing functions are pure, so unit-test them with plain dictionaries. In integration tests, assert on the set of node names visited, not only the final answer. That test fails the moment someone rewires a branch.
A real-life example
Scenario, numbers made up. A support agent graph gets a new check_refund_eligibility node. For two weeks, refund answers ignore eligibility rules, and nobody notices because answers still look fine.
The engineer streams one refund conversation with stream_mode="updates": the visited nodes are classify, retrieve, answer. The router's classifier now labels these chats "refund", but the router only checks for "refunds", and its fallback line sends anything unknown to retrieve. The fix is one character. The team then adds a test that asserts refund questions visit check_refund_eligibility, and changes the router's return type to a Literal so type checkers flag mismatched keys.
Follow-up questions to expect
- "How would you find this without tracing?" — Draw the graph and read the path map against the router's return values; most wiring bugs are visible in the diagram.
- "Why give routers a default branch?" — So an unexpected value goes to a safe, logged path instead of crashing mid-run or silently skipping work.
- "Can a node run and still look like it didn't?" — Yes, if its update was overwritten by a parallel branch writing the same key; that is a reducer problem, not a routing one.