Using LangGraph stores in ASGI application hits RuntimeError: Event loop is closed #1122

Closed
opened 2026-02-20 17:43:10 -05:00 by yindo · 0 comments
Owner

Originally created by @khteh on GitHub (Jan 17, 2026).

Checked other resources

  • This is a bug, not a usage question. For questions, please use the LangChain Forum (https://forum.langchain.com/).
  • 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

async def upsert_memory(
    content: str,
    context: str,
    *,
    memory_id: Optional[uuid7str] = None,
    # Hide these arguments from the model.
    config: Annotated[RunnableConfig, InjectedToolArg],
    store: Annotated[BaseStore, InjectedStore()],
):
    """Upsert a memory in the database.

    If a memory conflicts with an existing one, then just UPDATE the
    existing one by passing in memory_id - don't create two memories
    that are the same. If the user corrects a memory, UPDATE it.
    It uses a simple memory structure "content: str, context: str" for each memory, but it could be structured in other ways.

    Args:
        content: The main content of the memory. For example:
            "User expressed interest in learning about French."
        context: Additional context for the memory. For example:
            "This was mentioned while discussing career options in Europe."
        memory_id: ONLY PROVIDE IF UPDATING AN EXISTING MEMORY.
        The memory to overwrite.
    """
    logging.info(f"\n=== upsert_memory ===")
    mem_id = memory_id or uuid7str()
    user_id = Configuration.from_runnable_config(config).user_id
    logging.debug(f"content: {content}, context: {context}, memory_id: {memory_id} {mem_id}, user_id: {user_id}")
    await store.aput(
        ("memories", user_id),
        key=str(mem_id),
        value={"content": content, "context": context},
    )
    return f"Stored memory {mem_id}"

Exception:

Traceback (most recent call last):
  File "/usr/src/Python/rag-agent/src/rag_agent/Tools.py", line 134, in upsert_memory
    await store.aput(
    ...<3 lines>...
    )
  File "/usr/src/Python/rag-agent/.venv/lib/python3.13/site-packages/langgraph/store/base/batch.py", line 140, in aput
    self._ensure_task()
    ~~~~~~~~~~~~~~~~~^^
  File "/usr/src/Python/rag-agent/.venv/lib/python3.13/site-packages/langgraph/store/base/batch.py", line 80, in _ensure_task
    self._task = self._loop.create_task(_run(self._aqueue, weakref.ref(self)))
                 ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/asyncio/base_events.py", line 466, in create_task
    self._check_closed()
    ~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/asyncio/base_events.py", line 556, in _check_closed
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed

Description

deepagent using the upsert_memory as tool which uses the injected PostgreSQL store for long-term memory hits a bogus RuntimeError: Event loop is closed exception.

System Info

System Information
------------------
> OS:  Linux
> OS Version:  #8-Ubuntu SMP PREEMPT_DYNAMIC Fri Nov 14 21:44:46 UTC 2025
> Python Version:  3.13.7 (main, Jan  8 2026, 12:15:45) [GCC 15.2.0]

Package Information
-------------------
> langchain_core: 1.2.7
> langchain: 1.2.4
> langchain_community: 0.4.1
> langsmith: 0.6.4
> langchain_anthropic: 1.3.1
> langchain_classic: 1.0.1
> langchain_google_genai: 4.2.0
> langchain_neo4j: 0.7.0
> langchain_ollama: 1.0.1
> langchain_postgres: 0.0.16
> langchain_text_splitters: 1.1.0
> langgraph_api: 0.6.38
> langgraph_cli: 0.4.11
> langgraph_runtime_inmem: 0.22.0
> langgraph_sdk: 0.3.3

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

Other Dependencies
------------------
> aiohttp: 3.13.3
> anthropic: 0.76.0
> asyncpg: 0.31.0
> blockbuster: 1.5.26
> click: 8.3.1
> cloudpickle: 3.1.2
> cryptography: 46.0.3
> dataclasses-json: 0.6.7
> filetype: 1.2.0
> google-genai: 1.59.0
> grpcio: 1.76.0
> grpcio-health-checking: 1.76.0
> grpcio-tools: 1.75.1
> httpx: 0.28.1
> httpx-sse: 0.4.3
> jsonpatch: 1.33
> jsonschema-rs: 0.29.1
> langgraph: 1.0.6
> langgraph-checkpoint: 4.0.0
> neo4j: 6.1.0
> neo4j-graphrag: 1.12.0
> numpy: 2.4.1
> ollama: 0.6.1
> opentelemetry-api: 1.39.1
> opentelemetry-exporter-otlp-proto-http: 1.39.1
> opentelemetry-sdk: 1.39.1
> orjson: 3.11.5
> packaging: 25.0
> pgvector: 0.3.6
> protobuf: 6.33.4
> psycopg: 3.3.2
> psycopg-pool: 3.3.0
> pydantic: 2.12.5
> pydantic-settings: 2.12.0
> pyjwt: 2.10.1
> pytest: 9.0.2
> python-dotenv: 1.2.1
> pyyaml: 6.0.3
> PyYAML: 6.0.3
> requests: 2.32.5
> requests-toolbelt: 1.0.0
> SQLAlchemy: 2.0.45
> sqlalchemy: 2.0.45
> sse-starlette: 2.1.3
> starlette: 0.50.0
> structlog: 25.5.0
> tenacity: 9.1.2
> truststore: 0.10.4
> typing-extensions: 4.15.0
> uuid-utils: 0.13.0
> uvicorn: 0.40.0
> watchfiles: 1.1.1
> zstandard: 0.25.0
Originally created by @khteh on GitHub (Jan 17, 2026). ### 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 ```python async def upsert_memory( content: str, context: str, *, memory_id: Optional[uuid7str] = None, # Hide these arguments from the model. config: Annotated[RunnableConfig, InjectedToolArg], store: Annotated[BaseStore, InjectedStore()], ): """Upsert a memory in the database. If a memory conflicts with an existing one, then just UPDATE the existing one by passing in memory_id - don't create two memories that are the same. If the user corrects a memory, UPDATE it. It uses a simple memory structure "content: str, context: str" for each memory, but it could be structured in other ways. Args: content: The main content of the memory. For example: "User expressed interest in learning about French." context: Additional context for the memory. For example: "This was mentioned while discussing career options in Europe." memory_id: ONLY PROVIDE IF UPDATING AN EXISTING MEMORY. The memory to overwrite. """ logging.info(f"\n=== upsert_memory ===") mem_id = memory_id or uuid7str() user_id = Configuration.from_runnable_config(config).user_id logging.debug(f"content: {content}, context: {context}, memory_id: {memory_id} {mem_id}, user_id: {user_id}") await store.aput( ("memories", user_id), key=str(mem_id), value={"content": content, "context": context}, ) return f"Stored memory {mem_id}" ``` ### Exception: ``` Traceback (most recent call last): File "/usr/src/Python/rag-agent/src/rag_agent/Tools.py", line 134, in upsert_memory await store.aput( ...<3 lines>... ) File "/usr/src/Python/rag-agent/.venv/lib/python3.13/site-packages/langgraph/store/base/batch.py", line 140, in aput self._ensure_task() ~~~~~~~~~~~~~~~~~^^ File "/usr/src/Python/rag-agent/.venv/lib/python3.13/site-packages/langgraph/store/base/batch.py", line 80, in _ensure_task self._task = self._loop.create_task(_run(self._aqueue, weakref.ref(self))) ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.13/asyncio/base_events.py", line 466, in create_task self._check_closed() ~~~~~~~~~~~~~~~~~~^^ File "/usr/lib/python3.13/asyncio/base_events.py", line 556, in _check_closed raise RuntimeError('Event loop is closed') RuntimeError: Event loop is closed ``` ### Description `deepagent` using the `upsert_memory` as tool which uses the injected PostgreSQL store for long-term memory hits a bogus `RuntimeError: Event loop is closed` exception. ### System Info ``` System Information ------------------ > OS: Linux > OS Version: #8-Ubuntu SMP PREEMPT_DYNAMIC Fri Nov 14 21:44:46 UTC 2025 > Python Version: 3.13.7 (main, Jan 8 2026, 12:15:45) [GCC 15.2.0] Package Information ------------------- > langchain_core: 1.2.7 > langchain: 1.2.4 > langchain_community: 0.4.1 > langsmith: 0.6.4 > langchain_anthropic: 1.3.1 > langchain_classic: 1.0.1 > langchain_google_genai: 4.2.0 > langchain_neo4j: 0.7.0 > langchain_ollama: 1.0.1 > langchain_postgres: 0.0.16 > langchain_text_splitters: 1.1.0 > langgraph_api: 0.6.38 > langgraph_cli: 0.4.11 > langgraph_runtime_inmem: 0.22.0 > langgraph_sdk: 0.3.3 Optional packages not installed ------------------------------- > langserve Other Dependencies ------------------ > aiohttp: 3.13.3 > anthropic: 0.76.0 > asyncpg: 0.31.0 > blockbuster: 1.5.26 > click: 8.3.1 > cloudpickle: 3.1.2 > cryptography: 46.0.3 > dataclasses-json: 0.6.7 > filetype: 1.2.0 > google-genai: 1.59.0 > grpcio: 1.76.0 > grpcio-health-checking: 1.76.0 > grpcio-tools: 1.75.1 > httpx: 0.28.1 > httpx-sse: 0.4.3 > jsonpatch: 1.33 > jsonschema-rs: 0.29.1 > langgraph: 1.0.6 > langgraph-checkpoint: 4.0.0 > neo4j: 6.1.0 > neo4j-graphrag: 1.12.0 > numpy: 2.4.1 > ollama: 0.6.1 > opentelemetry-api: 1.39.1 > opentelemetry-exporter-otlp-proto-http: 1.39.1 > opentelemetry-sdk: 1.39.1 > orjson: 3.11.5 > packaging: 25.0 > pgvector: 0.3.6 > protobuf: 6.33.4 > psycopg: 3.3.2 > psycopg-pool: 3.3.0 > pydantic: 2.12.5 > pydantic-settings: 2.12.0 > pyjwt: 2.10.1 > pytest: 9.0.2 > python-dotenv: 1.2.1 > pyyaml: 6.0.3 > PyYAML: 6.0.3 > requests: 2.32.5 > requests-toolbelt: 1.0.0 > SQLAlchemy: 2.0.45 > sqlalchemy: 2.0.45 > sse-starlette: 2.1.3 > starlette: 0.50.0 > structlog: 25.5.0 > tenacity: 9.1.2 > truststore: 0.10.4 > typing-extensions: 4.15.0 > uuid-utils: 0.13.0 > uvicorn: 0.40.0 > watchfiles: 1.1.1 > zstandard: 0.25.0 ```
yindo added the bugpending labels 2026-02-20 17:43:10 -05:00
yindo closed this issue 2026-02-20 17:43:10 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraph#1122