Possible EventTarget memory leak detected #304

Closed
opened 2026-02-15 18:15:41 -05:00 by yindo · 2 comments
Owner

Originally created by @saba-ch on GitHub (Jul 17, 2025).

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

import { Injectable, Logger } from "@nestjs/common";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { ConfigService } from "@nestjs/config";
import { HumanMessage } from "@langchain/core/messages";
import { ChatPromptTemplate, MessagesPlaceholder } from "@langchain/core/prompts";
import { ChatOpenAI } from "@langchain/openai";
import { z } from "zod";
import { tool } from "@langchain/core/tools";
import { Runnable } from "@langchain/core/runnables";

import { IAiConfig } from "src/config/interfaces";
import { FoodTools } from "src/modules/food/food.tools";
import { WebSearchService } from "src/common/tools";
import { aiResponseFormat } from "src/utils/ai-response-format";

import { FoodResearchService } from "./food-research.service";

export const foodResearchOutputSchema = z.object({
  id: z.string(),
  name: z.string(),
  brand_name: z.string(),
  calories: z.number(),
  protein: z.number(),
  carbs: z.number(),
  fat: z.number(),
  serving_size_name: z.string(),
  serving_size_grams: z.number(),
  servings: z.array(z.object({
    id: z.string(),
    name: z.string(),
    grams: z.number(),
  })),
})


@Injectable()
export class FoodResearchAgent {
  private readonly logger = new Logger(FoodResearchService.name);
  private readonly customModel: Runnable;
  private readonly agent: ReturnType<typeof createReactAgent>;

  constructor(
    private readonly configService: ConfigService,
    private readonly foodTools: FoodTools,
    private readonly webSearchService: WebSearchService,
  ) {
    this.customModel = new ChatOpenAI({
      model: 'moonshotai/Kimi-K2-Instruct',
      temperature: 1,
      apiKey: this.configService.get<IAiConfig>('ai')?.baseTenApiKey,
      configuration: {
        baseURL: 'https://inference.baseten.co/v1'
      }
    });
    const prompt = ChatPromptTemplate.fromMessages([
      ["system", `You are a helpful food researcher.
Your job is to research foods and their nutritional information, and store them accurately in the database.

Use the web search tool to find the food and its nutritional information. Prefer reliable and official sources like USDA, nutritiondata, or manufacturer websites.

Once you find the food:
	1.	Use the createFood tool to create the food in the database.
	2.	Always include the source_url (the website used to retrieve the nutritional information).
	3.	Use the USDA standard for the food name and brand name.

If you are providing grams, use this format: 100g, 1g, 10g, 1000g, etc.

The createFood tool will automatically create servings for:
	•	100g
	•	1g
	•	The serving size you passed to it (e.g., 1 medium apple)

Then, use the createServingTool to create additional specific servings for the food.
Do not duplicate servings already created by createFood.

Examples of specific servings to create:
	•	Apple: small, medium, large
	•	Pizza: slice, small, medium, large
	•	Burger: burger
	•	French fries: small, medium, large

Your work must be accurate and precise.
You are not interacting with the user—you are only researching foods and storing them in the database.
      `],
      new MessagesPlaceholder('messages'),
    ]);
    
    this.agent = createReactAgent({
      llm: this.customModel,
      tools: [
        this.foodTools.createFoodTool,
        this.foodTools.createServingTool,
        this.webSearchService.webSearchTool,
      ],
      prompt,
      responseFormat: foodResearchOutputSchema as any,
    });
  }

  async invoke({
    message,
  }) {
    const result = await this.agent.invoke(
      {
        messages: [new HumanMessage(message)],
      },
    );

    return result.structuredResponse;
  }

  async invokeStream({
    message,
    res,
  }) {
    const result = this.agent.stream(
      {
        messages: [new HumanMessage(message)],
      },
      {
        streamMode: ["updates"],
      }
    );

    for await (const [streamMode, chunk] of await result) {
      if (streamMode === 'updates') {
        res.write(`data: ${JSON.stringify(chunk)}\n\n`);
      }
    }

    res.end();
  }

  public invokeAgentTool = tool(
    async (input: { query: string }) => {
      const response = await this.invoke({ message: input.query })
      return JSON.stringify(aiResponseFormat(response, [], ['servings']))
    },
    {
      name: "researchFood",
      description: "Research a food, e.g. 'McDonald's hamburger burger'",
      schema: z.object({
        query: z.string(),
      }) as any,
    }
  )
}

Error Message and Stack Trace (if applicable)

(node:37960) MaxListenersExceededWarning: Possible EventTarget memory leak detected. 11 abort listeners added to [AbortSignal]. MaxListeners is 10. Use events.setMaxListeners() to increase limit
(Use node --trace-warnings ... to show where the warning was created)

Description

Warning is thrown when multiple tool calls are made, for example following run won't throw an error:

$ curl --location 'localhost:3000/food-research/research/stream' \
--header 'Authorization: Bearer <REDACTED>' \
--header 'Content-Type: application/json' \
--data '{
  "query": "Red apple"
}'

> data: {"agent":{"messages":[{"content":"I'll research the nutritional information for red apples and store them in the database.","tool_calls":[{"name":"serpApi","args":{"query":"red apple nutrition facts USDA calories carbs protein fat per 100g"}}]}]}}

> data: {"tools":{"messages":[{"name":"serpApi","content":"...","response_metadata":{},"tool_call_id":"0"}]}}

> data: {"agent":{"messages":[{"tool_calls":[{"name":"createFood","args":{"name":"Red apple","brand_name":"Generic","calories":52,"protein":0.26,"carbs":13.81,"fat":0.17,"serving":{"name":"100g","grams":100},"source_url":"https://fdc.nal.usda.gov/fdc-app.html#/food-details/1102644/nutrients"}}]}]}}

> data: {"tools":{"messages":[{"name":"createFood","content":"{ \"name\": \"Red apple\", \"brand_name\": \"Generic\", \"calories\": 52, \"protein\": 0.26, \"carbs\": 13.81, \"fat\": 0.17, \"serving_size_name\": \"100g\", \"serving_size_grams\": 100, \"source_url\": \"https://fdc.nal.usda.gov/fdc-app.html#/food-details/1102644/nutrients\" }"}]}}

> data: {"agent":{"messages":[{"content":"✅ Task Complete — \"Red apple\" added to the database.\n\n📊 Nutrients per 100 g:\n- Calories: 52 kcal\n- Protein: 0.26 g\n- Carbohydrates: 13.81 g\n- Fat: 0.17 g\n\n🔗 Source: USDA FoodData Central"}]}}

but this one will

$ curl --location 'localhost:3000/food-research/research/stream' \
--header 'Authorization: Bearer <REDACTED>' \
--header 'Content-Type: application/json' \
--data '{
  "query": "Red apple"
}'

> data: {"agent":{"messages":[{"content":"I'll research red apple nutritional information and add it to the database.","tool_calls":[{"name":"serpApi","args":{"query":"red apple nutritional information usda calories protein carbs fat"}}]}]}}

> data: {"tools":{"messages":[{"name":"serpApi","content":"{\n  \"searchParameters\": { ... },\n  \"answerBox\": {\n    \"snippet\": \"95 calories, 0 gram fat, 1 gram protein, 25 grams carbohydrate\",\n    \"title\": \"Apples - The Nutrition Source\",\n    \"link\": \"https://nutritionsource.hsph.harvard.edu/food-features/apples/\"\n  },\n  \"organic\": [...],\n  \"peopleAlsoAsk\": [...],\n  \"relatedSearches\": [...]\n}","tool_call_id":"0"}]}}

> data: {"agent":{"messages":[{"tool_calls":[{"name":"createFood","args":{"name":"Red Delicious apple, raw, with skin","brand_name":"USDA","calories":52,"protein":0.3,"carbs":14.1,"fat":0.2,"serving":{"name":"1 medium apple (3'' dia)","grams":182},"source_url":"https://fdc.nal.usda.gov/fdc-app.html#/food-details/1102604/nutrients"}}]}]}}

> data: {"tools":{"messages":[{"name":"createFood","content":"{\n  \"name\": \"Red Delicious apple, raw, with skin\",\n  \"brand_name\": \"USDA\",\n  \"calories\": 52,\n  \"protein\": 0.3,\n  \"carbs\": 14.1,\n  \"fat\": 0.2,\n  \"serving_size_name\": \"1 medium apple (3'' dia)\",\n  \"serving_size_grams\": 182,\n  \"source_url\": \"https://fdc.nal.usda.gov/fdc-app.html#/food-details/1102604/nutrients\"\n}"}]}}

> data: {"agent":{"messages":[{"tool_calls":[{"name":"createServing","args":{"food_id":"c2481f84-d709-43f7-be65-ec48608b2e54","servings":[{"name":"1 small apple","grams":160},{"name":"1 large apple","grams":245}]}}]}}}

> data: {"tools":{"messages":[{"name":"createServing","content":"{\n  \"servings\": [\n    {\"name\": \"1 small apple\", \"grams\": 160},\n    {\"name\": \"1 large apple\", \"grams\": 245}\n  ]\n}"}]}}

> data: {"agent":{"messages":[{"content":"✅ Task Complete — \"Red Delicious apple, raw, with skin\" added to the database.\n\n📊 Nutrients per 100 g:\n- Calories: 52 kcal\n- Protein: 0.3 g\n- Carbohydrates: 14.1 g\n- Fat: 0.2 g\n\n🍎 Default serving sizes:\n- 1g\n- 100g\n- 1 medium apple (3\" dia) — 182g\n\n➕ Additional sizes:\n- 1 small apple — 160g\n- 1 large apple — 245g\n\n🔗 Source: USDA FoodData Central"}]}}

System Info

├── @aws-sdk/client-s3@3.844.0
├── @aws-sdk/client-ses@3.844.0
├── @aws-sdk/client-sesv2@3.844.0
├── @aws-sdk/s3-request-presigner@3.844.0
├── @eslint/eslintrc@3.3.1
├── @eslint/js@9.30.1
├── @langchain/community@0.3.48
├── @langchain/core@0.3.62
├── @langchain/google-genai@0.2.14
├── @langchain/langgraph-checkpoint-postgres@0.0.5
├── @langchain/langgraph@0.3.7
├── @langchain/openai@0.5.18
├── @nestjs/axios@4.0.0
├── @nestjs/cli@11.0.7
├── @nestjs/common@11.1.3
├── @nestjs/config@4.0.2
├── @nestjs/core@11.1.3
├── @nestjs/jwt@11.0.0
├── @nestjs/platform-express@11.1.3
├── @nestjs/schematics@11.0.5
├── @nestjs/swagger@11.0.3
├── @nestjs/testing@11.1.3
├── @nestjs/typeorm@11.0.0
├── @swc/cli@0.6.0
├── @swc/core@1.12.11
├── @types/express@5.0.3
├── @types/jest@29.5.14
├── @types/multer@2.0.0
├── @types/node@22.16.2
├── @types/supertest@6.0.3
├── bcrypt@6.0.0
├── class-transformer@0.5.1
├── class-validator@0.14.2
├── date-fns@4.1.0
├── eslint-config-prettier@10.1.5
├── eslint-plugin-prettier@5.5.1
├── eslint@9.30.1
├── globals@16.3.0
├── helmet@8.1.0
├── jest@29.7.0
├── moment@2.30.1
├─��� nodemailer@7.0.5
├── passport-google-oauth20@2.0.0
├── pg@8.16.3
├── prettier@3.6.2
├── reflect-metadata@0.2.2
├── rxjs@7.8.2
├── sharp@0.34.3
├── source-map-support@0.5.21
├── supertest@7.1.3
├── ts-jest@29.4.0
├── ts-loader@9.5.2
├── ts-node@10.9.2
├── tsconfig-paths@4.2.0
├── typeorm@0.3.25
├── typescript-eslint@8.36.0
├── typescript@5.8.3
└── zod@3.25.76

Originally created by @saba-ch on GitHub (Jul 17, 2025). ### Checked other resources - [x] I added a very descriptive title to this issue. - [x] I searched the LangGraph.js documentation with the integrated search. - [x] I used the GitHub search to find a similar question and didn't find it. - [x] I am sure that this is a bug in LangGraph.js rather than my code. - [x] The bug is not resolved by updating to the latest stable version of LangGraph (or the specific integration package). ### Example Code ```typescript import { Injectable, Logger } from "@nestjs/common"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { ConfigService } from "@nestjs/config"; import { HumanMessage } from "@langchain/core/messages"; import { ChatPromptTemplate, MessagesPlaceholder } from "@langchain/core/prompts"; import { ChatOpenAI } from "@langchain/openai"; import { z } from "zod"; import { tool } from "@langchain/core/tools"; import { Runnable } from "@langchain/core/runnables"; import { IAiConfig } from "src/config/interfaces"; import { FoodTools } from "src/modules/food/food.tools"; import { WebSearchService } from "src/common/tools"; import { aiResponseFormat } from "src/utils/ai-response-format"; import { FoodResearchService } from "./food-research.service"; export const foodResearchOutputSchema = z.object({ id: z.string(), name: z.string(), brand_name: z.string(), calories: z.number(), protein: z.number(), carbs: z.number(), fat: z.number(), serving_size_name: z.string(), serving_size_grams: z.number(), servings: z.array(z.object({ id: z.string(), name: z.string(), grams: z.number(), })), }) @Injectable() export class FoodResearchAgent { private readonly logger = new Logger(FoodResearchService.name); private readonly customModel: Runnable; private readonly agent: ReturnType<typeof createReactAgent>; constructor( private readonly configService: ConfigService, private readonly foodTools: FoodTools, private readonly webSearchService: WebSearchService, ) { this.customModel = new ChatOpenAI({ model: 'moonshotai/Kimi-K2-Instruct', temperature: 1, apiKey: this.configService.get<IAiConfig>('ai')?.baseTenApiKey, configuration: { baseURL: 'https://inference.baseten.co/v1' } }); const prompt = ChatPromptTemplate.fromMessages([ ["system", `You are a helpful food researcher. Your job is to research foods and their nutritional information, and store them accurately in the database. Use the web search tool to find the food and its nutritional information. Prefer reliable and official sources like USDA, nutritiondata, or manufacturer websites. Once you find the food: 1. Use the createFood tool to create the food in the database. 2. Always include the source_url (the website used to retrieve the nutritional information). 3. Use the USDA standard for the food name and brand name. If you are providing grams, use this format: 100g, 1g, 10g, 1000g, etc. The createFood tool will automatically create servings for: • 100g • 1g • The serving size you passed to it (e.g., 1 medium apple) Then, use the createServingTool to create additional specific servings for the food. Do not duplicate servings already created by createFood. Examples of specific servings to create: • Apple: small, medium, large • Pizza: slice, small, medium, large • Burger: burger • French fries: small, medium, large Your work must be accurate and precise. You are not interacting with the user—you are only researching foods and storing them in the database. `], new MessagesPlaceholder('messages'), ]); this.agent = createReactAgent({ llm: this.customModel, tools: [ this.foodTools.createFoodTool, this.foodTools.createServingTool, this.webSearchService.webSearchTool, ], prompt, responseFormat: foodResearchOutputSchema as any, }); } async invoke({ message, }) { const result = await this.agent.invoke( { messages: [new HumanMessage(message)], }, ); return result.structuredResponse; } async invokeStream({ message, res, }) { const result = this.agent.stream( { messages: [new HumanMessage(message)], }, { streamMode: ["updates"], } ); for await (const [streamMode, chunk] of await result) { if (streamMode === 'updates') { res.write(`data: ${JSON.stringify(chunk)}\n\n`); } } res.end(); } public invokeAgentTool = tool( async (input: { query: string }) => { const response = await this.invoke({ message: input.query }) return JSON.stringify(aiResponseFormat(response, [], ['servings'])) }, { name: "researchFood", description: "Research a food, e.g. 'McDonald's hamburger burger'", schema: z.object({ query: z.string(), }) as any, } ) } ``` ### Error Message and Stack Trace (if applicable) (node:37960) MaxListenersExceededWarning: Possible EventTarget memory leak detected. 11 abort listeners added to [AbortSignal]. MaxListeners is 10. Use events.setMaxListeners() to increase limit (Use `node --trace-warnings ...` to show where the warning was created) ### Description Warning is thrown when multiple tool calls are made, for example following run won't throw an error: ```bash $ curl --location 'localhost:3000/food-research/research/stream' \ --header 'Authorization: Bearer <REDACTED>' \ --header 'Content-Type: application/json' \ --data '{ "query": "Red apple" }' > data: {"agent":{"messages":[{"content":"I'll research the nutritional information for red apples and store them in the database.","tool_calls":[{"name":"serpApi","args":{"query":"red apple nutrition facts USDA calories carbs protein fat per 100g"}}]}]}} > data: {"tools":{"messages":[{"name":"serpApi","content":"...","response_metadata":{},"tool_call_id":"0"}]}} > data: {"agent":{"messages":[{"tool_calls":[{"name":"createFood","args":{"name":"Red apple","brand_name":"Generic","calories":52,"protein":0.26,"carbs":13.81,"fat":0.17,"serving":{"name":"100g","grams":100},"source_url":"https://fdc.nal.usda.gov/fdc-app.html#/food-details/1102644/nutrients"}}]}]}} > data: {"tools":{"messages":[{"name":"createFood","content":"{ \"name\": \"Red apple\", \"brand_name\": \"Generic\", \"calories\": 52, \"protein\": 0.26, \"carbs\": 13.81, \"fat\": 0.17, \"serving_size_name\": \"100g\", \"serving_size_grams\": 100, \"source_url\": \"https://fdc.nal.usda.gov/fdc-app.html#/food-details/1102644/nutrients\" }"}]}} > data: {"agent":{"messages":[{"content":"✅ Task Complete — \"Red apple\" added to the database.\n\n📊 Nutrients per 100 g:\n- Calories: 52 kcal\n- Protein: 0.26 g\n- Carbohydrates: 13.81 g\n- Fat: 0.17 g\n\n🔗 Source: USDA FoodData Central"}]}} ``` but this one will ```bash $ curl --location 'localhost:3000/food-research/research/stream' \ --header 'Authorization: Bearer <REDACTED>' \ --header 'Content-Type: application/json' \ --data '{ "query": "Red apple" }' > data: {"agent":{"messages":[{"content":"I'll research red apple nutritional information and add it to the database.","tool_calls":[{"name":"serpApi","args":{"query":"red apple nutritional information usda calories protein carbs fat"}}]}]}} > data: {"tools":{"messages":[{"name":"serpApi","content":"{\n \"searchParameters\": { ... },\n \"answerBox\": {\n \"snippet\": \"95 calories, 0 gram fat, 1 gram protein, 25 grams carbohydrate\",\n \"title\": \"Apples - The Nutrition Source\",\n \"link\": \"https://nutritionsource.hsph.harvard.edu/food-features/apples/\"\n },\n \"organic\": [...],\n \"peopleAlsoAsk\": [...],\n \"relatedSearches\": [...]\n}","tool_call_id":"0"}]}} > data: {"agent":{"messages":[{"tool_calls":[{"name":"createFood","args":{"name":"Red Delicious apple, raw, with skin","brand_name":"USDA","calories":52,"protein":0.3,"carbs":14.1,"fat":0.2,"serving":{"name":"1 medium apple (3'' dia)","grams":182},"source_url":"https://fdc.nal.usda.gov/fdc-app.html#/food-details/1102604/nutrients"}}]}]}} > data: {"tools":{"messages":[{"name":"createFood","content":"{\n \"name\": \"Red Delicious apple, raw, with skin\",\n \"brand_name\": \"USDA\",\n \"calories\": 52,\n \"protein\": 0.3,\n \"carbs\": 14.1,\n \"fat\": 0.2,\n \"serving_size_name\": \"1 medium apple (3'' dia)\",\n \"serving_size_grams\": 182,\n \"source_url\": \"https://fdc.nal.usda.gov/fdc-app.html#/food-details/1102604/nutrients\"\n}"}]}} > data: {"agent":{"messages":[{"tool_calls":[{"name":"createServing","args":{"food_id":"c2481f84-d709-43f7-be65-ec48608b2e54","servings":[{"name":"1 small apple","grams":160},{"name":"1 large apple","grams":245}]}}]}}} > data: {"tools":{"messages":[{"name":"createServing","content":"{\n \"servings\": [\n {\"name\": \"1 small apple\", \"grams\": 160},\n {\"name\": \"1 large apple\", \"grams\": 245}\n ]\n}"}]}} > data: {"agent":{"messages":[{"content":"✅ Task Complete — \"Red Delicious apple, raw, with skin\" added to the database.\n\n📊 Nutrients per 100 g:\n- Calories: 52 kcal\n- Protein: 0.3 g\n- Carbohydrates: 14.1 g\n- Fat: 0.2 g\n\n🍎 Default serving sizes:\n- 1g\n- 100g\n- 1 medium apple (3\" dia) — 182g\n\n➕ Additional sizes:\n- 1 small apple — 160g\n- 1 large apple — 245g\n\n🔗 Source: USDA FoodData Central"}]}} ``` ### System Info ├── @aws-sdk/client-s3@3.844.0 ├── @aws-sdk/client-ses@3.844.0 ├── @aws-sdk/client-sesv2@3.844.0 ├── @aws-sdk/s3-request-presigner@3.844.0 ├── @eslint/eslintrc@3.3.1 ├── @eslint/js@9.30.1 ├── @langchain/community@0.3.48 ├── @langchain/core@0.3.62 ├── @langchain/google-genai@0.2.14 ├── @langchain/langgraph-checkpoint-postgres@0.0.5 ├── @langchain/langgraph@0.3.7 ├── @langchain/openai@0.5.18 ├── @nestjs/axios@4.0.0 ├── @nestjs/cli@11.0.7 ├── @nestjs/common@11.1.3 ├── @nestjs/config@4.0.2 ├── @nestjs/core@11.1.3 ├── @nestjs/jwt@11.0.0 ├── @nestjs/platform-express@11.1.3 ├── @nestjs/schematics@11.0.5 ├── @nestjs/swagger@11.0.3 ├── @nestjs/testing@11.1.3 ├── @nestjs/typeorm@11.0.0 ├── @swc/cli@0.6.0 ├── @swc/core@1.12.11 ├── @types/express@5.0.3 ├── @types/jest@29.5.14 ├── @types/multer@2.0.0 ├── @types/node@22.16.2 ├── @types/supertest@6.0.3 ├── bcrypt@6.0.0 ├── class-transformer@0.5.1 ├── class-validator@0.14.2 ├── date-fns@4.1.0 ├── eslint-config-prettier@10.1.5 ├── eslint-plugin-prettier@5.5.1 ├── eslint@9.30.1 ├── globals@16.3.0 ├── helmet@8.1.0 ├── jest@29.7.0 ├── moment@2.30.1 ├─��� nodemailer@7.0.5 ├── passport-google-oauth20@2.0.0 ├── pg@8.16.3 ├── prettier@3.6.2 ├── reflect-metadata@0.2.2 ├── rxjs@7.8.2 ├── sharp@0.34.3 ├── source-map-support@0.5.21 ├── supertest@7.1.3 ├── ts-jest@29.4.0 ├── ts-loader@9.5.2 ├── ts-node@10.9.2 ├── tsconfig-paths@4.2.0 ├── typeorm@0.3.25 ├── typescript-eslint@8.36.0 ├── typescript@5.8.3 └── zod@3.25.76
yindo added the bug label 2026-02-15 18:15:41 -05:00
yindo closed this issue 2026-02-15 18:15:41 -05:00
Author
Owner

@hntrl commented on GitHub (Jul 17, 2025):

Hey @saba-ch! I notice you're on an older version of langgraph. Could you try forcing the upgrade to latest (0.3.10) to see if that fixes your issue?

@hntrl commented on GitHub (Jul 17, 2025): Hey @saba-ch! I notice you're on an older version of langgraph. Could you try forcing the upgrade to latest (0.3.10) to see if that fixes your issue?
Author
Owner

@saba-ch commented on GitHub (Jul 17, 2025):

Hey @hntrl just upgraded and looks like it's resolved, thank you!

@saba-ch commented on GitHub (Jul 17, 2025): Hey @hntrl just upgraded and looks like it's resolved, thank you!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraphjs#304