langchain-ai/langchain

core: leak when using object member in a `RunnableSequence`

Open

#30,667 opened on 2025年4月4日

GitHub で見る
 (8 comments) (2 reactions) (0 assignees)Python (136,758 stars) (22,617 forks)batch import
bugcoreexternalhelp wantedinvestigate

説明

Checked other resources

  • I added a very descriptive title to this issue.
  • I searched the LangChain documentation with the integrated search.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangChain rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).

Example Code

import gc

from langchain_core.runnables import (
    RunnableLambda,
    RunnablePassthrough,
)


def log_memory_usage():
    gc.collect()
    objs = gc.get_objects()
    print(f"Total objects: {len(objs)}")


class ThingWithRunnable:
    def __init__(self, func):
        self.func = func
        self.runnable_lambda = RunnableLambda(func)
        self.expensive = {i: [i] for i in range(1000000)}

    def call(self, inputs):
        return self.runnable_lambda.invoke(inputs)

    def __del__(self):
        print(">>>> Cleaning up")


def func(inp):
    return {"result": "ok"}


def works():
    thing = ThingWithRunnable(func)
    thing.call({})


def works2():
    thing = ThingWithRunnable(func)
    (RunnableLambda(thing.func) | RunnablePassthrough()).invoke({})


def broken():
    thing = ThingWithRunnable(func)
    (thing.call | RunnablePassthrough()).invoke({})


def broken2():
    thing = ThingWithRunnable(func)
    (RunnableLambda(thing.call) | RunnablePassthrough()).invoke({})


if __name__ == "__main__":
    gc.freeze()
    print("Works:")
    for _ in range(2):
        works()
        log_memory_usage()

    print("Works 2:")
    for _ in range(2):
        works2()
        log_memory_usage()

    print("Broken:")
    for _ in range(2):
        broken()
        log_memory_usage()

    print("Broken 2:")
    for _ in range(2):
        broken2()
        log_memory_usage()

Error Message and Stack Trace (if applicable)

No response

Description

(I created this first as a discussion but after giving it some more thought, I'm pretty sure it's a bug in langchain-core so I'm opening this issue)

Hi, we encountered a memory leak in our app and simplified it down to this. When creating a new RunnableSequence where a member of an object (thing.call) that invokes a Runnable is followed by something else like a RunnablePassthrough, the memory is not cleaned up.

There seems to be a reference to thing still held somewhere which is why the GC doesn't remove the object from memory.

Output:

Works:
>>>> Cleaning up
Total objects: 24670
>>>> Cleaning up
Total objects: 24658
Works 2:
>>>> Cleaning up
Total objects: 24936
>>>> Cleaning up
Total objects: 24936
Broken:
Total objects: 1024999
Total objects: 2025005
Broken 2:
Total objects: 3025011
Total objects: 4025017

What I would expect: "Cleaning up" logged also in the "broken" versions, object counts don't increase by a lot

In our real app, we were able to work around it by creating two Runnables, the first with the object member and the second with further steps, and invoking them one after the other.

System Info

uv run python -m langchain_core.sys_info

System Information
------------------
> OS:  Darwin
> OS Version:  Darwin Kernel Version 24.3.0: Thu Jan  2 20:24:24 PST 2025; root:xnu-11215.81.4~3/RELEASE_ARM64_T6030
> Python Version:  3.13.1 (main, Jan  5 2025, 06:22:40) [Clang 19.1.6 ]

Package Information
-------------------
> langchain_core: 0.3.50
> langsmith: 0.3.24

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

Other Dependencies
------------------
> httpx: 0.28.1
> jsonpatch<2.0,>=1.33: Installed. No version info available.
> langsmith-pyo3: Installed. No version info available.
> langsmith<0.4,>=0.1.125: Installed. No version info available.
> openai-agents: Installed. No version info available.
> opentelemetry-api: Installed. No version info available.
> opentelemetry-exporter-otlp-proto-http: Installed. No version info available.
> opentelemetry-sdk: Installed. No version info available.
> orjson: 3.10.16
> packaging: 24.2
> packaging<25,>=23.2: Installed. No version info available.
> pydantic: 2.11.2
> pydantic<3.0.0,>=2.5.2;: Installed. No version info available.
> pydantic<3.0.0,>=2.7.4;: Installed. No version info available.
> pytest: Installed. No version info available.
> PyYAML>=5.3: Installed. No version info available.
> requests: 2.32.3
> requests-toolbelt: 1.0.0
> rich: Installed. No version info available.
> tenacity!=8.4.0,<10.0.0,>=8.1.0: Installed. No version info available.
> typing-extensions>=4.7: Installed. No version info available.
> zstandard: 0.23.0

コントリビューターガイド

core: leak when using object member in a `RunnableSequence` · langchain-ai/langchain#30667 | Good First Issue