OpenAI builtin usage messed up by randomly populated .id field on AIMessage #273

Closed
opened 2026-02-15 18:15:22 -05:00 by yindo · 3 comments
Owner

Originally created by @jackharrhy on GitHub (May 28, 2025).

I'm struggling to get the OpenAI builtin web_search_preview to play nice with createReactAgent

This code works just fine:

import {
  HumanMessage,
  AIMessage,
  SystemMessage,
} from "@langchain/core/messages";
import { ChatOpenAI } from "@langchain/openai";

const model = new ChatOpenAI({
  model: "gpt-4o",
}).bindTools([{ type: "web_search_preview" }]);

const result = await model.invoke([
  new SystemMessage(
    "You are a helpful assistant that can search the web for the latest news, use the web_search_preview tool to do so."
  ),
  new AIMessage(
    "Hello, I'm a helpful assistant will tell you the latest news."
  ),
  new HumanMessage("When did SpaceX last explode one of their rockets?"),
]);

console.log(JSON.stringify(result, null, 2));

No API errors, I get the responses, all is well.


However, the same code using createReactAgent / langraph:

import {
  HumanMessage,
  AIMessage,
  SystemMessage,
} from "@langchain/core/messages";
import { ChatOpenAI } from "@langchain/openai";
import { createReactAgent } from "@langchain/langgraph/prebuilt";

const llm = new ChatOpenAI({
  model: "gpt-4o",
});

const agent = await createReactAgent({
  llm,
  tools: [{ type: "web_search_preview" }],
});

const result = await agent.invoke({
  messages: [
    new SystemMessage(
      "You are a helpful assistant that can search the web for the latest news, use the web_search_preview tool to do so."
    ),
    new AIMessage(
      "Hello, I'm a helpful assistant will tell you the latest news."
    ),
    new HumanMessage("When did SpaceX last explode one of their rockets?"),
  ],
});

console.log(JSON.stringify(result, null, 2));

I'm getting:

error: 400 Invalid 'input[1].id': '12477ef5-223a-41e2-9745-c7d73caab6a1'. Expected an ID that begins with 'msg'.

Which is coming internally from OpenAI:

      error: {
  message: "Invalid 'input[1].id': '12477ef5-223a-41e2-9745-c7d73caab6a1'. Expected an ID that begins with 'msg'.",
  type: "invalid_request_error",
  param: "input[1].id",
  code: "invalid_value",
},
      param: "input[1].id",
       type: "invalid_request_error",
 attemptNumber: 1,
 retriesLeft: 6,
 pregelTaskId: "69a8fe0d-9d50-5798-8033-2a253bd0fcd0",
       code: "invalid_value"

      at new OpenAIError (1:23)
      at new APIError (/Users/jack/repos/personal/langgraph-test/node_modules/openai/error.mjs:7:9)
      at new BadRequestError (1:23)
      at generate (/Users/jack/repos/personal/langgraph-test/node_modules/openai/error.mjs:41:20)
      at <anonymous> (/Users/jack/repos/personal/langgraph-test/node_modules/openai/core.mjs:339:30)

My guess is, somewhere here, an AIMessage is getting set a random id, which is fine for the chat responses API, but not for the responses API

Looks to be mentioned in the LangChainJS core docs, that the usage of the builtin triggers the underlying model to change what endpoint it uses:

ChatOpenAI will route to the Responses API if one of these features is used. You can also specify use_responses_api=True when instantiating ChatOpenAI.

I'm probably going to dive into where this is happening myself, but might be a low hanging fruit a maintainer can quickly fix, or a misunderstanding on my part of how to go about doing this.

Originally created by @jackharrhy on GitHub (May 28, 2025). I'm struggling to get the OpenAI builtin `web_search_preview` to play nice with `createReactAgent` This code works just fine: ```js import { HumanMessage, AIMessage, SystemMessage, } from "@langchain/core/messages"; import { ChatOpenAI } from "@langchain/openai"; const model = new ChatOpenAI({ model: "gpt-4o", }).bindTools([{ type: "web_search_preview" }]); const result = await model.invoke([ new SystemMessage( "You are a helpful assistant that can search the web for the latest news, use the web_search_preview tool to do so." ), new AIMessage( "Hello, I'm a helpful assistant will tell you the latest news." ), new HumanMessage("When did SpaceX last explode one of their rockets?"), ]); console.log(JSON.stringify(result, null, 2)); ``` No API errors, I get the responses, all is well. --- However, the same code using `createReactAgent` / langraph: ```js import { HumanMessage, AIMessage, SystemMessage, } from "@langchain/core/messages"; import { ChatOpenAI } from "@langchain/openai"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; const llm = new ChatOpenAI({ model: "gpt-4o", }); const agent = await createReactAgent({ llm, tools: [{ type: "web_search_preview" }], }); const result = await agent.invoke({ messages: [ new SystemMessage( "You are a helpful assistant that can search the web for the latest news, use the web_search_preview tool to do so." ), new AIMessage( "Hello, I'm a helpful assistant will tell you the latest news." ), new HumanMessage("When did SpaceX last explode one of their rockets?"), ], }); console.log(JSON.stringify(result, null, 2)); ``` I'm getting: ``` error: 400 Invalid 'input[1].id': '12477ef5-223a-41e2-9745-c7d73caab6a1'. Expected an ID that begins with 'msg'. ``` Which is coming internally from OpenAI: ``` error: { message: "Invalid 'input[1].id': '12477ef5-223a-41e2-9745-c7d73caab6a1'. Expected an ID that begins with 'msg'.", type: "invalid_request_error", param: "input[1].id", code: "invalid_value", }, param: "input[1].id", type: "invalid_request_error", attemptNumber: 1, retriesLeft: 6, pregelTaskId: "69a8fe0d-9d50-5798-8033-2a253bd0fcd0", code: "invalid_value" at new OpenAIError (1:23) at new APIError (/Users/jack/repos/personal/langgraph-test/node_modules/openai/error.mjs:7:9) at new BadRequestError (1:23) at generate (/Users/jack/repos/personal/langgraph-test/node_modules/openai/error.mjs:41:20) at <anonymous> (/Users/jack/repos/personal/langgraph-test/node_modules/openai/core.mjs:339:30) ``` My guess is, somewhere here, an `AIMessage` is getting set a random `id`, which is fine for the chat responses API, but _not_ for the responses API [Looks to be mentioned in the LangChainJS core docs](https://python.langchain.com/docs/integrations/chat/openai/#responses-api), that the usage of the builtin triggers the underlying model to change what endpoint it uses: > ChatOpenAI will route to the Responses API if one of these features is used. You can also specify use_responses_api=True when instantiating ChatOpenAI. I'm probably going to dive into where this is happening myself, but might be a low hanging fruit a maintainer can quickly fix, or a misunderstanding on my part of how to go about doing this.
yindo closed this issue 2026-02-15 18:15:22 -05:00
Author
Owner

@jackharrhy commented on GitHub (Jun 10, 2025):

import { ChatOpenAI } from '@langchain/openai';

class FixedChatOpenAI extends ChatOpenAI {
  protected async responseApiWithRetry(
    request: any,
    options: any,
  ): Promise<any> {
    if (request.input) {
      request.input = request.input.map((message: any) => {
        if ('id' in message) {
          const { id, ...messageWithoutId } = message;
          return messageWithoutId;
        }
        return message;
      });
    }

    return super.responseApiWithRetry(request, options);
  }
}

The above workaround is what I've been doing to get around this, without any noticeable bugs (I think / hope)


Likely parking usage of file_search altogether though... Anthropic / Gemini have much better out of the box citations... would rather switch to them or roll our own than use the what seemed to be nice but pretty lackluster OpenAI citations 😆

@jackharrhy commented on GitHub (Jun 10, 2025): ```js import { ChatOpenAI } from '@langchain/openai'; class FixedChatOpenAI extends ChatOpenAI { protected async responseApiWithRetry( request: any, options: any, ): Promise<any> { if (request.input) { request.input = request.input.map((message: any) => { if ('id' in message) { const { id, ...messageWithoutId } = message; return messageWithoutId; } return message; }); } return super.responseApiWithRetry(request, options); } } ``` The above workaround is what I've been doing to get around this, without any noticeable bugs (I think / hope) --- Likely parking usage of [file_search](https://platform.openai.com/docs/guides/tools-file-search) altogether though... Anthropic / Gemini have much better out of the box citations... would rather switch to them or roll our own than use the what seemed to be _nice_ but pretty lackluster OpenAI citations 😆
Author
Owner

@dqbd commented on GitHub (Jul 4, 2025):

Hello! LangGraph.js will by default generate an UUIDv4 as ID for the message when no ID is being passed during creation of AIMessage.

I think it's better to handle this on the model side, opened a PR here: https://github.com/langchain-ai/langchainjs/pull/8458/files?w=1

@dqbd commented on GitHub (Jul 4, 2025): Hello! LangGraph.js will by default generate an UUIDv4 as ID for the message when no ID is being passed during creation of AIMessage. I think it's better to handle this on the model side, opened a PR here: https://github.com/langchain-ai/langchainjs/pull/8458/files?w=1
Author
Owner

@dqbd commented on GitHub (Jul 4, 2025):

Released in @langchain/openai 0.5.17!

@dqbd commented on GitHub (Jul 4, 2025): Released in `@langchain/openai 0.5.17`!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraphjs#273