deepset-ai/haystack · error · PipelineRuntimeError

PipelineRuntimeError.from_invalid_output(component_name, ins

Error message

PipelineRuntimeError.from_invalid_output(component_name, instance.__class__, outputs)

What it means

PipelineRuntimeError.from_invalid_output is raised in _run_component_async (pipeline.py:591) when a component's run returns a value that is not a Mapping (dict-like). Haystack components must return a dictionary of output sockets so the pipeline can distribute outputs to downstream connections. A non-mapping return value makes output routing impossible.

Source

Thrown at haystack/core/pipeline/pipeline.py:591

            component_name=component_name, instance=instance, inputs=component_inputs, parent_span=parent_span
        ) as span:
            # deepcopy inputs before passing to the tracer so that even if a tracer mutates them
            # the component always receives the original unmodified values
            component_inputs_copy = _deepcopy_with_exceptions(component_inputs)
            span.set_content_tag(_COMPONENT_INPUT, component_inputs)
            logger.info("Running component {component_name}", component_name=component_name)

            try:
                # For sync-only components, _run_component_async dispatches to a thread via asyncio.to_thread,
                # which copies the current contextvars context — preserving e.g. the active tracing span.
                outputs = await _execute_component_async(instance, **component_inputs_copy)
            except Exception as error:
                raise PipelineRuntimeError.from_exception(component_name, instance.__class__, error) from error

            component_visits[component_name] += 1

            if not isinstance(outputs, Mapping):
                raise PipelineRuntimeError.from_invalid_output(component_name, instance.__class__, outputs)

            _validate_component_output_keys(component_name, component, outputs)

            span.set_tag(_COMPONENT_VISITS, component_visits[component_name])
            span.set_content_tag(_COMPONENT_OUTPUT, outputs)

            return outputs

    @staticmethod
    async def _wait_for_tasks(
        running_tasks: dict[asyncio.Task, str], scheduled_components: set[str], *, return_when: str
    ) -> AsyncIterator[dict[str, Any]]:
        """
        Waits for running tasks to finish and yields their partial outputs.

        :param running_tasks: Mapping of in-flight tasks to the name of the component they run. Finished tasks are
            removed in place.
        :param scheduled_components: Set of component names that are scheduled but not yet finished. Finished

View on GitHub (pinned to e318778c9b)

Solutions

  1. Change the component's run() to return a dict keyed by declared output socket names.
  2. If the result can be absent, return an empty dict or a dict with an explicit key rather than None.
  3. Add a unit test asserting isinstance(result, Mapping) for the component.

Example fix

# before
class Sum:
    @component.output_types(total=int)
    def run(self, a: int, b: int):
        return a + b  # not a Mapping
# after
class Sum:
    @component.output_types(total=int)
    def run(self, a: int, b: int):
        return {"total": a + b}
Defensive patterns

Strategy: type-guard

Validate before calling

result = my_component.run(**inputs)
if not isinstance(result, Mapping):
    raise TypeError('component must return a Mapping')

Type guard

from collections.abc import Mapping
def returns_mapping(result) -> bool:
    return isinstance(result, Mapping)

Try / catch

try:
    result = pipe.run(data)
except PipelineRuntimeError as e:
    if 'did not return a Mapping' in str(e):
        print('fix the component return type named in the message')

Prevention

When it happens

Trigger: A custom component's run() returns a list, tuple, string, DataFrame, or None instead of a dict; a decorator-refactored component whose return type changed.

Common situations: Hand-written components returning bare values or structured objects; components migrated from older Haystack versions with different return conventions; code that returns Optional[dict] and hits the None path.

Related errors


AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30). Data as JSON: /api/errors/510c2279e75d0054. Report an issue: GitHub.