run-llama/llama_index · error · ValueError

Must specify num_steps if early_stopping is False.

Error message

Must specify num_steps if early_stopping is False.

What it means

MultiStepQueryEngine's constructor enforces a coherence rule: if early_stopping is False, the loop must know exactly when to stop, so num_steps must be a positive int. Omitting num_steps while passing early_stopping=False raises ValueError('Must specify num_steps if early_stopping is False.') before any query runs.

Source

Thrown at llama-index-core/llama_index/core/query_engine/multistep_query_engine.py:70

        num_steps: Optional[int] = 3,
        early_stopping: bool = True,
        index_summary: str = "None",
        stop_fn: Optional[Callable[[Dict], bool]] = None,
    ) -> None:
        self._query_engine = query_engine
        self._query_transform = query_transform
        self._response_synthesizer = response_synthesizer or get_response_synthesizer(
            callback_manager=self._query_engine.callback_manager
        )

        self._index_summary = index_summary
        self._num_steps = num_steps
        self._early_stopping = early_stopping
        # TODO: make interface to stop function better
        self._stop_fn = stop_fn or default_stop_fn
        # num_steps must be provided if early_stopping is False
        if not self._early_stopping and self._num_steps is None:
            raise ValueError("Must specify num_steps if early_stopping is False.")

        callback_manager = self._query_engine.callback_manager
        super().__init__(callback_manager)

    def _get_prompt_modules(self) -> PromptMixinType:
        """Get prompt sub-modules."""
        return {
            "response_synthesizer": self._response_synthesizer,
            "query_transform": self._query_transform,
        }

    def _query(self, query_bundle: QueryBundle) -> RESPONSE_TYPE:
        with self.callback_manager.event(
            CBEventType.QUERY, payload={EventPayload.QUERY_STR: query_bundle.query_str}
        ) as query_event:
            nodes, source_nodes, metadata = self._query_multistep(query_bundle)

            final_response = self._response_synthesizer.synthesize(

View on GitHub (pinned to afd0fef371)

Solutions

  1. Set num_steps: MultiStepQueryEngine(..., num_steps=3, early_stopping=False).
  2. Or keep early_stopping=True (default) and let the stop function decide, in which case num_steps stays optional.
  3. Validate config before construction in code that builds engines from a config dict (see validation snippet).
  4. Pick num_steps based on how many query rewrites the task needs — 2-4 covers most multi-hop QA setups.

Example fix

# before
engine = MultiStepQueryEngine(
    query_engine=inner,
    query_transform=MultiStepQueryTransform(index_summary=summary),
    early_stopping=False,        # num_steps omitted -> ValueError
)

# after
engine = MultiStepQueryEngine(
    query_engine=inner,
    query_transform=MultiStepQueryTransform(index_summary=summary),
    num_steps=3,                  # explicit step budget
    early_stopping=False,
)
Defensive patterns

Strategy: validation

Validate before calling

def build_multistep_engine(inner, transform, *, num_steps=None, early_stopping=True, **kw):
    if not early_stopping and num_steps is None:
        raise ValueError("num_steps is required when early_stopping=False")
    from llama_index.core.query_engine import MultiStepQueryEngine
    return MultiStepQueryEngine(
        query_engine=inner, query_transform=transform,
        num_steps=num_steps, early_stopping=early_stopping, **kw,
    )

Type guard

def is_valid_multistep_config(num_steps, early_stopping) -> bool:
    return early_stopping or (isinstance(num_steps, int) and num_steps > 0)

Prevention

When it happens

Trigger: MultiStepQueryEngine(query_engine=..., query_transform=MultiStepQueryTransform(...), early_stopping=False) with num_steps left at its default None. Also triggered by passing num_steps=None explicitly, or by copying example code that relied on defaults after changing early_stopping.

Common situations: Disabling early stopping to force a fixed exploration depth but forgetting the step budget; upgrading code where an older version defaulted num_steps; interactive experimentation where early_stopping is toggled per run while num_steps is only set in one branch.

Related errors


AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15). Data as JSON: /api/errors/63706668cf80fdc6. Report an issue: GitHub.