deepset-ai/haystack · error · SchemaGenerationError
Failed to create JSON schema for the run method of Component
Error message
Failed to create JSON schema for the run method of Component '{component.__class__.__name__}' What it means
Raised by ComponentTool._create_tool_parameters_schema when Pydantic fails to build a JSON schema from the component's run() method signature. ComponentTool wraps a Haystack Component so it can be exposed as a Tool; to do that it introspects run()'s parameters with type hints and calls create_model(...).model_json_schema(). If any parameter annotation cannot be converted to a JSON schema (unsupported types, broken generics, forward references that don't resolve), the underlying exception is chained and re-raised as SchemaGenerationError.
Source
Thrown at haystack/tools/component_tool.py:368
if _unwrap_optional(input_type) is State:
continue
description = param_descriptions.get(input_name, f"Input '{input_name}' for the component.")
# if the parameter has not a default value, Pydantic requires an Ellipsis (...)
# to explicitly indicate that the parameter is required
default = ... if socket.is_mandatory else socket.default_value
resolved_type = _resolve_type(input_type)
fields[input_name] = (resolved_type, Field(default=default, description=description))
parameters_schema: dict[str, Any] = {}
try:
# No `__doc__`: it would surface as a top-level `description` on the parameters schema,
# which LLM providers ignore. The component description feeds the tool-level description.
model = create_model(component.run.__name__, **fields)
parameters_schema = model.model_json_schema()
except Exception as e:
raise SchemaGenerationError(
f"Failed to create JSON schema for the run method of Component '{component.__class__.__name__}'"
) from e
# we don't want to include title keywords in the schema, as they contain redundant information
# there is no programmatic way to prevent Pydantic from adding them, so we remove them later
# see https://github.com/pydantic/pydantic/discussions/8504
_remove_title_from_schema(parameters_schema)
return parameters_schema
def _convert_param(self, param_value: Any, param_type: type) -> Any:
"""
Converts a single parameter value to the expected type.
:param param_value: The value to convert.
:param param_type: The expected type of the parameter.
:returns:View on GitHub (pinned to e318778c9b)
Solutions
- Inspect the chained exception (__cause__) to find which run() parameter failed schema generation
- Change the offending run() parameter type hint to a JSON-serializable Pydantic-compatible type (str, int, list, dict, BaseModel)
- Remove or replace unsupported annotations like plain Callable, custom non-serializable classes, or unresolved forward references
- Provide a static 'parameters' schema via Tool instead of letting ComponentTool derive it from run()
Example fix
// before
class MyComponent:
def run(self, client: SomeClient) -> dict:
...
// after
class MyComponent:
def run(self, endpoint: str) -> dict:
... Defensive patterns
Strategy: validation
Validate before calling
import inspect
from typing import get_type_hints
def validate_component_run_schema(component) -> str | None:
try:
hints = get_type_hints(component.run)
except Exception as e:
return f"Unresolvable type hints on run(): {e}"
for name, hint in hints.items():
if name == "return":
continue
if not hasattr(hint, "__origin__") and hint in (object, type(None)):
return f"Parameter '{name}' has non-serializable hint {hint}"
return None
problem = validate_component_run_schema(my_component)
assert problem is None, problem Type guard
def has_annotated_run(component) -> bool:
params = inspect.signature(component.run).parameters
return all(p.annotation is not inspect.Parameter.empty for p in params.values()) Try / catch
from haystack.tools.errors import SchemaGenerationError
try:
tool = ComponentTool(component=my_component)
except SchemaGenerationError as e:
logger.error("run() signature not schema-able: %s", e.__cause__)
raise Prevention
- Annotate every run() parameter with a JSON-serializable Pydantic-supported type
- Avoid Callable, client objects, and unresolved forward references in run() signatures
- Unit-test ComponentTool construction for each custom component
When it happens
Trigger: ComponentTool(component=SomeComponent()) where the component's run() method has a parameter type hint that Pydantic cannot model, e.g. an unresolvable forward reference, a Callable without parameters, arbitrary classes, or a badly parameterized generic.
Common situations: Writing a custom component whose run() takes non-serializable objects (DB connections, clients, callables); renaming/moving types so string annotations no longer resolve; Python version changes altering typing semantics.
Related errors
- Failed to create JSON schema for function '{function.__name_
- {type(self.chat_generator).__name__} does not accept tools p
- Input must be a dictionary or a list of dictionaries.
- Pre-init hooks do not support components with variadic posit
- Output type specifications of 'run' and 'run_async' methods
AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30).
Data as JSON: /api/errors/eb6aeb34e6dfaf59.
Report an issue: GitHub.