aio-libs/aiohttp · error · ClientError
Digest auth error: Unsupported Quality of Protection (qop) v
Error message
Digest auth error: Unsupported Quality of Protection (qop) value(s): {qop_raw} What it means
Raised as a ClientError when a Digest auth challenge includes a 'qop' (Quality of Protection) parameter whose token list contains no value aiohttp can negotiate. aiohttp only implements 'auth' and 'auth-int' (RFC 2617/7616); if the server advertises only unsupported tokens (or unparseable garbage), the client cannot compute the response digest correctly and refuses rather than send an unauthenticated-looking request.
Source
Thrown at aiohttp/client_middleware_digest_auth.py:285
# Convert string values to bytes once
nonce_bytes = nonce.encode("utf-8")
realm_bytes = realm.encode("utf-8")
# Use the encoded request-target (raw_path_qs) since that is what is
# transmitted on the wire and what the server signs against. Using the
# decoded form would cause digest verification to fail when the path
# or query string contains percent-encoded reserved characters.
path = URL(url).raw_path_qs
# Process QoP
qop = ""
qop_bytes = b""
if qop_raw:
valid_qops = {"auth", "auth-int"}.intersection(
{q.strip() for q in qop_raw.split(",") if q.strip()}
)
if not valid_qops:
raise ClientError(
f"Digest auth error: Unsupported Quality of Protection (qop) value(s): {qop_raw}"
)
qop = "auth-int" if "auth-int" in valid_qops else "auth"
qop_bytes = qop.encode("utf-8")
if algorithm not in DigestFunctions:
raise ClientError(
f"Digest auth error: Unsupported hash algorithm: {algorithm}. "
f"Supported algorithms: {', '.join(SUPPORTED_ALGORITHMS)}"
)
hash_fn: Final = DigestFunctions[algorithm]
def H(x: bytes) -> bytes:
"""RFC 7616 Section 3: Hash function H(data) = hex(hash(data))."""
return hash_fn(x).hexdigest().encode()
def KD(s: bytes, d: bytes) -> bytes:View on GitHub (pinned to c0ef574e29)
Solutions
- Reconfigure the server to advertise qop="auth" (most widely supported) instead of auth-conf or custom values.
- If the server only supports auth-conf, use a different HTTP client that implements it, or tunnel via TLS and disable qop server-side.
- Confirm the exact WWW-Authenticate header the server emits and verify qop parsing.
Example fix
# server config (nginx example) - before: # auth_basic_user_file ... ; (digest module emitting qop=auth-conf) # after: configure digest module to qop=auth
Defensive patterns
Strategy: try-catch
Try / catch
from aiohttp import ClientError
try:
resp = await session.get(url, auth=DigestAuth(login, pwd))
except ClientError as e:
if "Unsupported Quality of Protection" in str(e):
# negotiate a non-digest auth path or report server misconfig Prevention
- Confirm server qop advertises 'auth' before relying on digest auth.
- Capture the WWW-Authenticate header in logs to diagnose qop mismatches.
- Maintain a known-good server config snippet for digest auth (qop=auth, algorithm=SHA-256).
When it happens
Trigger: Fires at line 284-287 after intersecting the server's qop token set with {"auth","auth-int"} yields an empty set. Common when the server sends qop values like "auth-conf", proprietary tokens, or malformed comma-separated lists.
Common situations: Server configured for qop=auth-conf (confidentiality, which aiohttp doesn't implement); legacy Microsoft IIS or custom DAV servers using non-standard qop tokens; typos in server config.
Related errors
- Security issue: Digest auth challenge contains empty 'nonce'
- Digest auth error: Unsupported hash algorithm: {algorithm}.
- total timeout must be a positive number or None to disable,
- {url}
- aiohttp only supports http(s) proxies (got: {proxy.scheme!r}
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/3dd888deb00e2af6.json.
Report an issue: GitHub.