home-assistant/core · error · InvalidPipelineStagesError

validation-error

validation-error

Error message

Invalid stage combination: start={start_stage}, end={end_stage}

What it means

InvalidPipelineStagesError raised in PipelineRun.__post_init__ when the requested run stages are misordered: in the wake -> stt -> intent -> tts pipeline, the end stage appears before the start stage in PIPELINE_STAGE_ORDER, so the run would be empty/negative. Its message ('Invalid stage combination: start={start_stage}, end={end_stage}') carries the offending pair.

Source

Thrown at homeassistant/components/assist_pipeline/pipeline.py:608

    _intent_agent_only = False
    """If request should only be handled by agent.

    Ignores sentence triggers and local processing.
    """

    _streamed_response_text = False
    """If the conversation agent streamed response text to TTS result."""

    def __post_init__(self) -> None:
        """Set language for pipeline."""
        self.language = self.pipeline.language or self.hass.config.language

        # wake -> stt -> intent -> tts
        if PIPELINE_STAGE_ORDER.index(self.end_stage) < PIPELINE_STAGE_ORDER.index(
            self.start_stage
        ):
            raise InvalidPipelineStagesError(self.start_stage, self.end_stage)

        pipeline_data = self.hass.data[KEY_ASSIST_PIPELINE]
        if self.pipeline.id not in pipeline_data.pipeline_debug:
            pipeline_data.pipeline_debug[self.pipeline.id] = LimitedSizeDict(
                size_limit=STORED_PIPELINE_RUNS
            )
        pipeline_data.pipeline_debug[self.pipeline.id][self.id] = PipelineRunDebug()
        pipeline_data.pipeline_runs.add_run(self)

        # Initialize with audio settings
        if self.audio_settings.needs_processor and (self.audio_enhancer is None):
            # Default audio enhancer
            self.audio_enhancer = MicroVadSpeexEnhancer(
                self.audio_settings.auto_gain_dbfs,
                self.audio_settings.noise_suppression_level,
                self.audio_settings.is_vad_enabled,
            )

View on GitHub (pinned to 58a3fdb3ea)

Solutions

  1. Order stages along wake -> stt -> intent -> tts (start must not come after end).
  2. Validate stage names and order against PIPELINE_STAGE_ORDER before constructing PipelineRun.
  3. If you only need a suffix/slice of the pipeline, pick start/end from the ordered constant list programmatically.

Example fix

# before
run = PipelineRun(hass, pipeline, start_stage="intent", end_stage="stt")
# after
run = PipelineRun(hass, pipeline, start_stage="stt", end_stage="tts")
Defensive patterns

Strategy: validation

Validate before calling

from homeassistant.components.assist_pipeline.pipeline import PIPELINE_STAGE_ORDER

def stages_valid(start: str, end: str) -> bool:
    return PIPELINE_STAGE_ORDER.index(end) >= PIPELINE_STAGE_ORDER.index(start)

Try / catch

Validate stage order (or catch InvalidPipelineStagesError) when accepting user-specified run stages, and normalize/reject before constructing PipelineRun.

Prevention

When it happens

Trigger: Constructing PipelineRun with e.g. start_stage='intent' and end_stage='stt', or passing stage names from websocket options that were not validated (including case mismatches yielding wrong indices indirectly).

Common situations: Programmatic pipeline runs with hand-built stage arguments; frontends exposing free-text stage pickers; code updated after stage constants were renamed/reordered.

Related errors


AI-assisted analysis of home-assistant/core@58a3fdb3ea (2026-08-14). Data as JSON: /api/errors/9af75103001fa5ff. Report an issue: GitHub.