aio-libs/aiohttp · error · InvalidURL
InvalidURL: {url}
Error message
InvalidURL: {url} What it means
Raised as InvalidURL by ClientRequest.__init__ when the request URL has no raw_host (e.g. a relative URL or an empty/URL without an authority). aiohttp requires an absolute URL with a host for client requests; the check 'if not url.raw_host' fails and raises InvalidURL. This is a usage error, not a network error.
Source
Thrown at aiohttp/client_reqrep.py:843
):
if match := _CONTAINS_CONTROL_CHAR_RE.search(method):
raise ValueError(
f"Method cannot contain non-token characters {method!r} "
f"(found at least {match.group()!r})"
)
# URL forbids subclasses, so a simple type check is enough.
assert type(url) is URL, url
self.original_url = url
self.url = url.with_fragment(None) if url.raw_fragment else url
self.method = method.upper()
self.loop = loop
self._ssl = ssl
if loop.get_debug():
self._source_traceback = traceback.extract_stack(sys._getframe(1))
if not url.raw_host:
raise InvalidURL(url)
self._update_headers(headers)
if url.raw_user or url.raw_password:
self.headers[hdrs.AUTHORIZATION] = encode_basic_auth(
url.user or "", url.password or ""
)
def _reset_writer(self, _: object = None) -> None:
self._writer_task = None
def _get_content_length(self) -> int | None:
"""Extract and validate Content-Length header value.
Returns parsed Content-Length value or None if not set.
Raises ValueError if header exists but cannot be parsed as an integer.
"""
if hdrs.CONTENT_LENGTH not in self.headers:
return None
View on GitHub (pinned to d041d4d0fd)
Solutions
- Pass an absolute URL: 'http://example.com/path'. Use aiohttp's URL or yarl.URL to build it.
- If you have a base URL and a path, combine them: str(URL(base) / path.lstrip('/')).
- Validate url.raw_host is truthy before constructing the request.
- Check for trailing/leading issues when assembling URLs from parts.
Example fix
# before
await session.get('/api/users') # InvalidURL — no host
# after
from yarl import URL
base = URL('http://api.example.com')
await session.get(base / 'api/users') Defensive patterns
Strategy: validation
Validate before calling
from yarl import URL
def absolute_url(url) -> URL:
u = URL(url) if not isinstance(url, URL) else url
if not u.raw_host:
raise ValueError(f'URL must be absolute with a host: {url!r}')
return u Type guard
from yarl import URL
def is_absolute_http_url(url) -> bool:
try:
u = URL(url) if not isinstance(url, URL) else url
except Exception:
return False
return bool(u.raw_host) and u.scheme in ('http', 'https') Try / catch
from aiohttp import InvalidURL
try:
await session.get(maybe_relative)
except InvalidURL as e:
# prepend a base URL and retry
await session.get(str(URL('http://api.example.com') / maybe_relative.lstrip('/'))) Prevention
- Always construct client URLs from a known base URL using yarl.URL.
- Validate url.raw_host before issuing requests.
- Keep server-relative paths out of client code unless combined with a base.
When it happens
Trigger: Passing a relative path like '/path' or 'path' instead of 'http://host/path'; passing an empty URL(); passing a URL with only a scheme but no host ('http:///path'). The raw_host check in ClientRequest.__init__ fails at construction.
Common situations: Building URLs by string concatenation and forgetting the scheme/host; reading a path from config/env and using it directly; mixing server-side relative URLs with client requests; URL parsing edge cases producing empty hosts.
Related errors
- Method cannot contain non-token characters {method!r} (found
- Invalid Content-Length header: {content_length_hdr!r}
- compress must be one of True, False, 'deflate', or 'gzip'
- base_url must have a trailing '/'
- Connection closed
AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11).
Data as JSON: /api/errors/7ecfdb929f9f5118.
Report an issue: GitHub.