aio-libs/aiohttp · error · TypeError
Domain must be str
Error message
Domain must be str
What it means
Raised as TypeError by Domain.validation when the domain argument is not a str. Domain (used in Domain and MaskDomain for sub-app matching by host) requires a textual hostname, so non-string inputs (bytes, int, None) are rejected before any parsing.
Source
Thrown at aiohttp/web_urldispatcher.py:781
@abc.abstractmethod # pragma: no branch
def canonical(self) -> str:
"""Return a str"""
class Domain(AbstractRuleMatching):
re_part = re.compile(r"(?!-)[a-z\d-]{1,63}(?<!-)")
def __init__(self, domain: str) -> None:
super().__init__()
self._domain = self.validation(domain)
@property
def canonical(self) -> str:
return self._domain
def validation(self, domain: str) -> str:
if not isinstance(domain, str):
raise TypeError("Domain must be str")
domain = domain.rstrip(".").lower()
if not domain:
raise ValueError("Domain cannot be empty")
elif "://" in domain:
raise ValueError("Scheme not supported")
url = URL("http://" + domain)
assert url.raw_host is not None
if not all(self.re_part.fullmatch(x) for x in url.raw_host.split(".")):
raise ValueError("Domain not valid")
if url.port == 80:
return url.raw_host
return f"{url.raw_host}:{url.port}"
async def match(self, request: Request) -> bool:
host = request.headers.get(hdrs.HOST)
if not host:
return False
return self.match_domain(host)View on GitHub (pinned to c0ef574e29)
Solutions
- Pass the host as a string: Domain('example.com').
- Coerce config values: Domain(str(host)) after loading.
- Validate host is a non-empty str before constructing Domain.
Example fix
# before
app.add_domain(8080, sub_app) # port int instead of host str
# after
app.add_domain('example.com', sub_app) Defensive patterns
Strategy: type-guard
Validate before calling
def coerce_domain(domain):
if not isinstance(domain, str):
raise TypeError(f"Domain must be str, got {type(domain).__name__}")
return domain Type guard
def is_domain_str(domain) -> bool:
return isinstance(domain, str) Try / catch
try:
app.add_domain(host, sub_app)
except TypeError as e:
if 'Domain must be str' in str(e):
host = str(host)
app.add_domain(host, sub_app)
else:
raise Prevention
- Coerce config values to str before passing to add_domain/Domain.
- Validate host config keys are strings in config loading.
- Annotate host variables as str.
When it happens
Trigger: Constructing aiohttp.web.Domain(123), Domain(b'example.com'), Domain(None), or passing a host read from config that was parsed as a non-string type. Used via app.add_domain(host, sub_app).
Common situations: Config loaded from YAML/JSON where the host was unquoted and parsed as a number; passing bytes from a network parser; None when a host variable was unset.
Related errors
- Domain cannot be empty
- Scheme not supported
- ssl should be SSLContext, Fingerprint, or bool, got {ssl!r}
- The first argument should be web.Application instance, got {
- access_log_class must be subclass of aiohttp.abc.AbstractAcc
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/47cb43fc3ac6fe16.json.
Report an issue: GitHub.