pytest-dev/pytest · error · ValueError
`allow_unwrapped=True` bypasses the `match` and `check`…
Error message
`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.
What it means
Raised by RaisesGroup.__init__ when allow_unwrapped=True is combined with a non-None match or check argument. If the raised exception is unwrapped (a bare exception instead of a group), the match regex and check callback target the group, not the inner exception, so they would be silently bypassed — a latent bug. pytest requires RaisesExc for matching an unwrapped exception, and suggests asserting on the group afterward when the exception is actually wrapped.
Solutions
- If you want to match/check the (possibly unwrapped) exception, drop allow_unwrapped and use RaisesExc(ValueError, match='x').
- Keep allow_unwrapped=True and remove match/check; then after the with-block, assert on the group only when wrapped: if isinstance(excinfo.value, ExceptionGroup): assert RaisesGroup(...).matches(excinfo.value).
- Split into two cases: RaisesExc for the unwrapped path and RaisesGroup for the wrapped path.
Example fix
// before
with pytest.raises(RaisesGroup(ValueError, allow_unwrapped=True, match='boom')) as ei:
...
// after
with pytest.raises(RaisesExc(ValueError, match='boom')) as ei:
...
// or conditional post-check:
with pytest.raises(RaisesGroup(ValueError, allow_unwrapped=True)) as ei:
...
if isinstance(ei.value, ExceptionGroup):
assert RaisesGroup(ValueError, match='boom').matches(ei.value) Defensive patterns
Strategy: validation
Validate before calling
if allow_unwrapped and (match is not None or check is not None):
raise SystemExit('drop allow_unwrapped, or move match/check into a RaisesExc') Type guard
def allow_unwrapped_match_check_ok(allow_unwrapped, match, check) -> bool:
return (not allow_unwrapped) or (match is None and check is None) Prevention
- Never combine allow_unwrapped=True with match= or check= on a RaisesGroup.
- Use RaisesExc(ValueError, match='x') to assert on an unwrapped exception's message.
- Post-assert on the group conditionally when the exception may be wrapped.
When it happens
Trigger: RaisesGroup(ValueError, allow_unwrapped=True, match='x'); RaisesGroup(ValueError, allow_unwrapped=True, check=lambda e: True). Fires on `allow_unwrapped and (match is not None or check is not None)`.
Common situations: Wanting to assert both 'accept a lone ValueError' AND 'its message matches X'; copying match= from a raises() call into a RaisesGroup with allow_unwrapped.
Related errors
- `allow_unwrapped=True` has no effect when expecting a…
- You cannot specify multiple exceptions with…
- Expected , but got . RaisesGroup does not support tuples of…
- You cannot specify a nested structure inside a RaisesGroup…
- Only `ExceptionGroup[Exception]` or…
AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11).
Data as JSON: /api/errors/ec0fcfbec950d29a.
Report an issue: GitHub.
Appendix: source
Thrown at src/_pytest/raises.py:984
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")
for e in (
expected_exception,
*other_exceptions,
)
)
View on GitHub (pinned to 0d6fbdeffa)