ComposioHQ/composio · error · ValidationError

{context}: input_params must be a Pydantic BaseModel subclas

Error message

{context}: input_params must be a Pydantic BaseModel subclass. Tool input parameters are always an object with named properties.

What it means

Raised when a custom tool's input_params is not a Pydantic BaseModel subclass. Composio tool inputs must be object schemas with named properties, so bare types (int, str), TypedDict, dataclass, or dict schemas are rejected.

Source

Thrown at python/composio/core/models/custom_tool.py:181

    description: str,
    input_params: t.Type[BaseModel],
    execute: CustomToolExecuteFn,
    extends_toolkit: t.Optional[str] = None,
    output_params: t.Optional[t.Type[BaseModel]] = None,
    preload: t.Optional[bool] = None,
) -> CustomTool:
    """Internal: create and validate a CustomTool."""
    context = "experimental.tool"

    _validate_slug(slug, context)

    if not name:
        raise ValidationError(f"{context}: name is required")
    if not description:
        raise ValidationError(f"{context}: description is required")

    if not isinstance(input_params, type) or not issubclass(input_params, BaseModel):
        raise ValidationError(
            f"{context}: input_params must be a Pydantic BaseModel subclass. "
            f"Tool input parameters are always an object with named properties."
        )

    try:
        from pydantic import RootModel

        if issubclass(input_params, RootModel):
            raise ValidationError(
                f"{context}: input_params must be a regular BaseModel with named fields, "
                f"not a RootModel. Tool input parameters are always an object with "
                f"named properties."
            )
    except ImportError:
        pass

    if not callable(execute):
        raise ValidationError(f"{context}: execute must be a callable")

View on GitHub (pinned to 64b1b85502)

Solutions

  1. Wrap parameters in a BaseModel with named fields, e.g. class SearchInput(BaseModel): query: str — even for a single parameter
  2. For typed-function tools, let the @tool decorator infer the model from the function signature instead of hand-writing input_params
  3. Pass the class (not an instance): input_params=SearchInput, not SearchInput()
  4. Replace TypedDict/dataclass schemas with an equivalent BaseModel

Example fix

# before
class SearchInput(TypedDict):
    query: str
Tool(slug="search", ..., input_params=SearchInput)

# after
from pydantic import BaseModel
class SearchInput(BaseModel):
    query: str
Tool(slug="search", ..., input_params=SearchInput)
Defensive patterns

Strategy: type-guard

Validate before calling

from pydantic import BaseModel
def as_input_model(params) -> type[BaseModel]:
    if isinstance(params, type) and issubclass(params, BaseModel):
        return params
    raise TypeError("input_params must be a BaseModel subclass")

Type guard

from pydantic import BaseModel
from pydantic import RootModel
def is_tool_input_model(t: object) -> bool:
    return (
        isinstance(t, type)
        and issubclass(t, BaseModel)
        and not issubclass(t, RootModel)
    )

Try / catch

from composio.core.exceptions import ValidationError
try:
    Tool(input_params=input_params, ...)
except ValidationError:
    class _Input(BaseModel):
        __root__: input_params  # wrap scalar/legacy schema
    Tool(input_params=_Input, ...)

Prevention

When it happens

Trigger: Passing input_params=int, input_params=SomeTypedDict, a dataclass, or a Pydantic RootModel-style scalar type to Tool(...) / the @tool decorator; also passing an instance instead of the class itself.

Common situations: Wanting a scalar-parameter tool (e.g. input is just a string) and trying input_params=str; migrating from frameworks that accept TypedDict or JSON schema dicts; accidentally passing Model() instead of Model.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28). Data as JSON: /api/errors/2d84e76569ae2104. Report an issue: GitHub.