{"record":{"id":"507f98697faad82f","repo":"aio-libs/aiohttp","slug":"inheritance-class-cls-name-from-clientsessio","errorCode":null,"errorMessage":"Inheritance class {cls.__name__} from ClientSession is forbidden","messagePattern":"Inheritance class (.+?) from ClientSession is forbidden","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"aiohttp/client.py","lineNumber":426,"sourceCode":"            self._skip_auto_headers = frozenset()\n\n        self._request_class = request_class\n        self._response_class = response_class\n        self._ws_response_class = ws_response_class\n\n        self._trace_configs = trace_configs or []\n        for trace_config in self._trace_configs:\n            trace_config.freeze()\n\n        self._resolve_charset = fallback_charset_resolver\n\n        self._default_proxy = proxy\n        self._default_ssl = ssl\n        self._retry_connection: bool = True\n        self._middlewares = tuple(middlewares)\n\n    def __init_subclass__(cls: type[\"ClientSession\"]) -> None:\n        raise TypeError(\n            f\"Inheritance class {cls.__name__} from ClientSession is forbidden\"\n        )\n\n    def __del__(self, _warnings: Any = warnings) -> None:\n        if not self.closed:\n            _warnings.warn(\n                f\"Unclosed client session {self!r}\",\n                ResourceWarning,\n                source=self,\n            )\n            context = {\"client_session\": self, \"message\": \"Unclosed client session\"}\n            if self._source_traceback is not None:\n                context[\"source_traceback\"] = self._source_traceback\n            self._loop.call_exception_handler(context)\n\n    if sys.version_info >= (3, 11) and TYPE_CHECKING:\n\n        def request(","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d9aaf697c2cd4783ca5749a971965c689f3ec24f/aiohttp/client.py#L408-L444","documentation":"Raised as a TypeError via __init_subclass__ (client.py:425-428) the moment any class subclasses ClientSession. aiohttp intentionally forbids subclassing because the session's internals (connector ownership, loop pinning, middleware pipeline, header/cookie state) are not a stable extension surface; subclassing routinely breaks resource cleanup and invariants. The error names the offending subclass so the offending class is obvious. This is a hard design constraint, not a runtime data error.","triggerScenarios":"Writing class MySession(aiohttp.ClientSession) and importing/instantiating it (the error fires at class-definition time). Wrapping ClientSession to add retry/logging/auth helpers via inheritance. Following a generic 'extend the library class' pattern from another framework.","commonSituations":"Porting from requests where subclassing requests.Session is common. Trying to bundle default headers/cookies/auth by overriding __init__. Code generated by an ORM/web framework that auto-subclasses third-party clients.","solutions":["Use composition: write a plain class that holds a ClientSession instance and delegates calls to it.","Inject behavior through the supported extension points: middlewares=, trace_configs=, headers=, cookies=, and the auth middleware.","Set session-wide defaults via the ClientSession constructor (base_url, headers, timeout, auth) rather than overriding methods.","If you need request-level hooks, pass per-request middlewares to session.request(..., middlewares=[...])."],"exampleFix":"# before\nclass MySession(aiohttp.ClientSession):  # TypeError at class definition\n    async def get(self, url):\n        return await super().get(url, headers={'X-Custom': '1'})\n\n# after\nclass MyClient:\n    def __init__(self, session: aiohttp.ClientSession):\n        self._s = session\n    async def get(self, url):\n        return await self._s.get(url, headers={'X-Custom': '1'})","handlingStrategy":"validation","validationCode":"# No runtime guard needed: the failure is at class-definition time.\n# Static rule: never subclass aiohttp.ClientSession.\ndef assert_not_subclassing(cls):\n    assert aiohttp.ClientSession not in cls.__bases__, 'Do not subclass ClientSession'","typeGuard":"def is_client_session_instance(obj) -> bool:\n    return isinstance(obj, aiohttp.ClientSession) and type(obj) is aiohttp.ClientSession","tryCatchPattern":"# Not applicable at runtime; the TypeError fires at import/class-definition.\n# Fix is structural: switch from inheritance to composition.","preventionTips":["Treat ClientSession as final; wrap it in a holder class instead.","Use middlewares=/trace_configs= for cross-cutting behavior.","Add a lint check / pre-commit grep for 'class .*(aiohttp.ClientSession)'."],"tags":["client","api-design","inheritance","configuration"],"analyzedSha":"d9aaf697c2cd4783ca5749a971965c689f3ec24f","analyzedAt":"2026-08-06T21:30:48.638Z","schemaVersion":2},"datasetVersion":"2026-08-07T01:17:05.418Z"}