aio-libs/aiohttp · error · ValueError
A ":" is not allowed in username (RFC 1945#section-11.1)
Error message
A ":" is not allowed in username (RFC 1945#section-11.1)
What it means
Raised in `DigestAuthMiddleware.__init__` (client_middleware_digest_auth.py:208-209) when `login` contains a colon (`:`). RFC 1945 §11.1 (referenced in the message) defines the `userid` grammar as `*<any CHAR except CTL and ":">`, so a colon in the username is syntactically illegal in Basic/Digest auth and would corrupt the `username="..."` field of the Authorization header. The check fails fast at construction.
Source
Thrown at aiohttp/client_middleware_digest_auth.py:209
The core digest calculation is inspired by the implementation in
https://github.com/requests/requests/blob/v2.18.4/requests/auth.py
with added support for modern digest auth features and error handling.
"""
def __init__(
self,
login: str,
password: str,
preemptive: bool = True,
) -> None:
if login is None:
raise ValueError("None is not allowed as login value")
if password is None:
raise ValueError("None is not allowed as password value")
if ":" in login:
raise ValueError('A ":" is not allowed in username (RFC 1945#section-11.1)')
self._login_str: Final[str] = login
self._login_bytes: Final[bytes] = login.encode("utf-8")
self._password_bytes: Final[bytes] = password.encode("utf-8")
self._last_nonce_bytes = b""
self._nonce_count = 0
self._challenge: DigestAuthChallenge = {}
self._preemptive: bool = preemptive
# Set of URLs defining the protection space
self._protection_space: list[str] = []
# Origin the credentials are scoped to; set on the first request.
self._origin: URL | None = None
async def _encode(self, method: str, url: URL, body: Payload | Literal[b""]) -> str:
"""
Build digest authorization header for the current challenge.
View on GitHub (pinned to c0ef574e29)
Solutions
- Strip the password portion if it was accidentally included: split on the first colon and pass only the username.
- URL-encode or otherwise sanitize the username if the upstream truly uses colons (note: this may break server-side Digest validation).
- Use a username without a colon, per RFC 1945.
Example fix
// before mw = DigestAuthMiddleware(login='alice:s3cret', password='x') # colon in login // after mw = DigestAuthMiddleware(login='alice', password='s3cret')
Defensive patterns
Strategy: validation
Validate before calling
def sanitize_login(login: str) -> str:
if ':' in login:
raise ValueError('login must not contain ":" (RFC 1945)')
return login Type guard
def is_rfc1945_login(v) -> bool:
return isinstance(v, str) and ':' not in v Prevention
- Don't paste `user:pass` strings into the login field.
- Validate usernames against the RFC 1945 grammar at the config boundary.
- If upstream usernames contain colons, coordinate with the auth server on an encoding scheme.
When it happens
Trigger: Passing an email-style or `domain\user`-style login that contains a colon; usernames from external identity providers that include colons; copy-paste including a `user:pass` blob into the login field.
Common situations: Confusing `login` with a combined `user:password` string; email-as-username where the local-part has a colon; non-RFC-compliant identity systems.
Related errors
- None is not allowed as login value
- None is not allowed as password value
- Malformed Digest auth challenge: Missing 'realm' parameter
- Malformed Digest auth challenge: Missing 'nonce' parameter
- base_url must have a trailing '/'
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/ff712a03e0b3fa90.json.
Report an issue: GitHub.