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
- Set num_steps: MultiStepQueryEngine(..., num_steps=3, early_stopping=False).
- Or keep early_stopping=True (default) and let the stop function decide, in which case num_steps stays optional.
- Validate config before construction in code that builds engines from a config dict (see validation snippet).
- 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
- Whenever you set early_stopping=False, set num_steps in the same change — treat them as coupled.
- Validate engine configs from files/dicts before constructing MultiStepQueryEngine.
- Add a config-schema check (e.g. pydantic settings model) for engine constructors that accept None defaults.
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
- EmptyIndex only supports response_mode=generation.
- Unknown retriever mode: {retriever_mode}
- Unknown retriever mode: {retriever_mode}
- Cannot initialize from a vector store that does not store te
- llm must start with str 'local' or of type LLM or BaseLangua
AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15).
Data as JSON: /api/errors/63706668cf80fdc6.
Report an issue: GitHub.