ComposioHQ/composio · error · ValidationError

{context}: description is required

Error message

{context}: description is required

What it means

Raised when creating a custom tool with an empty description. Descriptions are what LLMs use to decide when to call the tool, so Composio requires them.

Source

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

    slug: str,
    *,
    name: str,
    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

View on GitHub (pinned to 64b1b85502)

Solutions

  1. Add a clear description parameter or a docstring: for @tool-decorated functions the function docstring becomes the description
  2. Check that docstrings survive your build (avoid -OO / aggressive minifiers) if you rely on implicit descriptions
  3. Validate generated tool definitions contain a non-empty description before registration

Example fix

# before
def search(q: str):
    pass  # no docstring

# after
def search(q: str):
    """Search the user's connected documents for a query.""
Defensive patterns

Strategy: validation

Validate before calling

if not description:
    description = (fn.__doc__ or "").strip() or f"Execute {fn.__name__}."
assert description, "description required"

Type guard

def has_description(desc: str | None) -> bool:
    return bool(desc and desc.strip())

Try / catch

try:
    Tool(description=description, ...)
except ValidationError:
    Tool(description=fn.__doc__ or f"Executes {fn.__name__}.", ...)

Prevention

When it happens

Trigger: Calling Tool(...) or the @tool decorator without a docstring-derived description, or with description="".

Common situations: Forgetting the docstring on a decorated function and not passing description explicitly; stripping docstrings in production builds or with python -OO; config-driven tool definitions missing the description key.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


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