langchain-ai/langchain · error · ValueError

String tool inputs are not allowed when using tools with JSO

Error message

String tool inputs are not allowed when using tools with JSON schema args_schema.

What it means

When a tool built with a JSON-schema dict `args_schema` is invoked with a plain string, `Tool.run`/validation refuses it: JSON-schema-dict tools have no single-field convention to map the string onto, unlike single-field Pydantic tools where the string is assigned to the lone field. The ValueError is raised during input validation before `_run` executes.

Source

Thrown at libs/core/langchain_core/tools/base.py:807

        Returns:
            The parsed and validated input.

        Raises:
            ValueError: If `string` input is provided with JSON schema `args_schema`.
            ValueError: If `InjectedToolCallId` is required but `tool_call_id` is not
                provided.
            TypeError: If `args_schema` is not a Pydantic `BaseModel` or dict.
        """
        input_args = self.args_schema

        if isinstance(tool_input, str):
            if input_args is not None:
                if isinstance(input_args, dict):
                    msg = (
                        "String tool inputs are not allowed when "
                        "using tools with JSON schema args_schema."
                    )
                    raise ValueError(msg)
                key_ = next(iter(get_fields(input_args).keys()))
                if issubclass(input_args, BaseModel):
                    input_args.model_validate({key_: tool_input})
                elif issubclass(input_args, BaseModelV1):
                    input_args.parse_obj({key_: tool_input})
                else:
                    msg = f"args_schema must be a Pydantic BaseModel, got {input_args}"  # type: ignore[unreachable]
                    raise TypeError(msg)
            return tool_input

        if input_args is not None:
            if isinstance(input_args, dict):
                return tool_input
            result: BaseModel | BaseModelV1
            if issubclass(input_args, BaseModel):
                # Check args_schema for InjectedToolCallId
                for k, v in get_all_basemodel_annotations(input_args).items():
                    if _is_injected_arg_type(v, injected_type=InjectedToolCallId):

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Invoke with a dict matching the schema: `my_tool.invoke({'query': '...'})`.
  2. If a single-string call must work, use a Pydantic single-field `args_schema` model instead of a raw JSON-schema dict (strings are then mapped to that one field).
  3. Post-process malformed model tool calls (string args) into dicts before dispatching to the tool.

Example fix

# before
@tool
def lookup(q: str) -> str:
    """Look up."""
    ...
json_tool = Tool(..., args_schema={'type':'object','properties':{'q':{'type':'string'}},'required':['q']})
json_tool.invoke('alice')  # ValueError
# after
json_tool.invoke({'q': 'alice'})
Defensive patterns

Strategy: type-guard

Validate before calling

def coerce_tool_input(tool, tool_input):
    if isinstance(tool_input, str) and isinstance(tool.args_schema, dict):
        props = tool.args_schema.get('properties', {})
        if len(props) == 1:
            return {next(iter(props)): tool_input}
        raise ValueError('dict-schema tool needs full dict input')
    return tool_input

tool.invoke(coerce_tool_input(tool, raw_input))

Type guard

def accepts_string_input(tool) -> bool:
    schema = tool.args_schema
    return not isinstance(schema, dict) and (
        schema is None or len(getattr(schema, 'model_fields', getattr(schema, '__fields__', {}))) <= 1
    )

Try / catch

try:
    out = tool.invoke(tool_input)
except ValueError as e:
    if 'String tool inputs are not allowed' in str(e):
        out = tool.invoke({'query': tool_input})  # map string to schema field
    else:
        raise

Prevention

When it happens

Trigger: `my_tool.invoke('plain string query')` where `my_tool` was created with `args_schema={'type': 'object', ...}`; agents calling a JSON-schema tool with `tool_input` as a bare string (older models sometimes emit single-string tool calls).

Common situations: Chat models that emit `{'args': 'just a string'}` for single-arg tools; mixing Pydantic-arg tools (string input tolerated) with dict-schema tools (strict); hand-built tools whose schema dict defines multiple properties but the caller passes a string.

Related errors


AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14). Data as JSON: /api/errors/1692696d353677fa. Report an issue: GitHub.