pytest-dev/pytest · error · ValueError
`allow_unwrapped=True` has no effect when expecting a…
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
Raised by RaisesGroup.__init__ when allow_unwrapped=True is passed to a RaisesGroup whose expected_exception is itself a RaisesGroup (nested). allow_unwrapped only affects the outermost unwrap decision, so setting it on a RaisesGroup that already expects a RaisesGroup is a no-op and signals user confusion. pytest points the user to put allow_unwrapped on the inner RaisesGroup or to use flatten_subgroups.
Solutions
- Move allow_unwrapped=True to the inner RaisesGroup where unwrapping should occur.
- Remove allow_unwrapped if you do not need single-exception unwrapping at all.
- If you want to ignore subgroup nesting structure, use flatten_subgroups=True on the outer RaisesGroup instead.
Example fix
// before
with pytest.raises(RaisesGroup(RaisesGroup(ValueError), allow_unwrapped=True)):
...
// after
with pytest.raises(RaisesGroup(RaisesGroup(ValueError, allow_unwrapped=True))):
...
// or flatten structure:
with pytest.raises(RaisesGroup(ValueError, flatten_subgroups=True)):
... Defensive patterns
Strategy: validation
Validate before calling
from _pytest.raises import RaisesGroup
if allow_unwrapped and isinstance(expected_exception, RaisesGroup):
raise SystemExit('move allow_unwrapped to the inner RaisesGroup, or use flatten_subgroups') Type guard
def allow_unwrapped_outer_ok(expected_exception, allow_unwrapped) -> bool:
from _pytest.raises import RaisesGroup
return (not allow_unwrapped) or not isinstance(expected_exception, RaisesGroup) Prevention
- Set allow_unwrapped only on the RaisesGroup whose immediate value may be a bare exception.
- Prefer flatten_subgroups=True when you want to ignore subgroup structure.
- Document nested RaisesGroup construction in helper code.
When it happens
Trigger: RaisesGroup(RaisesGroup(ValueError), allow_unwrapped=True); nesting RaisesGroup inside RaisesGroup and setting allow_unwrapped on the outer one. The isinstance(expected_exception, RaisesGroup) check fires.
Common situations: Building nested group matchers programmatically and copying allow_unwrapped through every level; misunderstanding which level the unwrap applies to.
Related errors
- `allow_unwrapped=True` bypasses the `match` and `check`…
- You cannot specify a nested structure inside a RaisesGroup…
- You cannot specify multiple exceptions with…
- Expected , but got . RaisesGroup does not support tuples of…
- Only `ExceptionGroup[Exception]` or…
AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11).
Data as JSON: /api/errors/7b7580126be7ec05.
Report an issue: GitHub.
Appendix: 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 0d6fbdeffa)