From f35c2f2baad42c9b1457b5578efeeeb49398e010 Mon Sep 17 00:00:00 2001 From: Kadir Can Ozden <101993364+bysiber@users.noreply.github.com> Date: Fri, 20 Feb 2026 05:26:51 +0300 Subject: [PATCH 1/2] code: use current excinfo when formatting chained BaseExceptionGroup In repr_excinfo, the BaseExceptionGroup branch incorrectly uses the original excinfo instead of excinfo_ (which tracks the current exception in the chain). This means that when walking __cause__ or __context__ chains, filter_excinfo_traceback and format_exception always operate on the first exception rather than the current one. The non-group branch on the else side already uses excinfo_ correctly. --- src/_pytest/_code/code.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/_pytest/_code/code.py b/src/_pytest/_code/code.py index 4cf99a77340..67ccc2ac661 100644 --- a/src/_pytest/_code/code.py +++ b/src/_pytest/_code/code.py @@ -1188,11 +1188,11 @@ def repr_excinfo(self, excinfo: ExceptionInfo[BaseException]) -> ExceptionChainR reprtraceback: ReprTraceback | ReprTracebackNative if isinstance(e, BaseExceptionGroup): # don't filter any sub-exceptions since they shouldn't have any internal frames - traceback = filter_excinfo_traceback(self.tbfilter, excinfo) + traceback = filter_excinfo_traceback(self.tbfilter, excinfo_) reprtraceback = ReprTracebackNative( format_exception( - type(excinfo.value), - excinfo.value, + type(excinfo_.value), + excinfo_.value, traceback[0]._rawentry if traceback else None, ) ) From 66d902b02b59ecb99b3967c5e711cd42eff919d8 Mon Sep 17 00:00:00 2001 From: Kadir Can Ozden <101993364+bysiber@users.noreply.github.com> Date: Fri, 20 Feb 2026 15:49:10 +0300 Subject: [PATCH 2/2] Add regression test for chained ExceptionGroup using wrong excinfo Test that when a BaseExceptionGroup appears as a chained exception, the traceback output correctly shows both the ExceptionGroup and the outer exception, using the current excinfo_ rather than the original. --- testing/code/test_excinfo.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/testing/code/test_excinfo.py b/testing/code/test_excinfo.py index 70499fec893..4c0d67fac37 100644 --- a/testing/code/test_excinfo.py +++ b/testing/code/test_excinfo.py @@ -2009,3 +2009,35 @@ def test_check_error_notes_failure( with pytest.raises(AssertionError): with pytest.raises(type(error), match=match): raise error + + +def test_chained_exceptiongroup_uses_current_excinfo(pytester: Pytester) -> None: + """Regression test: when a BaseExceptionGroup appears as a chained exception, + repr_excinfo should use excinfo_ (current) not excinfo (original outer). + + With the bug, the traceback and type info from the outer exception was used + instead of the chained ExceptionGroup, potentially causing wrong output or + a mismatch between the displayed exception type and its traceback. + """ + pytester.makepyfile( + """ + import sys + if sys.version_info < (3, 11): + from exceptiongroup import ExceptionGroup + + def test_chained_eg(): + try: + raise ExceptionGroup("inner", [TypeError("from inner")]) + except BaseException: + raise ValueError("outer") + """ + ) + result = pytester.runpytest() + result.stdout.fnmatch_lines( + [ + "*ExceptionGroup*", + "*TypeError: from inner*", + "*During handling of the above exception, another exception occurred:*", + "*ValueError: outer*", + ] + )