pytest-dev/pytest · error · ValueError

`allow_unwrapped=True` has no effect when expecting a `Raise

Error message

`allow_unwrapped=True` has no effect when expecting a `RaisesGroup`. You might want it in the expected `RaisesGroup`, or `flatten_subgroups=True` if you don't care about the structure.

What it means

allow_unwrapped=True on a RaisesGroup whose sole expected is itself a RaisesGroup has no effect — the outer group always expects a group, so unwrapping at that level is meaningless. The flag belongs on the inner RaisesGroup, or use flatten_subgroups.

Source

Thrown at src/_pytest/raises.py:978

        # it to avoid an error when passing it to super().__init__
        check = cast(
            "Callable[[BaseExceptionGroup[ExcT_1|BaseExcT_1|BaseExceptionGroup[BaseExcT_2]]], bool]",
            check,
        )
        super().__init__(match=match, check=check)
        self.allow_unwrapped = allow_unwrapped
        self.flatten_subgroups: bool = flatten_subgroups
        self.is_baseexception = False

        if allow_unwrapped and other_exceptions:
            raise ValueError(
                "You cannot specify multiple exceptions with `allow_unwrapped=True.`"
                " If you want to match one of multiple possible exceptions you should"
                " use a `RaisesExc`."
                " E.g. `RaisesExc(check=lambda e: isinstance(e, (...)))`",
            )
        if allow_unwrapped and isinstance(expected_exception, RaisesGroup):
            raise ValueError(
                "`allow_unwrapped=True` has no effect when expecting a `RaisesGroup`."
                " You might want it in the expected `RaisesGroup`, or"
                " `flatten_subgroups=True` if you don't care about the structure.",
            )
        if allow_unwrapped and (match is not None or check is not None):
            raise ValueError(
                "`allow_unwrapped=True` bypasses the `match` and `check` parameters"
                " if the exception is unwrapped. If you intended to match/check the"
                " exception you should use a `RaisesExc` object. If you want to match/check"
                " the exceptiongroup when the exception *is* wrapped you need to"
                " do e.g. `if isinstance(exc.value, ExceptionGroup):"
                " assert RaisesGroup(...).matches(exc.value)` afterwards.",
            )

        self.expected_exceptions: tuple[
            type[BaseExcT_co] | RaisesExc[BaseExcT_co] | RaisesGroup[BaseException], ...
        ] = tuple(
            self._parse_excgroup(e, "a BaseException type, RaisesExc, or RaisesGroup")

View on GitHub (pinned to 98b357f69e)

Solutions

  1. Move allow_unwrapped=True to the inner RaisesGroup: RaisesGroup(RaisesGroup(ValueError, allow_unwrapped=True)).
  2. If you don't care about nesting structure, use flatten_subgroups=True on the outer group instead.
  3. Reconsider whether you need nesting at all — a flat RaisesGroup(ValueError, allow_unwrapped=True) may suffice.

Example fix

// before
RaisesGroup(RaisesGroup(ValueError), allow_unwrapped=True)
// after
RaisesGroup(RaisesGroup(ValueError, allow_unwrapped=True))
Defensive patterns

Strategy: validation

Validate before calling

if allow_unwrapped and isinstance(expected_exception, RaisesGroup):
    raise ValueError('move allow_unwrapped to the inner RaisesGroup')
RaisesGroup(expected_exception, allow_unwrapped=allow_unwrapped)

Prevention

When it happens

Trigger: Calling RaisesGroup(RaisesGroup(ValueError), allow_unwrapped=True). Hits raises.py:978.

Common situations: Developer nests groups to assert structure but puts allow_unwrapped on the wrong (outer) level; confusion about which level may receive an unwrapped exception.

Related errors


AI-assisted analysis of pytest-dev/pytest@98b357f69e (2026-08-04). Data as JSON: /data/errors/7b7580126be7ec05.json. Report an issue: GitHub.