Skip to content

wait_chain: reject empty strategy list with ValueError instead of IndexError#646

Merged
mergify[bot] merged 1 commit into
jd:mainfrom
HrachShah:fix/wait-chain-empty-strategies-raises
Jul 1, 2026
Merged

wait_chain: reject empty strategy list with ValueError instead of IndexError#646
mergify[bot] merged 1 commit into
jd:mainfrom
HrachShah:fix/wait-chain-empty-strategies-raises

Conversation

@HrachShah

Copy link
Copy Markdown
Contributor

Summary

wait_chain() accepts a variadic list of strategies, but did not validate that the list is non-empty. The bad configuration only surfaced at the first call site of the resulting wait function, where self.strategies[-1] raised IndexError: tuple index out of range. This is confusing because the programmer error is at construction time, not at the moment the wait function is invoked inside a running retry.

This change makes wait_chain() raise a clear ValueError("wait_chain() requires at least one strategy") at construction time.

Repro of the pre-fix behaviour

>>> import tenacity
>>> fn = tenacity.wait_chain()
>>> from tenacity import RetryCallState
>>> s = RetryCallState(None, None, (), {})
>>> s.attempt_number = 1
>>> s.set_result(None)
>>> fn(s)
Traceback (most recent call last):
  ...
IndexError: tuple index out of range

With the patch, the same sequence raises ValueError on the wait_chain() call itself.

Changes

  • tenacity/wait.py: wait_chain.__init__ now raises ValueError when *strategies is empty.
  • tests/test_tenacity.py: added test_wait_chain_requires_at_least_one_strategy, which covers wait_chain() directly, Retrying(... wait=wait_chain()) at construction, and confirms a non-empty chain still works.
  • releasenotes/notes/fix-wait-chain-empty-strategies-...yaml: short user-facing note.

Tests

  • New test fails on the pre-fix code (AssertionError: ValueError not raised) and passes on the patched code.
  • Full tests/test_tenacity.py run: 128 passed.
  • ruff check: clean.
  • ruff format --check: clean.

…exError

Calling wait_chain() with no strategies stored an empty tuple in
self.strategies. The first call to __call__ then evaluated
min(max(1, 1), 0) == 0, so self.strategies[wait_func_no - 1]
turned into self.strategies[-1] and raised IndexError, which is
opaque for what is really a programmer error at construction time.

Validate in __init__ and raise ValueError('wait_chain() requires
at least one strategy') so the failure happens at the point where
the bad configuration is created, not later when the wait function
is first evaluated inside a running retry.
@mergify

mergify Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • Entered queue2026-07-01 08:52 UTC · Rule: default · triggered by rule autoqueue
  • Checks skipped · PR is already up-to-date
  • Merged2026-07-01 08:52 UTC · at ce53bc85245373a1b8b605ae78f5f2bc2de46fe2 · squash

This pull request spent 10 seconds in the queue, including 2 seconds running CI.

Required conditions to merge

@mergify mergify Bot merged commit 4ee186c into jd:main Jul 1, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants