AI & Agent Dev Bug Sandbox logo
AI & Agent Dev Bug Sandbox
Back to Radar

`InjectedToolCallId` Is Overridden By A Value Inside `Args` When A Custom `Args_schema` Does Not Declare The Field

A tool using `InjectedToolCallId` receives the wrong tool_call_id when the custom args_schema omits the injected field and the ToolCall args contain a key `tool_call_id`. The runtime ToolCall.id should always win, but currently the user-provided value from args is used, causing mismatch between tool body and ToolMessage.

highConfidence 95%Langchain-CoreAffected V1.6.5

Origin Analysis

In `_parse_input` of `langchain_core/tools/base.py`, the final loop over `self._injected_args_keys` gives priority to keys present in `tool_input` over the runtime `tool_call_id`. The pre-fill logic only handles fields declared in the schema (via `get_all_basemodel_annotations`), so when the custom args_schema omits the injected field, the pre-fill never overwrites it, and the later loop incorrectly uses the forged value from args.
1. Define a tool function with parameter `tool_call_id: Annotated[str, InjectedToolCallId]`. 2. Create a `StructuredTool` with a custom `args_schema` that does not include `tool_call_id`. 3. Invoke the tool with a ToolCall dict whose `id` is `"real"` and whose `args` contain `{"tool_call_id": "forged"}`. 4. Observe that the tool body receives `"forged"` while the ToolMessage carries `"real"`, causing inconsistency.

Fixing Code Block

Edge Case Audit

This change forces runtime id over args, which could break any code that intentionally relies on overriding tool_call_id via args when a ToolCall id is present (not an intended use). The direct dict path is preserved because tool_call_id is None in that scenario. If unexpected regressions occur, rollback to the previous version and as a workaround ensure the args_schema includes the injected field or manually scrub tool_call_id from args before invoking.

Ecosystem Topology