aio-libs/aiohttp · error · ValueError
None is not allowed as login value
Error message
None is not allowed as login value
What it means
Raised in `DigestAuthMiddleware.__init__` (client_middleware_digest_auth.py:202-203) when `login` is None. The middleware encodes the login to bytes immediately (line 212) and uses it in every digest computation, so a None login cannot proceed. The check is an explicit fail-fast before any encoding happens.
Source
Thrown at aiohttp/client_middleware_digest_auth.py:203
Standards compliance:
- RFC 7616: HTTP Digest Access Authentication (primary reference)
- RFC 2617: HTTP Authentication (deprecated by RFC 7616)
- RFC 1945: Section 11.1 (username restrictions)
Implementation notes:
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.View on GitHub (pinned to c0ef574e29)
Solutions
- Ensure `login` is a non-None string before constructing the middleware.
- Load credentials with a required-default: `login = os.environ['DIGEST_USER']` (raises KeyError early) or `os.environ.get('DIGEST_USER', '')`.
- Conditionally apply the middleware only when credentials are present.
Example fix
// before
mw = DigestAuthMiddleware(login=os.environ.get('USER'), password=pw)
// after
user = os.environ.get('DIGEST_USER')
if user is None:
raise RuntimeError('DIGEST_USER must be set')
mw = DigestAuthMiddleware(login=user, password=pw) Defensive patterns
Strategy: validation
Validate before calling
def require_login(login: str | None) -> str:
if login is None:
raise ValueError('login must not be None')
return login Type guard
def is_valid_login(v) -> bool:
return isinstance(v, str) Prevention
- Resolve credentials before constructing the middleware.
- Use `os.environ['VAR']` (raises KeyError) instead of `.get()` for required secrets.
- Add a startup check that fails loudly if credentials are missing.
When it happens
Trigger: Constructing `DigestAuthMiddleware(login=None, password='x')`; reading credentials from an env var or config that returned None; passing `login=None` as a placeholder.
Common situations: Env/config-driven credential loading where the login key is missing (returns None); test code stubbing credentials as None; conditional auth code that constructs the middleware even when credentials aren't set.
Related errors
- None is not allowed as password value
- A ":" is not allowed in username (RFC 1945#section-11.1)
- 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/f5d0d6f70264847f.json.
Report an issue: GitHub.