aio-libs/aiohttp · error · TypeError
Inheritance class {cls.__name__} from ClientSession is forbi
Error message
Inheritance class {cls.__name__} from ClientSession is forbidden What it means
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.
Source
Thrown at aiohttp/client.py:426
self._skip_auto_headers = frozenset()
self._request_class = request_class
self._response_class = response_class
self._ws_response_class = ws_response_class
self._trace_configs = trace_configs or []
for trace_config in self._trace_configs:
trace_config.freeze()
self._resolve_charset = fallback_charset_resolver
self._default_proxy = proxy
self._default_ssl = ssl
self._retry_connection: bool = True
self._middlewares = tuple(middlewares)
def __init_subclass__(cls: type["ClientSession"]) -> None:
raise TypeError(
f"Inheritance class {cls.__name__} from ClientSession is forbidden"
)
def __del__(self, _warnings: Any = warnings) -> None:
if not self.closed:
_warnings.warn(
f"Unclosed client session {self!r}",
ResourceWarning,
source=self,
)
context = {"client_session": self, "message": "Unclosed client session"}
if self._source_traceback is not None:
context["source_traceback"] = self._source_traceback
self._loop.call_exception_handler(context)
if sys.version_info >= (3, 11) and TYPE_CHECKING:
def request(View on GitHub (pinned to d9aaf697c2)
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=[...]).
Example fix
# before
class MySession(aiohttp.ClientSession): # TypeError at class definition
async def get(self, url):
return await super().get(url, headers={'X-Custom': '1'})
# after
class MyClient:
def __init__(self, session: aiohttp.ClientSession):
self._s = session
async def get(self, url):
return await self._s.get(url, headers={'X-Custom': '1'}) Defensive patterns
Strategy: validation
Validate before calling
# No runtime guard needed: the failure is at class-definition time.
# Static rule: never subclass aiohttp.ClientSession.
def assert_not_subclassing(cls):
assert aiohttp.ClientSession not in cls.__bases__, 'Do not subclass ClientSession' Type guard
def is_client_session_instance(obj) -> bool:
return isinstance(obj, aiohttp.ClientSession) and type(obj) is aiohttp.ClientSession Try / catch
# Not applicable at runtime; the TypeError fires at import/class-definition. # Fix is structural: switch from inheritance to composition.
Prevention
- 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)'.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- timeout parameter cannot be of {type(timeout)} type, please
- Session and connector have to use same event loop
- data and json parameters can not be used at the same time
- None is not allowed as login value
- None is not allowed as password value
AI-assisted analysis of aio-libs/aiohttp@d9aaf697c2 (2026-08-06).
Data as JSON: /api/errors/507f98697faad82f.
Report an issue: GitHub.