{"record":{"id":"730b2a9f5360bdc4","repo":"psf/requests","slug":"max-age-morsel-max-age-must-be-integer","errorCode":null,"errorMessage":"max-age: {morsel['max-age']} must be integer","messagePattern":"max-age: (.+?) must be integer","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/requests/cookies.py","lineNumber":539,"sourceCode":"\n    result.update(kwargs)\n    result[\"port_specified\"] = bool(result[\"port\"])\n    result[\"domain_specified\"] = bool(result[\"domain\"])\n    result[\"domain_initial_dot\"] = result[\"domain\"].startswith(\".\")\n    result[\"path_specified\"] = bool(result[\"path\"])\n\n    return cookielib.Cookie(**result)\n\n\ndef morsel_to_cookie(morsel: Morsel[Any]) -> Cookie:\n    \"\"\"Convert a Morsel object into a Cookie containing the one k/v pair.\"\"\"\n\n    expires: int | None = None\n    if morsel[\"max-age\"]:\n        try:\n            expires = int(time.time() + int(morsel[\"max-age\"]))\n        except ValueError:\n            raise TypeError(f\"max-age: {morsel['max-age']} must be integer\")\n    elif morsel[\"expires\"]:\n        time_template = \"%a, %d-%b-%Y %H:%M:%S GMT\"\n        expires = calendar.timegm(time.strptime(morsel[\"expires\"], time_template))\n    return create_cookie(\n        comment=morsel[\"comment\"],\n        comment_url=bool(morsel[\"comment\"]),\n        discard=False,\n        domain=morsel[\"domain\"],\n        expires=expires,\n        name=morsel.key,\n        path=morsel[\"path\"],\n        port=None,\n        rest={\"HttpOnly\": morsel[\"httponly\"]},\n        rfc2109=False,\n        secure=bool(morsel[\"secure\"]),\n        value=morsel.value,\n        version=morsel[\"version\"] or 0,\n    )","sourceCodeStart":521,"sourceCodeEnd":557,"githubUrl":"https://github.com/psf/requests/blob/8068356288978c4f54661ae6f95afe0e0831885e/src/requests/cookies.py#L521-L557","documentation":"Raised by morsel_to_cookie when a Set-Cookie morsel's 'max-age' attribute cannot be parsed as an integer. The function computes expires as time.time() + int(max-age); a non-numeric max-age (e.g. '0abc' or a malformed value) triggers a ValueError that is converted to a TypeError with the offending value. This is a parser-level rejection of malformed cookie metadata.","triggerScenarios":"A server sends Set-Cookie with max-age set to a non-integer value (malformed or non-RFC-compliant); an upstream proxy rewrites max-age with garbage; manual construction of a Morsel object whose 'max-age' is a non-numeric string.","commonSituations":"Interoperating with non-RFC-6265 servers; middleboxes that corrupt headers; tests feeding synthetic Morsel objects with placeholder max-age values.","solutions":["Catch TypeError around cookie-jar population if you cannot control server headers, and skip the offending cookie.","Report the malformed Set-Cookie to the server-side team; the value must be a base-10 integer per RFC 6265.","If you control the server, ensure max-age is sent as a bare integer (e.g. max-age=3600, not max-age='3,600')."],"exampleFix":"// before\n# server returns: Set-Cookie: sid=x; Max-Age=1h\n\n// after\n# server returns: Set-Cookie: sid=x; Max-Age=3600","handlingStrategy":"try-catch","validationCode":"# Pre-validate a Morsel's max-age before conversion, if you construct Morsels manually:\ndef safe_max_age(morsel) -> int | None:\n    ma = morsel.get('max-age')\n    if not ma:\n        return None\n    try:\n        return int(ma)\n    except (TypeError, ValueError):\n        return None  # or raise","typeGuard":"def morsel_has_valid_max_age(morsel) -> bool:\n    ma = morsel.get('max-age')\n    if not ma:\n        return True\n    try:\n        int(ma)\n        return True\n    except (TypeError, ValueError):\n        return False","tryCatchPattern":"from requests.cookies import morsel_to_cookie\n\ntry:\n    c = morsel_to_cookie(morsel)\nexcept TypeError:\n    # malformed max-age on server side; skip this cookie\n    c = None","preventionTips":["If you control the server, always send Max-Age as a bare integer.","Wrap cookie-jar population in try/except when ingesting untrusted servers.","Report non-compliant Set-Cookie upstream rather than silently dropping."],"tags":["cookies","typeerror","max-age","parsing","rfc6265"],"backgroundTag":null,"analyzedSha":"8068356288978c4f54661ae6f95afe0e0831885e","analyzedAt":"2026-08-11T20:11:09.238Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}