langgraph icon indicating copy to clipboard operation
langgraph copied to clipboard

TypeError: 'NoneType' object is not iterable when resume is used in thread.submit command

Open leopeng1995 opened this issue 4 months ago • 9 comments

Checked other resources

  • [x] This is a bug, not a usage question. For questions, please use the LangChain Forum (https://forum.langchain.com/).
  • [x] I added a clear and detailed title that summarizes the issue.
  • [x] I read what a minimal reproducible example is (https://stackoverflow.com/help/minimal-reproducible-example).
  • [x] 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

thread.submit(undefined, { command: { resume: [{"type": "accept"}] } });

Error Message and Stack Trace (if applicable)

Traceback (most recent call last):
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph_api/worker.py", line 134, in wrap_user_errors
    await consume(stream, run_id, resumable)
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph_api/stream.py", line 332, in consume
    raise e
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph_api/stream.py", line 316, in consume
    async for mode, payload in stream:
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph_api/stream.py", line 251, in astream_state
    event = await wait_if_not_done(anext(stream, sentinel), done)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph_api/asyncio.py", line 91, in wait_if_not_done
    raise e.exceptions[0] from None
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph/pregel/__init__.py", line 2768, in astream
    async for _ in runner.atick(
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph/pregel/write.py", line 101, in _awrite
    self.do_write(
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph/pregel/write.py", line 128, in do_write
    write(_assemble_writes(writes))
          ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph/pregel/write.py", line 183, in _assemble_writes
    if ww := w.mapper(w.value):
             ^^^^^^^^^^^^^^^^^
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph/graph/state.py", line 1248, in _control_branch
    for go in command.goto
              ^^^^^^^^^^^^
TypeError: 'NoneType' object is not iterable
During task with name '__start__' and id '17de729a-e0e0-aa69-dba1-583551ea7936'

Description

The update and goto parameters for Command are optional. I'm passing a resume parameter in App.tsx, but why am I getting the following error when it crashes?

Command definition:

export interface Command {
    /**
     * An object to update the thread state with.
     */
    update?: Record<string, unknown> | [string, unknown][] | null;
    /**
     * The value to return from an `interrupt` function call.
     */
    resume?: unknown;
    /**
     * Determine the next node to navigate to. Can be one of the following:
     * - Name(s) of the node names to navigate to next.
     * - `Send` command(s) to execute node(s) with provided input.
     */
    goto?: Send | Send[] | string | string[];
}

App.tsx:

                  {thread.interrupt && (
                    <div className="mt-4 p-4 bg-yellow-700 rounded-md text-neutral-100">
                      <h3 className="text-lg font-bold mb-2">Tool Call</h3>
                      <p className="mb-4">Tool Call Request:</p>
                      <ReactMarkdown remarkPlugins={[remarkGfm]} className="markdown-body">
                        {JSON.stringify(thread.interrupt.value, null, 2)}
                      </ReactMarkdown>
                      <Button
                        onClick={() => {
                          thread.submit(undefined, { command: { resume: [{"type": "accept"}] } });
                        }}
                        className="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded"
                      >
                        Continue
                      </Button>
                    </div>
                  )}

human_in_the_loop.py:

from typing import Callable, TypedDict, Optional
from langchain_core.tools import BaseTool, tool as create_tool
from langchain_core.runnables import RunnableConfig
from langgraph.types import interrupt


class HumanInterruptConfig(TypedDict, total=False):
    allow_accept: bool
    allow_edit: bool
    allow_respond: bool


class ActionRequest(TypedDict):
    action: str
    args: dict


class HumanInterrupt(TypedDict):
    action_request: ActionRequest
    config: HumanInterruptConfig
    description: str


def add_human_in_the_loop(
    tool: Callable | BaseTool,
    *,
    interrupt_config: Optional[HumanInterruptConfig] = None,
) -> BaseTool:
    """Wrap a tool to support human-in-the-loop review."""
    if not isinstance(tool, BaseTool):
        tool = create_tool(tool)

    if interrupt_config is None:
        interrupt_config = {
            "allow_accept": True,
            "allow_edit": True,
            "allow_respond": True,
        }

    @create_tool(
        tool.name,
        description=tool.description,
        args_schema=tool.args_schema
    )
    async def call_tool_with_interrupt(config: RunnableConfig, **tool_input):
        request: HumanInterrupt = {
            "action_request": {
                "action": tool.name,
                "args": tool_input
            },
            "config": interrupt_config,
            "description": "Please review the tool call"
        }
        response = interrupt([request])[0]
        
        if response["type"] == "accept":
            tool_response = await tool.ainvoke(tool_input, config)
        elif response["type"] == "edit":
            tool_input = response["args"]["args"]
            tool_response = await tool.ainvoke(tool_input, config)
        elif response["type"] == "response":
            user_feedback = response["args"]
            tool_response = user_feedback
        else:
            raise ValueError(f"Unsupported interrupt response type: {response['type']}")

        return tool_response

    return call_tool_with_interrupt

System Info

System Information

OS: Darwin OS Version: Darwin Kernel Version 23.5.0: Wed May 1 20:19:05 PDT 2024; root:xnu-10063.121.3~5/RELEASE_ARM64_T8112 Python Version: 3.12.8 (main, Jan 14 2025, 23:36:58) [Clang 19.1.6 ]

Package Information

langchain_core: 0.3.68 langchain: 0.3.26 langchain_community: 0.3.27 langsmith: 0.3.45 langchain_anthropic: 0.3.17 langchain_dashscope: 0.1.8 langchain_deepseek: 0.1.3 langchain_google_genai: 2.1.8 langchain_openai: 0.3.28 langchain_tavily: 0.2.7 langchain_text_splitters: 0.3.8 langgraph_api: 0.2.94 langgraph_cli: 0.3.4 langgraph_license: Installed. No version info available. langgraph_runtime: Installed. No version info available. langgraph_runtime_inmem: 0.5.0 langgraph_sdk: 0.1.73

Optional packages not installed

langserve

Other Dependencies

aiohttp: 3.11.18 aiohttp<4.0.0,>=3.8.3: Installed. No version info available. anthropic<1,>=0.57.0: Installed. No version info available. async-timeout<5.0.0,>=4.0.0;: Installed. No version info available. blockbuster<2.0.0,>=1.5.24: Installed. No version info available. click>=8.1.7: Installed. No version info available. cloudpickle>=3.0.0: Installed. No version info available. cryptography<45.0,>=42.0.0: Installed. No version info available. dashscope: 1.23.8 dataclasses-json<0.7,>=0.5.7: Installed. No version info available. filetype: 1.2.0 google-ai-generativelanguage: 0.6.18 httpx: 0.28.1 httpx-sse<1.0.0,>=0.4.0: Installed. No version info available. httpx>=0.25.0: Installed. No version info available. httpx>=0.25.2: Installed. No version info available. jsonpatch<2.0,>=1.33: Installed. No version info available. jsonschema-rs<0.30,>=0.20.0: Installed. No version info available. langchain-anthropic;: Installed. No version info available. langchain-aws;: Installed. No version info available. langchain-azure-ai;: Installed. No version info available. langchain-cohere;: Installed. No version info available. langchain-community;: Installed. No version info available. langchain-core<1.0.0,>=0.3.47: Installed. No version info available. langchain-core<1.0.0,>=0.3.51: Installed. No version info available. langchain-core<1.0.0,>=0.3.66: Installed. No version info available. langchain-core<1.0.0,>=0.3.68: Installed. No version info available. langchain-core>=0.3.64: Installed. No version info available. langchain-deepseek;: Installed. No version info available. langchain-fireworks;: Installed. No version info available. langchain-google-genai;: Installed. No version info available. langchain-google-vertexai;: Installed. No version info available. langchain-groq;: Installed. No version info available. langchain-huggingface;: Installed. No version info available. langchain-mistralai;: Installed. No version info available. langchain-ollama;: Installed. No version info available. langchain-openai;: Installed. No version info available. langchain-openai<1.0.0,>=0.3.9: Installed. No version info available. langchain-perplexity;: Installed. No version info available. langchain-text-splitters<1.0.0,>=0.3.8: Installed. No version info available. langchain-together;: Installed. No version info available. langchain-xai;: Installed. No version info available. langchain<1.0.0,>=0.3.26: Installed. No version info available. langgraph-api<0.3.0,>=0.2.67;: Installed. No version info available. langgraph-checkpoint>=2.0.23: Installed. No version info available. langgraph-checkpoint>=2.0.25: Installed. No version info available. langgraph-runtime-inmem<0.4.0,>=0.3.0;: Installed. No version info available. langgraph-runtime-inmem<0.6,>=0.5.0: Installed. No version info available. langgraph-sdk>=0.1.0;: Installed. No version info available. langgraph-sdk>=0.1.71: Installed. No version info available. langgraph>=0.2: Installed. No version info available. langgraph>=0.3.27: Installed. No version info available. langsmith-pyo3: Installed. No version info available. langsmith>=0.1.125: Installed. No version info available. langsmith>=0.1.17: Installed. No version info available. langsmith>=0.3.45: Installed. No version info available. numpy>=1.26.2;: Installed. No version info available. numpy>=2.1.0;: Installed. No version info available. openai-agents: Installed. No version info available. openai<2.0.0,>=1.86.0: Installed. No version info available. opentelemetry-api: 1.32.1 opentelemetry-exporter-otlp-proto-http: Installed. No version info available. opentelemetry-sdk: 1.32.1 orjson: 3.10.12 orjson>=3.10.1: Installed. No version info available. orjson>=3.9.7: Installed. No version info available. packaging: 24.2 packaging<25,>=23.2: Installed. No version info available. pydantic: 2.11.7 pydantic-settings<3.0.0,>=2.4.0: Installed. No version info available. pydantic<3.0.0,>=2.7.4: Installed. No version info available. pydantic>=2.7.4: Installed. No version info available. pyjwt>=2.9.0: Installed. No version info available. pytest: Installed. No version info available. python-dotenv>=0.8.0;: Installed. No version info available. PyYAML>=5.3: Installed. No version info available. requests: 2.32.3 requests-toolbelt: 1.0.0 requests<3,>=2: Installed. No version info available. rich: 14.0.0 SQLAlchemy<3,>=1.4: Installed. No version info available. sse-starlette<2.2.0,>=2.1.0: Installed. No version info available. sse-starlette>=2: Installed. No version info available. starlette>=0.37: Installed. No version info available. starlette>=0.38.6: Installed. No version info available. structlog<26,>=24.1.0: Installed. No version info available. structlog>23: Installed. No version info available. tenacity!=8.4.0,<10,>=8.1.0: Installed. No version info available. tenacity!=8.4.0,<10.0.0,>=8.1.0: Installed. No version info available. tenacity>=8.0.0: Installed. No version info available. tiktoken: 0.7.0 tiktoken<1,>=0.7: Installed. No version info available. truststore>=0.1: Installed. No version info available. typing-extensions>=4.7: Installed. No version info available. uvicorn>=0.26.0: Installed. No version info available. watchfiles>=0.13: Installed. No version info available. zstandard: 0.23.0

leopeng1995 avatar Jul 25 '25 01:07 leopeng1995

After upgraded to langgraph 0.6.2:

Traceback (most recent call last):
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph_api/worker.py", line 135, in wrap_user_errors
    await consume(stream, run_id, resumable)
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph_api/stream.py", line 349, in consume
    raise e
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph_api/stream.py", line 333, in consume
    async for mode, payload in stream:
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph_api/stream.py", line 263, in astream_state
    event = await wait_if_not_done(anext(stream, sentinel), done)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph_api/asyncio.py", line 91, in wait_if_not_done
    raise e.exceptions[0] from None
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph/pregel/main.py", line 2934, in astream
    async for _ in runner.atick(
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph/pregel/_runner.py", line 401, in atick
    _panic_or_proceed(
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph/pregel/_runner.py", line 511, in _panic_or_proceed
    raise exc
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph/pregel/_retry.py", line 137, in arun_with_retry
    return await task.proc.ainvoke(task.input, config)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph/_internal/_runnable.py", line 463, in ainvoke
    ret = await self.afunc(*args, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph/pregel/_write.py", line 102, in _awrite
    self.do_write(
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph/pregel/_write.py", line 129, in do_write
    write(_assemble_writes(writes))
          ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph/pregel/_write.py", line 184, in _assemble_writes
    if ww := w.mapper(w.value):
             ^^^^^^^^^^^^^^^^^
  File "/Users/leopeng1995/workspaces/promptcn/deep-insight/.venv/lib/python3.12/site-packages/langgraph/graph/state.py", line 1252, in _control_branch
    for go in goto_targets:
              ^^^^^^^^^^^^
TypeError: 'NoneType' object is not iterable
During task with name '__start__' and id '19dc15fb-f9f0-d6fd-bef9-1b174d17f8d8'

leopeng1995 avatar Jul 30 '25 11:07 leopeng1995

we are using 0.6.10 and got exact same issue, any hints ?

TypeError("'NoneType' object is not iterable")Traceback (most recent call last):


  File "/usr/local/lib/python3.12/site-packages/langgraph/pregel/__init__.py", line 2830, in astream
    async for _ in runner.atick(


  File "/usr/local/lib/python3.12/site-packages/langgraph/pregel/write.py", line 114, in _awrite
    self.do_write(


  File "/usr/local/lib/python3.12/site-packages/langgraph/pregel/write.py", line 142, in do_write
    write(_assemble_writes(writes))
          ^^^^^^^^^^^^^^^^^^^^^^^^


  File "/usr/local/lib/python3.12/site-packages/langgraph/pregel/write.py", line 199, in _assemble_writes
    if ww := w.mapper(w.value):
             ^^^^^^^^^^^^^^^^^


  File "/usr/local/lib/python3.12/site-packages/langgraph/graph/state.py", line 1079, in _control_branch
    for go in command.goto
              ^^^^^^^^^^^^


TypeError: 'NoneType' object is not iterable


During task with name '__start__' and id '07550128-d02a-8832-204d-460fe083b6ec'

zhaohc10 avatar Oct 31 '25 14:10 zhaohc10

Root Cause:

The [Command] class had goto with a default value of () (empty tuple), but it could still be set to None The [_control_branch] function assumed goto would always be iterable, but didn't handle the None case

When command.goto was None, the code tried to iterate over None, causing the TypeError

Solution:

Updated [Command.goto] type annotation to explicitly allow None:

# Before
goto: Send | Sequence[Send | N] | N = ()

# After  
goto: Send | Sequence[Send | N] | N | None = None

python

Fixed _control_branch function to handle None values:

# Before
goto_targets = (
    [command.goto] if isinstance(command.goto, (Send, str)) else command.goto
)

# After
if command.goto is None:
    goto_targets = ()
else:
    goto_targets = (
        [command.goto] if isinstance(command.goto, (Send, str)) else command.goto
    )

zhaohc10 avatar Oct 31 '25 14:10 zhaohc10

@zhaohc10 Thanks for your reply! I'm not sure if this issue still exists after LangGraph was upgraded to 1.0.

leopeng1995 avatar Oct 31 '25 14:10 leopeng1995

what's the sepcific version you are using now? how about langgrap server version ? thx

zhaohc10 avatar Oct 31 '25 15:10 zhaohc10

I encountered this issue earlier while working on a personal project. I haven't been using the LangGraph JavaScript SDK recently, as I'm currently handling HITL resume through Python instead. This approach works fine for me, so I'm not sure whether this problem still exists in the newer version.

leopeng1995 avatar Oct 31 '25 15:10 leopeng1995

thank you for your reply, when ust HITL resume through Python, which langgrah version you are using, are you able to to only specifying resuem without goto filed

zhaohc10 avatar Oct 31 '25 15:10 zhaohc10

If you restart the HITL process through the Command in Python, it currently doesn't require passing the 'goto' parameter (just resume). I've tested this with both LangGraph 0.6.x and 1.0.x, which led me to believe the issue was with the LangGraph JavaScript SDK.

leopeng1995 avatar Oct 31 '25 15:10 leopeng1995

when invoke the resume command, were you using langgraph-sdk ? it works for me to without langgraph-sdk but it failed when using langgraph-sdk with command

zhaohc10 avatar Oct 31 '25 15:10 zhaohc10