langchain - ✅(Solved) Fix StructuredTool.from_function injects spurious v__args field into JSON schema when function parameter is named args [4 pull requests, 4 comments, 5 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
langchain-ai/langchain#35796Fetched 2026-04-08 00:43:12
View on GitHub
Comments
4
Participants
5
Timeline
17
Reactions
0
Author
Timeline (top)
commented ×4cross-referenced ×4labeled ×4referenced ×4

Description

When a Python function with a parameter named args is wrapped via StructuredTool.from_function, the generated JSON schema contains a spurious extra field v__args of type array with an empty items: {}. This breaks tool use with the Gemini API, which requires all array schema fields to have a non-empty items.

Root cause

StructuredTool.from_function internally uses pydantic.deprecated.decorator.ValidatedFunction (Pydantic v1 compatibility layer) to build the args schema. That wrapper always injects a sentinel field named args to validate that no unexpected positional arguments are passed. When the wrapped function already has a parameter named args, it renames the sentinel to v__args (see pydantic/deprecated/decorator.py lines 128–137) — but still injects it into the schema as list[Any] with default: null. Pydantic renders list[Any] as {"type": "array", "items": {}}.

Impact

  • Gemini API rejects tool schemas containing {type: array, items: {}} with INVALID_ARGUMENT: missing field items.
  • The legitimate args parameter is silently dropped from the schema, so the model never learns the parameter exists.

Affected versions

  • langchain-core (tested: 0.3.x with Pydantic 2.x)

Workaround

Either rename the parameter to avoid args, or supply an explicit args_schema Pydantic model to bypass ValidatedFunction:

from pydantic import BaseModel

class RunCommandInput(BaseModel): working_dir: str args: list[str] timeout: int = 60

st = StructuredTool.from_function(run_command, args_schema=RunCommandInput)

Error Message

Error Message and Stack Trace (if applicable)

Root Cause

Root cause

Fix Action

Fix / Workaround

  • This is a bug, not a usage question.
  • I added a clear and descriptive title that summarizes this issue.
  • 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).
  • This is not related to the langchain-community package.
  • I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS.

Related issues that show the runtime symptom of the same underlying cause (but were closed as user workarounds without a framework fix): #26849, #30910. This issue focuses on the schema generation side — the v__args ghost field polluting the tool description sent to LLMs, causing silent parameter loss and API-level schema validation failures.

Workaround

PR fix notes

PR #35799: fix(core): remove v__args sentinel from StructuredTool schema

Description (problem / solution / changelog)

Fixes #35796

StructuredTool.from_function was including Pydantic’s internal v__args sentinel in the generated args schema when the wrapped function had a parameter named args, causing the real args parameter to be dropped and tool schemas to be invalid for some backends. This PR filters out the v__args sentinel while preserving a genuine args parameter and adds a regression test to cover this case.

How did you verify your code works?

  • Created a virtual environment and installed langchain-core + test deps.

  • Ran:

    source .venv/bin/activate
    pytest libs/core/tests/unit_tests/test_tools.py -k "structured_tool_from_function_with_args_param"

Changed files

  • libs/core/langchain_core/tools/base.py (modified, +10/-1)
  • libs/core/tests/unit_tests/test_tools.py (modified, +20/-0)

PR #35808: fix(core): restore original param name when function has arg named 'args'

Description (problem / solution / changelog)

Summary

Fixes #35796

When StructuredTool.from_function wraps a function with a parameter named args (or kwargs), Pydantic's ValidatedFunction renames it to v__args (v__kwargs) to avoid clashing with its own sentinel fields. The resulting JSON schema exposes the mangled name instead of the original, which:

  1. Hides the real parameter from LLMs — the model never learns the parameter exists
  2. Breaks Gemini API — the spurious v__args field has {type: array, items: {}}, which Gemini rejects with INVALID_ARGUMENT: missing field items

Root Cause

create_schema_from_function already strips Pydantic's sentinel args/kwargs fields when the function doesn't use *args/**kwargs. However, it didn't handle the reverse rename: when a regular parameter named args exists, Pydantic creates v__args — and that slipped through the filter.

Fix

  1. In create_schema_from_function: detect when the function has a regular parameter named args (or kwargs) and build a field_renames map (v__args → args)
  2. In _create_subset_model_v2: apply the rename when constructing the output model, so the JSON schema uses the original parameter name

Verification

from langchain_core.tools import StructuredTool

def run_command(working_dir: str, args: list[str], timeout: int = 60) -> str:
    """Run a command."""
    ...

st = StructuredTool.from_function(run_command)
schema = st.args_schema.model_json_schema()
print(list(schema['properties'].keys()))
# Before: ['working_dir', 'timeout', 'v__args']  ← spurious
# After:  ['working_dir', 'timeout', 'args']      ← correct

All existing test_tools.py tests pass (31/31 sync tests — the 1 async failure is pre-existing, missing pytest-asyncio dep).

Changed files

  • libs/core/langchain_core/tools/base.py (modified, +22/-1)
  • libs/core/langchain_core/utils/pydantic.py (modified, +8/-3)

PR #35815: fix: handle 'args' parameter name conflict in StructuredTool schema generation

Description (problem / solution / changelog)

Summary

  • Fixes StructuredTool.from_function injecting a spurious v__args field and dropping the legitimate args parameter when a function parameter is literally named args
  • Adds filtering for Pydantic's internal v__args/v__kwargs sentinel fields that leak into the schema when parameter names conflict with Pydantic internals
  • Preserves backward compatibility: functions with *args/**kwargs (VAR_POSITIONAL/VAR_KEYWORD) continue to work as before

Root cause

In create_schema_from_function, the check not has_args and field == "args" filters out any field named args when the function has no *args. But when a function has a regular parameter named args (e.g., def run_command(args: list[str])), Pydantic's ValidatedFunction keeps it as args in the model while renaming its own internal sentinel to v__args. The old code:

  1. Incorrectly filtered out the legitimate args field
  2. Let the spurious v__args sentinel pass through into the schema

Fix

  1. Before filtering args/kwargs fields, check whether the function actually has a regular parameter with that name
  2. Always filter out v__args and v__kwargs (Pydantic's renamed internal sentinels)

Test plan

  • Verify StructuredTool.from_function with a function having args: list[str] produces schema with args and without v__args
  • Verify functions with *args (VAR_POSITIONAL) still work correctly
  • Verify functions without any args parameter still work correctly
  • Verify same behavior for kwargs parameter name

Fixes #35796

🤖 Generated with Claude Code

Changed files

  • libs/core/langchain_core/tools/base.py (modified, +14/-2)

PR #35826: fix: Strip v__args/v__kwargs Pydantic v2 internal fields

Description (problem / solution / changelog)

Summary

Fixes issue #35796: StructuredTool.from_function injects spurious v__args field when function has param named args.

Problem

The code checked for "args" and "kwargs" but Pydantic v2 creates "v__args" and "v__kwargs" internal fields.

Fix

Changed to filter the Pydantic v2 internal field names:

-if not has_args and field == "args":
+if not has_args and field == "v__args":  # Pydantic v2 internal field
     continue
-if not has_kwargs and field == "kwargs":
+if not has_kwargs and field == "v__kwargs":
     continue

Testing

Added regression test: test_structured_tool_args_param_not_injected

Changed files

  • libs/core/langchain_core/tools/base.py (modified, +3/-2)
  • libs/core/tests/unit_tests/test_tools.py (modified, +21/-0)

Code Example

Reproducer

from langchain_core.tools import StructuredTool

def run_command(working_dir: str, args: list[str], timeout: int = 60) -> str:
"""Run a command."""
...

st = StructuredTool.from_function(run_command)
schema = st.args_schema.model_json_schema()
print(list(schema["properties"].keys()))
# → ['working_dir', 'timeout', 'v__args']  ← spurious field; 'args' is missing!
print(schema["properties"]["v__args"])
# → {'default': None, 'items': {}, 'title': 'V  Args', 'type': 'array'}

Observed: schema has v__args: {type: array, items: {}} injected, while the legitimate args parameter is absent.

Expected: schema has only working_dir, args, timeout. No v__args.

---
RAW_BUFFERClick to expand / collapse

Checked other resources

  • This is a bug, not a usage question.
  • I added a clear and descriptive title that summarizes this issue.
  • 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).
  • This is not related to the langchain-community package.
  • I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS.

Package (Required)

  • langchain
  • langchain-openai
  • langchain-anthropic
  • langchain-classic
  • langchain-core
  • langchain-model-profiles
  • langchain-tests
  • langchain-text-splitters
  • langchain-chroma
  • langchain-deepseek
  • langchain-exa
  • langchain-fireworks
  • langchain-groq
  • langchain-huggingface
  • langchain-mistralai
  • langchain-nomic
  • langchain-ollama
  • langchain-openrouter
  • langchain-perplexity
  • langchain-qdrant
  • langchain-xai
  • Other / not sure / general

Related Issues / PRs

Related issues that show the runtime symptom of the same underlying cause (but were closed as user workarounds without a framework fix): #26849, #30910. This issue focuses on the schema generation side — the v__args ghost field polluting the tool description sent to LLMs, causing silent parameter loss and API-level schema validation failures.

Reproduction Steps / Example Code (Python)

Reproducer

from langchain_core.tools import StructuredTool

def run_command(working_dir: str, args: list[str], timeout: int = 60) -> str:
"""Run a command."""
...

st = StructuredTool.from_function(run_command)
schema = st.args_schema.model_json_schema()
print(list(schema["properties"].keys()))
# → ['working_dir', 'timeout', 'v__args']  ← spurious field; 'args' is missing!
print(schema["properties"]["v__args"])
# → {'default': None, 'items': {}, 'title': 'V  Args', 'type': 'array'}

Observed: schema has v__args: {type: array, items: {}} injected, while the legitimate args parameter is absent.

Expected: schema has only working_dir, args, timeout. No v__args.

Error Message and Stack Trace (if applicable)

Description

Description

When a Python function with a parameter named args is wrapped via StructuredTool.from_function, the generated JSON schema contains a spurious extra field v__args of type array with an empty items: {}. This breaks tool use with the Gemini API, which requires all array schema fields to have a non-empty items.

Root cause

StructuredTool.from_function internally uses pydantic.deprecated.decorator.ValidatedFunction (Pydantic v1 compatibility layer) to build the args schema. That wrapper always injects a sentinel field named args to validate that no unexpected positional arguments are passed. When the wrapped function already has a parameter named args, it renames the sentinel to v__args (see pydantic/deprecated/decorator.py lines 128–137) — but still injects it into the schema as list[Any] with default: null. Pydantic renders list[Any] as {"type": "array", "items": {}}.

Impact

  • Gemini API rejects tool schemas containing {type: array, items: {}} with INVALID_ARGUMENT: missing field items.
  • The legitimate args parameter is silently dropped from the schema, so the model never learns the parameter exists.

Affected versions

  • langchain-core (tested: 0.3.x with Pydantic 2.x)

Workaround

Either rename the parameter to avoid args, or supply an explicit args_schema Pydantic model to bypass ValidatedFunction:

from pydantic import BaseModel

class RunCommandInput(BaseModel): working_dir: str args: list[str] timeout: int = 60

st = StructuredTool.from_function(run_command, args_schema=RunCommandInput)

System Info

$ uv run python -m langchain_core.sys_info

System Information

OS: Linux OS Version: #1 SMP PREEMPT_DYNAMIC Wed, 04 Mar 2026 18:25:08 +0000 Python Version: 3.12.12 (main, Feb 12 2026, 00:42:14) [Clang 21.1.4 ]

Package Information

langchain_core: 1.2.17 langchain: 1.2.10 langsmith: 0.7.12 deepagents: 0.4.5 langchain_anthropic: 1.3.4 langchain_chroma: 1.1.0 langchain_deepseek: 1.0.1 langchain_google_genai: 4.2.1 langchain_mcp_adapters: 0.2.1 langchain_openai: 1.1.10 langchain_qdrant: 1.1.0 langgraph_api: 0.7.63 langgraph_cli: 0.4.14 langgraph_runtime_inmem: 0.26.0 langgraph_sdk: 0.3.9

extent analysis

Fix Plan

To resolve the issue with the spurious v__args field in the JSON schema, you can explicitly define the args_schema using a Pydantic model. Here's how you can do it:

  • Define a Pydantic model for the function's arguments:
from pydantic import BaseModel

class RunCommandInput(BaseModel):
    working_dir: str
    args: list[str]
    timeout: int = 60
  • Pass this model to StructuredTool.from_function as the args_schema argument:
st = StructuredTool.from_function(run_command, args_schema=RunCommandInput)

Alternatively, you can rename the args parameter in your function to avoid the conflict with the sentinel field.

Verification

After applying the fix, you can verify that the v__args field is no longer present in the generated JSON schema:

schema = st.args_schema.model_json_schema()
print(list(schema["properties"].keys()))
# Should print: ['working_dir', 'args', 'timeout']

Extra Tips

  • Make sure to update your function's documentation to reflect the new argument names, if you choose to rename them.
  • If you're using other libraries or frameworks that rely on the args parameter name, you may need to update their configurations or code accordingly.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

langchain - ✅(Solved) Fix StructuredTool.from_function injects spurious v__args field into JSON schema when function parameter is named args [4 pull requests, 4 comments, 5 participants]