{"record":{"id":"ec0fcfbec950d29a","repo":"pytest-dev/pytest","slug":"allow-unwrapped-true-bypasses-the-match-and-c","errorCode":null,"errorMessage":"`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.","messagePattern":"`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\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/_pytest/raises.py","lineNumber":984,"sourceCode":"        self.allow_unwrapped = allow_unwrapped\n        self.flatten_subgroups: bool = flatten_subgroups\n        self.is_baseexception = False\n\n        if allow_unwrapped and other_exceptions:\n            raise ValueError(\n                \"You cannot specify multiple exceptions with `allow_unwrapped=True.`\"\n                \" If you want to match one of multiple possible exceptions you should\"\n                \" use a `RaisesExc`.\"\n                \" E.g. `RaisesExc(check=lambda e: isinstance(e, (...)))`\",\n            )\n        if allow_unwrapped and isinstance(expected_exception, RaisesGroup):\n            raise ValueError(\n                \"`allow_unwrapped=True` has no effect when expecting a `RaisesGroup`.\"\n                \" You might want it in the expected `RaisesGroup`, or\"\n                \" `flatten_subgroups=True` if you don't care about the structure.\",\n            )\n        if allow_unwrapped and (match is not None or check is not None):\n            raise ValueError(\n                \"`allow_unwrapped=True` bypasses the `match` and `check` parameters\"\n                \" if the exception is unwrapped. If you intended to match/check the\"\n                \" exception you should use a `RaisesExc` object. If you want to match/check\"\n                \" the exceptiongroup when the exception *is* wrapped you need to\"\n                \" do e.g. `if isinstance(exc.value, ExceptionGroup):\"\n                \" assert RaisesGroup(...).matches(exc.value)` afterwards.\",\n            )\n\n        self.expected_exceptions: tuple[\n            type[BaseExcT_co] | RaisesExc[BaseExcT_co] | RaisesGroup[BaseException], ...\n        ] = tuple(\n            self._parse_excgroup(e, \"a BaseException type, RaisesExc, or RaisesGroup\")\n            for e in (\n                expected_exception,\n                *other_exceptions,\n            )\n        )\n","sourceCodeStart":966,"sourceCodeEnd":1002,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/raises.py#L966-L1002","documentation":"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.","triggerScenarios":"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)`.","commonSituations":"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.","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."],"exampleFix":"// before\nwith pytest.raises(RaisesGroup(ValueError, allow_unwrapped=True, match='boom')) as ei:\n    ...\n// after\nwith pytest.raises(RaisesExc(ValueError, match='boom')) as ei:\n    ...\n// or conditional post-check:\nwith pytest.raises(RaisesGroup(ValueError, allow_unwrapped=True)) as ei:\n    ...\nif isinstance(ei.value, ExceptionGroup):\n    assert RaisesGroup(ValueError, match='boom').matches(ei.value)","handlingStrategy":"validation","validationCode":"if allow_unwrapped and (match is not None or check is not None):\n    raise SystemExit('drop allow_unwrapped, or move match/check into a RaisesExc')","typeGuard":"def allow_unwrapped_match_check_ok(allow_unwrapped, match, check) -> bool:\n    return (not allow_unwrapped) or (match is None and check is None)","tryCatchPattern":null,"preventionTips":["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."],"tags":["pytest","raises","raisesgroup","allow-unwrapped","match-check","validation"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}