{"record":{"id":"26c59368930b4c34","repo":"pytest-dev/pytest","slug":"you-cannot-specify-multiple-exceptions-with-allow","errorCode":null,"errorMessage":"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, (...)))`","messagePattern":"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, \\(\\.\\.\\.\\)\\)\\)`","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/_pytest/raises.py","lineNumber":971,"sourceCode":"            Callable[[BaseExceptionGroup[BaseExcT_1]], bool]\n            | Callable[[ExceptionGroup[ExcT_1]], bool]\n            | None\n        ) = None,\n    ):\n        # The type hint on the `self` and `check` parameters uses different formats\n        # that are *very* hard to reconcile while adhering to the overloads, so we cast\n        # it to avoid an error when passing it to super().__init__\n        check = cast(\n            \"Callable[[BaseExceptionGroup[ExcT_1|BaseExcT_1|BaseExceptionGroup[BaseExcT_2]]], bool]\",\n            check,\n        )\n        super().__init__(match=match, check=check)\n        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):\"","sourceCodeStart":953,"sourceCodeEnd":989,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/raises.py#L953-L989","documentation":"Raised by RaisesGroup.__init__ when allow_unwrapped=True is combined with more than one expected exception (the other_exceptions branch). allow_unwrapped means the matcher will accept a single non-group exception by wrapping it implicitly; with multiple candidate types that single exception could not be disambiguated. pytest steers users to RaisesExc(check=lambda e: isinstance(e, (...))) for 'one of several' matching.","triggerScenarios":"RaisesGroup(ValueError, KeyError, allow_unwrapped=True); RaisesGroup((ValueError, KeyError), allow_unwrapped=True); or any RaisesGroup where other_exceptions is non-empty and allow_unwrapped is set.","commonSituations":"Adapting a RaisesGroup to also accept a lone exception (unwrapped) while still wanting to match a set of candidate types; migrating from raises(ValueError, KeyError) to group semantics.","solutions":["Drop allow_unwrapped and let the exception arrive already wrapped in an ExceptionGroup.","Keep allow_unwrapped=True but expect a single type, and move multi-type matching into a check: RaisesExc(check=lambda e: isinstance(e, (ValueError, KeyError))).","Wrap the group matcher so it accepts either shape via a custom check on RaisesGroup itself."],"exampleFix":"// before\nwith pytest.raises(RaisesGroup(ValueError, KeyError, allow_unwrapped=True)):\n    ...\n// after\nwith pytest.raises(RaisesExc(check=lambda e: isinstance(e, (ValueError, KeyError)))):\n    ...","handlingStrategy":"validation","validationCode":"n = 0 if expected_exception is None else (len(expected_exception) if isinstance(expected_exception, tuple) else 1)\nn += len(other_exceptions)\nassert not (allow_unwrapped and n > 1), 'allow_unwrapped=True requires exactly one expected exception'","typeGuard":"def raisesgroup_unwrapped_single(expected_exception, other_exceptions, allow_unwrapped) -> bool:\n    n = 0 if expected_exception is None else (len(expected_exception) if isinstance(expected_exception, tuple) else 1)\n    n += len(other_exceptions or ())\n    return (not allow_unwrapped) or n <= 1","tryCatchPattern":null,"preventionTips":["Reserve allow_unwrapped=True for single-type RaisesGroup usage.","Use RaisesExc(check=lambda e: isinstance(e, (...))) for 'one of several' matching.","Document the convention in your group-matcher helpers."],"tags":["pytest","raises","raisesgroup","allow-unwrapped","validation"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}