aio-libs/aiohttp · error · TypeError
Inheritance class from ClientSession is forbidden
Error message
Inheritance class {cls.__name__} from ClientSession is forbidden What it means
ClientSession.__init_subclass__ unconditionally raises TypeError for any subclass. aiohttp intentionally closes ClientSession for extension because its internal lifecycle, __del__, and middleware plumbing are not safe to override; composition (wrapping a session) is the supported extension model.
Solutions
- Use composition: write a class that holds a ClientSession instance and delegates calls.
- Set defaults through ClientSession constructor args (base_url, headers, cookies, middlewares).
- Use client_middlewares (or a wrapper function) to inject custom request/response behavior.
Example fix
// before
class MySession(ClientSession):
async def get_json(self, url):
return await (await self.get(url)).json()
// after
class MyClient:
def __init__(self, session: ClientSession):
self._s = session
async def get_json(self, url):
async with self._s.get(url) as r:
return await r.json() Defensive patterns
Strategy: validation
Validate before calling
# No validation needed if you simply do not subclass.
# Composition pattern:
class ApiClient:
def __init__(self, session):
self._s = session Type guard
from aiohttp import ClientSession
def is_client_session(obj) -> bool:
return isinstance(obj, ClientSession) and type(obj) is ClientSession Try / catch
# Subclassing fails at class definition, not catchable in the usual sense.
# Detect at import time:
try:
class _Sub(ClientSession): # noqa
pass
except TypeError:
# switch to composition
pass Prevention
- Prefer composition: write a wrapper that holds a ClientSession.
- Use middlewares for cross-cutting request customization.
- Annotate module intent with a comment so future contributors don't attempt subclassing.
When it happens
Trigger: Writing class MySession(ClientSession): pass anywhere in user code, at class-definition time (not even at instantiation).
Common situations: Porting code from older aiohttp versions or other HTTP libs where session subclassing was idiomatic. Trying to add helper methods or default headers via inheritance instead of composition.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- base_url must have a trailing '/'
- Inheritance class from ChainMapProxy is forbidden
- Session and connector have to use same event loop
- Session is closed
- ssl should be SSLContext, Fingerprint, or bool, got
AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11).
Data as JSON: /api/errors/507f98697faad82f.
Report an issue: GitHub.
Appendix: 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 d041d4d0fd)