Skip to content

When using subgraphs and Command, the output of the final node in the subgraph is not displayed #3362

Open
@ren8k

Description

Checked other resources

  • This is a bug, not a usage question. For questions, please use GitHub Discussions.
  • I added a clear and detailed title that summarizes the issue.
  • I read what a minimal reproducible example is (https://stackoverflow.com/help/minimal-reproducible-example).
  • I included a self-contained, minimal example that demonstrates the issue INCLUDING all the relevant imports. The code run AS IS to reproduce the issue.

Example Code

from typing import Annotated, TypedDict

from typing_extensions import Literal

from langgraph.graph import END, StateGraph
from langgraph.types import Command


def my_reducer(a: str, b: str | None) -> int:
    if b is not None:
        return b
    return a


class State(TypedDict):
    # node_name: Annotated[list[str], add]
    node_name: Annotated[str, my_reducer]
    foo: str


def subgraph_node_1(state: State) -> Command[Literal["subgraph_node_2"]]:
    return Command(
        goto="subgraph_node_2",
        update={
            "node_name": "subgraph_node_1",
            "foo": "Update at subgraph_node_1!",
        },
    )


def subgraph_node_2(state: State) -> Command:
    return Command(
        goto="node_3",
        update={"node_name": "subgraph_node_2"},
        graph=Command.PARENT,
    )


subgraph_builder = StateGraph(State)
subgraph_builder.add_node(subgraph_node_1)
subgraph_builder.add_node(subgraph_node_2)
subgraph_builder.set_entry_point("subgraph_node_1")
subgraph = subgraph_builder.compile()


# Define main graph
def node_1(state: State) -> Command[Literal["node_2"]]:
    return Command(
        goto="node_2",
        update={"node_name": "node_1"},
    )


def node_3(state: State) -> Command[Literal["__end__"]]:
    return Command(
        goto=END,
        update={"node_name": "node_3"},
    )


main_builder = StateGraph(State)
main_builder.add_node("node_1", node_1)
main_builder.add_node("node_2", subgraph)
main_builder.add_node("node_3", node_3)
main_builder.set_entry_point("node_1")
main_graph = main_builder.compile()


# Build subgraph
with open("graph_use_command.md", "w") as file:
    file.write(f"\n{main_graph.get_graph(xray=1).draw_mermaid()}")

initial = {"node_name": "__start__"}
for chunk in main_graph.stream(initial, stream_mode="values", subgraphs=True):
    print(chunk)

Error Message and Stack Trace (if applicable)

Description

This issue is related to #3115.

Problem

When using Command in both the parent graph and the subgraph, running the stream method does not display the output of the final node in the subgraph.

Below is a diagram of the graph from the example code:

%%{init: {'flowchart': {'curve': 'linear'}}}%%
graph TD;
	__start__([<p>__start__</p>]):::first
	node_1(node_1)
	node_2_subgraph_node_1(subgraph_node_1)
	node_2_subgraph_node_2(subgraph_node_2)
	node_3(node_3)
	__end__([<p>__end__</p>]):::last
	__start__ --> node_1;
	node_1 --> node_2_subgraph_node_1;
	node_2_subgraph_node_2 --> node_3;
	node_3 --> __end__;
	subgraph node_2
	node_2_subgraph_node_1 --> node_2_subgraph_node_2;
	end
	classDef default fill:#f2f0ff,line-height:1.2
	classDef first fill-opacity:0
	classDef last fill:#bfb6fc
Loading

Below is the output from the example code. Notice that the result for the subgraph node subgaph_node_2 is not displayed:

((), {'node_name': '__start__'})
((), {'node_name': 'node_1'})
(('node_2:5198e6fe-5d96-32e1-6f68-ce104abdea04',), {'node_name': 'node_1'})
(('node_2:5198e6fe-5d96-32e1-6f68-ce104abdea04',), {'node_name': 'subgraph_node_1', 'foo': 'Update at subgraph_node_1!'})
((), {'node_name': 'subgraph_node_2', 'foo': 'Update at subgraph_node_1!'})
((), {'node_name': 'node_3', 'foo': 'Update at subgraph_node_1!'})

Expected Behavior

It is expected that the output of the final node in the subgraph is displayed.

Note that when using add_edge instead of Command, the expected behavior is achieved. Below is the example code rewritten using add_edge:

from typing import TypedDict

from langgraph.graph import END, START, StateGraph


class State(TypedDict):
    node_name: str
    foo: str


def subgraph_node_1(state: State):
    return {
        "node_name": "subgraph_node_1",
        "foo": "Update at subgraph_node_1!",
    }


def subgraph_node_2(state: State):
    return {"node_name": "subgraph_node_2"}


subgraph_builder = StateGraph(State)
subgraph_builder.add_node(subgraph_node_1)
subgraph_builder.add_node(subgraph_node_2)
subgraph_builder.add_edge(START, "subgraph_node_1")
subgraph_builder.add_edge("subgraph_node_1", "subgraph_node_2")
subgraph_builder.add_edge("subgraph_node_2", END)
subgraph = subgraph_builder.compile()


# Define main graph
def node_1(state: State):
    return {"node_name": "node_1"}


def node_3(state: State):
    return {"node_name": "node_3"}


main_builder = StateGraph(State)
main_builder.add_node("node_1", node_1)
main_builder.add_node("node_2", subgraph)
main_builder.add_node("node_3", node_3)
main_builder.add_edge(START, "node_1")
main_builder.add_edge("node_1", "node_2")
main_builder.add_edge("node_2", "node_3")
main_builder.add_edge("node_3", END)
main_graph = main_builder.compile()


# Build subgraph
with open("graph_use_edge.md", "w") as file:
    file.write(f"```mermaid\n{main_graph.get_graph(xray=1).draw_mermaid()}```")

initial = {"node_name": "__start__"}
for chunk in main_graph.stream(initial, stream_mode="values", subgraphs=True):
    print(chunk)

Below is the output, where the result for the subgraph node subgraph_node_2 is correctly displayed:

((), {'node_name': '__start__'})
((), {'node_name': 'node_1'})
(('node_2:0cf73922-e372-fc29-ef53-ba1c568bb221',), {'node_name': 'node_1'})
(('node_2:0cf73922-e372-fc29-ef53-ba1c568bb221',), {'node_name': 'subgraph_node_1', 'foo': 'Update at subgraph_node_1!'})
(('node_2:0cf73922-e372-fc29-ef53-ba1c568bb221',), {'node_name': 'subgraph_node_2', 'foo': 'Update at subgraph_node_1!'})
((), {'node_name': 'subgraph_node_2', 'foo': 'Update at subgraph_node_1!'})
((), {'node_name': 'node_3', 'foo': 'Update at subgraph_node_1!'})

System Info

System Information
------------------
> OS:  Linux
> OS Version:  #44~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue Jun 18 14:36:16 UTC 2
> Python Version:  3.12.5 | packaged by Anaconda, Inc. | (main, Sep 12 2024, 18:27:27) [GCC 11.2.0]

Package Information
-------------------
> langchain_core: 0.3.28
> langchain: 0.3.7
> langchain_community: 0.3.5
> langsmith: 0.1.136
> langchain_aws: 0.2.10
> langchain_fireworks: 0.2.1
> langchain_openai: 0.2.11
> langchain_text_splitters: 0.3.0
> langgraph_sdk: 0.1.48

Optional packages not installed
-------------------------------
> langserve

Other Dependencies
------------------
> aiohttp: 3.10.5
> async-timeout: Installed. No version info available.
> boto3: 1.35.90
> dataclasses-json: 0.6.7
> fireworks-ai: 0.15.7
> httpx: 0.27.0
> httpx-sse: 0.4.0
> jsonpatch: 1.33
> numpy: 1.26.4
> openai: 1.56.2
> orjson: 3.10.9
> packaging: 24.1
> pydantic: 2.9.2
> pydantic-settings: 2.6.1
> PyYAML: 6.0.2
> requests: 2.32.3
> requests-toolbelt: 1.0.0
> SQLAlchemy: 2.0.34
> tenacity: 8.2.3
> tiktoken: 0.8.0
> typing-extensions: 4.11.0

LangGraph Version

pip list | grep langgraph

> langgraph                         0.2.70
> langgraph-checkpoint              2.0.12
> langgraph-sdk                     0.1.48

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions