Skip to content

heap memory use increasing with langgraph invocations on node server #1746

@orangewit3

Description

@orangewit3

Checked other resources

  • I added a very descriptive title to this issue.
  • I searched the LangGraph.js 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 LangGraph.js rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangGraph (or the specific integration package).

Example Code

N/A

Error Message and Stack Trace (if applicable)

No response

Description

langgraph invocations are leaking heap between requests (Node + LangGraph/LangChain)

TL;DR: After two back-to-back langgraph invocations on a warm server, heap never returns to baseline. Biggest deltas: strings +~2.3 MB (duplicate prompts/config blobs) and compiled code +~3.5 MB (per-request instruction streams/functions). Under load this pushes Render into OOM/restarts.

What I did

Instrumented the server with heap snapshots: capture before request, run langgraph, capture after, repeat for a second request, then run a comparison.

Image Image Image

What I’m seeing

I've attached a couple screenshots showing the heap comparison between consecutive requests showing the heap increases for the string and compiled code sections.

Strings ballooning (~+2.3 MB / 2 reqs). They’re our long prompt bodies (repeated prompts) and generation config JSON.
Ref: “Filter by class → string” shows many repeats of the same long prompt text.

“Compiled code” ballooning (~+3.5 MB / 2 reqs).
Retainers point to instruction streams (_prepareSingleTask, _parse, _Request, ClientRequest, pipelineImpl) chained to ChatGoogleGenerativeAI in @langchain/google-genai/dist/chat_models.cjs.
Ref: compiled code delta + retainers tree.

Smaller persistent growths (5–10 KB each/request). Objects from setContextVariable('UserDetails') and setContextVariable('CartDetails') stick around. I suspect artifacts and a few other run objects too (needs a focused snapshot to confirm).

Node does not GC at end of HTTP request. Anything still strongly referenced (module cache, closure, event listener, etc.) persists.

Why it matters

Heap climbs with every http request → steady climb to OOM → Render kills/restarts. That’s exactly what we’re seeing under moderate burst.

Likely causes (most → least)

Prompt/template duplication + retention.
We pull from Prompt Hub each request and build fresh ChatPromptTemplates. Those carry large strings and appear to remain referenced. I tried a quick Map cache keyed by prompt name; growth still happens → either the cache pins instances, or other references exist (templates copied into new graph instances each run, captured by closures, etc.).

Graph/model plumbing rebuilt per run and retained.
“Compiled code” growth + retainers tied to ChatGoogleGenerativeAI implies new functions/instruction streams (parsers, validators, pipeline steps) per invocation, and something holds references so they never get collected.

Request context + artifacts leaking scope.
setContextVariable(...) values and possibly artifacts aren’t purely ephemeral; they’re likely ending up in long-lived structures or listeners.

Repro (minimal)

Start Node server (LangGraph; Prompt Hub; LangChain @langchain/google-genai).

Warm with first request.

Take Heap A.

Send two identical http requests.

Take Heap B and compare.

Observe strings and compiled code heap sections increasing, retained via prompt strings and instruction streams linked to ChatGoogleGenerativeAI.

Environment

Node on Render.

LangGraph/LangSmith orchestration.

Prompt Hub fetch.

LangChain @langchain/google-genai client.

Default Node flags (no --expose-gc in prod).

What I tried

Naive Map cache for prompts → no change. Either cache pins or there are additional references beyond the cache (graph copies, closures, listeners).

What this likely means

Strong references exist past request end (module caches, event listeners, run registries, client singletons done wrong, etc.).

If LangGraph/LangSmith deep-copies graph elements (templates, tools, validators) per run and keeps a reference (esp. with tracing), that would explain the compiled-code growth. So hoping someone can provide more clarity on this issue and propose a strategy for fixing this!

System Info

Node version: v22.13.1
Operating system: darwin arm64
Package manager: npm
Package manager version: N/A

zod -> @3.24.3, , @"^3.22.4", @"^3.23.8", @"^3.24.1"
@langchain/anthropic -> @0.3.19, , @"^0.3.19", @""
@langchain/core -> @0.3.57, , @"^0.3.50", @">=0.3.48, @">=0.3.55, @">=0.2.36, @">=0.2.31, @">=0.2.21
langsmith -> @0.3.29, , @"^0.3.29"
@langchain/google-genai -> @0.2.10, , @"^0.2.7", @"
"
@langchain/langgraph -> @0.2.67, , @"^0.2.67"
@langchain/langgraph-checkpoint -> @0.0.17, , @"~0.0.17"
@langchain/langgraph-sdk -> @0.0.74, , @"~0.0.32"
@langchain/openai -> @0.5.8, , @"^0.5.8", @">=0.1.0
langchain -> @0.3.27, , @"^0.3.27"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions