{"record":{"id":"4367850a834bfd36","repo":"aio-libs/aiohttp","slug":"value-value-r-is-not-a-valid-etag-maybe-it-cont","errorCode":null,"errorMessage":"Value {value!r} is not a valid etag. Maybe it contains '\"'?","messagePattern":"Value (.+?) is not a valid etag\\. Maybe it contains '\"'\\?","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/helpers.py","lineNumber":1146,"sourceCode":"# https://tools.ietf.org/html/rfc7232#section-2.3\n_ETAGC = r\"[!\\x23-\\x7E\\x80-\\xff]+\"\n_ETAGC_RE = re.compile(_ETAGC)\n_QUOTED_ETAG = rf'(W/)?\"({_ETAGC})\"'\nQUOTED_ETAG_RE = re.compile(_QUOTED_ETAG)\nLIST_QUOTED_ETAG_RE = re.compile(rf\"({_QUOTED_ETAG})(?:\\s*,\\s*|$)|(.)\")\n\nETAG_ANY = \"*\"\n\n\n@frozen_dataclass_decorator\nclass ETag:\n    value: str\n    is_weak: bool = False\n\n\ndef validate_etag_value(value: str) -> None:\n    if value != ETAG_ANY and not _ETAGC_RE.fullmatch(value):\n        raise ValueError(\n            f\"Value {value!r} is not a valid etag. Maybe it contains '\\\"'?\"\n        )\n\n\ndef parse_http_date(date_str: str | None) -> datetime.datetime | None:\n    \"\"\"Process a date string, return a datetime object\"\"\"\n    if date_str is not None:\n        timetuple = parsedate(date_str)\n        if timetuple is not None:\n            with suppress(ValueError):\n                return datetime.datetime(*timetuple[:6], tzinfo=datetime.timezone.utc)\n    return None\n\n\n@functools.lru_cache\ndef must_be_empty_body(method: str, code: int) -> bool:\n    \"\"\"Check if a request must return an empty body.\"\"\"\n    return (","sourceCodeStart":1128,"sourceCodeEnd":1164,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/helpers.py#L1128-L1164","documentation":"Thrown by aiohttp.helpers.validate_etag_value when a string is not a legal ETag value per RFC 7232. Accepted forms are the wildcard '*' or any string matching the etag-char class [!\\x23-\\x7E\\x80-\\xff]+ (printable ASCII minus the double-quote 0x22, plus non-ASCII bytes). The value must NOT carry surrounding quotes or the 'W/' weak prefix; the caller supplies only the bare opaque tag.","triggerScenarios":"Calling validate_etag_value() directly, or setting StreamResponse.etag (web_response.py) with an ETag whose .value contains a '\"', whitespace, or control char. The wildcard '*' alone is allowed.","commonSituations":"Passing a fully quoted ETag like '\"abc123\"' (with literal quotes) instead of the bare token; copying raw header values from another response and reusing them; hashes that accidentally include delimiters.","solutions":["Strip surrounding double-quotes and any 'W/' prefix before passing the value.","Pass the bare opaque token only (e.g. 'abc123'), or '*' for the wildcard.","If generating from a hash, restrict the alphabet to base64/hex and trim to etag-char range."],"exampleFix":"# before\nvalidate_etag_value('\"abc123\"')   # raises\n\n# after\nvalidate_etag_value('abc123')      # ok","handlingStrategy":"validation","validationCode":"import re\n_ETAGC_RE = re.compile(r'[!\\x23-\\x7E\\x80-\\xff]+')\ndef normalize_etag(v: str) -> str:\n    # drop W/ prefix and surrounding quotes\n    v = v.strip()\n    if v.startswith('W/'):\n        v = v[2:].lstrip()\n    if len(v) >= 2 and v[0] == '\"' and v[-1] == '\"':\n        v = v[1:-1]\n    return v\n\ndef safe_etag(v: str) -> str | None:\n    n = normalize_etag(v)\n    if n == '*' or _ETAGC_RE.fullmatch(n):\n        return n\n    return None","typeGuard":"import re\n_ETAGC_RE = re.compile(r'[!\\x23-\\x7E\\x80-\\xff]+')\ndef is_valid_etag_value(v: str) -> bool:\n    return v == '*' or bool(_ETAGC_RE.fullmatch(v))","tryCatchPattern":"from aiohttp.helpers import validate_etag_value\ntry:\n    validate_etag_value(candidate)\nexcept ValueError as e:\n    # log and use a fallback tag or skip the ETag header\n    ...","preventionTips":["Never pass raw header values that may include quotes; normalize first.","Treat ETag as an opaque token, not a quoted-string."],"tags":["http","etag","validation","header","server"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}