deepset-ai/haystack · error · PipelineRuntimeError
PipelineRuntimeError.from_invalid_output(component_name, ins
Error message
PipelineRuntimeError.from_invalid_output(component_name, instance.__class__, component_output)
What it means
Haystack requires every component to return a Mapping (dict-like) output so results can be routed to other components. If a component's run() returns a non-mapping (list, string, None, object), PipelineRuntimeError.from_invalid_output is raised naming the component and its class.
Source
Thrown at haystack/core/pipeline/pipeline.py:190
# This is important when Agent components internally use Pipeline._run_component
# and trigger breakpoints that need to bubble up to the main pipeline
raise error
# Any components that internally use Pipeline._run_component could raise a PipelineRuntimeError with
# additional context (e.g. Agent raises an agent snapshot) so we re-raise here instead of wrapping it in
# another PipelineRuntimeError
except PipelineRuntimeError as runtime_error:
raise runtime_error
# Catch all other exceptions and wrap them in a PipelineRuntimeError
except Exception as error:
raise PipelineRuntimeError.from_exception(component_name, instance.__class__, error) from error
component_visits[component_name] += 1
if not isinstance(component_output, Mapping):
raise PipelineRuntimeError.from_invalid_output(component_name, instance.__class__, component_output)
_validate_component_output_keys(component_name, component, component_output)
span.set_tag(_COMPONENT_VISITS, component_visits[component_name])
span.set_content_tag(_COMPONENT_OUTPUT, component_output)
return component_output
@mark_deserialization_internal
def run( # noqa: PLR0915, PLR0912, C901
self,
data: dict[str, Any],
include_outputs_from: set[str] | None = None,
*,
break_point: Breakpoint | None = None,
pipeline_snapshot: PipelineSnapshot | None = None,
snapshot_callback: SnapshotCallback | None = None,
) -> dict[str, Any]:View on GitHub (pinned to e318778c9b)
Solutions
- Make run() return a dict keyed by the component's declared output sockets, e.g. {"documents": docs}
- Check the @component decorator output type declarations match the returned dict keys
- Wrap third-party callables to convert their results into a dict
Example fix
// before
def run(self, docs):
return docs
// after
def run(self, docs):
return {"documents": docs} Defensive patterns
Strategy: validation
Validate before calling
out = my_component.run(documents=docs)
if not isinstance(out, Mapping):
raise TypeError("run() must return a dict keyed by output sockets") Type guard
from collections.abc import Mapping
def returns_mapping(out) -> bool:
return isinstance(out, Mapping) Try / catch
from haystack.core.errors import PipelineRuntimeError
try:
result = pipeline.run(inputs)
except PipelineRuntimeError as e:
if "invalid output" in str(e).lower():
logger.error("Fix component run() to return a dict: %s", e)
else:
raise Prevention
- Always return a dict whose keys match the component's declared output sockets
- Unit-test custom components' return types
- Use the @component decorator's set_output_types to keep the contract explicit
When it happens
Trigger: A custom component whose run() returns e.g. ["a", "b"], "text", or None instead of {"output": ...}; a mis-wrapped component from another framework.
Common situations: Hand-written components returning bare values, refactored components whose return type changed, third-party components not adapted to Haystack's Component contract.
Related errors
- tools must be a list of Tool and/or Toolset objects, a Tools
- MarkdownHeaderSplitter only works with text documents but co
- Error while unmarshalling serialized pipeline data. This is
- Component instance cannot be added to the pipeline more than
- A component named '{name}' already exists in this pipeline:
AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30).
Data as JSON: /api/errors/96e13f6f58d7513a.
Report an issue: GitHub.