From dad3851d55f9e87e35c18163dec664dd12dcad68 Mon Sep 17 00:00:00 2001 From: Kadir Can Ozden <101993364+bysiber@users.noreply.github.com> Date: Fri, 20 Feb 2026 05:26:13 +0300 Subject: [PATCH 1/3] raises: fix stale loop variable in RaisesGroup error reporting In _check_exceptions, the diagnostic loop at line 1368 uses i_exp (last value from the earlier enumerate loop) instead of i_failed (the current loop variable). This causes incorrect result lookups when building the failure message for unmatched expected exceptions. --- src/_pytest/raises.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_pytest/raises.py b/src/_pytest/raises.py index 7c246fde280..c979b599df3 100644 --- a/src/_pytest/raises.py +++ b/src/_pytest/raises.py @@ -1365,7 +1365,7 @@ def _check_exceptions( f"\n{indent_1}{self._repr_expected(self.expected_exceptions[i_failed])}" ) for i_actual, actual in enumerate(actual_exceptions): - if results.get_result(i_exp, i_actual) is None: + if results.get_result(i_failed, i_actual) is None: # we print full repr of match target s += ( f"\n{indent_2}It matches {backquote(repr(actual))} which was paired with " From 2063856b1d26a094e87163afb8e9a6017ee4a7ed Mon Sep 17 00:00:00 2001 From: Kadir Can Ozden <101993364+bysiber@users.noreply.github.com> Date: Fri, 20 Feb 2026 15:47:24 +0300 Subject: [PATCH 2/3] Add regression test for stale loop variable in RaisesGroup error message Tests that the error message for failed expected exceptions uses the correct index (i_failed) rather than a stale i_exp from a prior loop. --- testing/python/raises_group.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/testing/python/raises_group.py b/testing/python/raises_group.py index e5e3b5cd2dc..e6fe2086529 100644 --- a/testing/python/raises_group.py +++ b/testing/python/raises_group.py @@ -1355,3 +1355,31 @@ def test_tuples() -> None: ), ): RaisesGroup((ValueError, IndexError)) # type: ignore[call-overload] + + +def test_stale_loop_variable_in_error_message() -> None: + """Regression test: error message for failed expected exceptions should + reference the correct expected index, not a stale loop variable from + a previous enumerate() loop.""" + # We need multiple expected exceptions where a non-last expected fails. + # Expected: [RaisesExc(ValueError, match='foo'), TypeError, RuntimeError] + # Actual: [ValueError('bar'), TypeError(), KeyError()] + # Greedy matching: TypeError() pairs with TypeError (index 1->1) + # Failed expected: index 0 (match fails) and index 2 (KeyError is not RuntimeError) + # Remaining actual: index 0 (ValueError('bar')) and index 2 (KeyError()) + # + # With the stale-variable bug, the error message for the first failed + # expected (index 0) would use results from the last expected (index 2) + # instead of its own, potentially showing incorrect "It matches" lines. + with pytest.raises(Failed) as exc_info: + with RaisesGroup( + RaisesExc(ValueError, match="foo"), TypeError, RuntimeError + ): + raise ExceptionGroup( + "", + [ValueError("bar"), TypeError(), KeyError()], + ) + # Verify the error message references the correct expected exceptions + message = str(exc_info.value) + assert "RaisesExc(ValueError, match='foo')" in message + assert "RuntimeError" in message From 4c947b384c1fe70ac08923863f8a5439f3fe2c0f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 12:47:53 +0000 Subject: [PATCH 3/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- testing/python/raises_group.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/testing/python/raises_group.py b/testing/python/raises_group.py index e6fe2086529..5f6dbfebb79 100644 --- a/testing/python/raises_group.py +++ b/testing/python/raises_group.py @@ -1372,9 +1372,7 @@ def test_stale_loop_variable_in_error_message() -> None: # expected (index 0) would use results from the last expected (index 2) # instead of its own, potentially showing incorrect "It matches" lines. with pytest.raises(Failed) as exc_info: - with RaisesGroup( - RaisesExc(ValueError, match="foo"), TypeError, RuntimeError - ): + with RaisesGroup(RaisesExc(ValueError, match="foo"), TypeError, RuntimeError): raise ExceptionGroup( "", [ValueError("bar"), TypeError(), KeyError()],