{"id":"e96505a09dc333b8","repo":"pypa/pip","slug":"payload-in-an-invalid-encoding","errorCode":null,"errorMessage":"payload in an invalid encoding","messagePattern":"payload in an invalid encoding","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/packaging/metadata.py","lineNumber":238,"sourceCode":"\n\ndef _get_payload(msg: email.message.Message, source: bytes | str) -> str:\n    \"\"\"Get the body of the message.\"\"\"\n    # If our source is a str, then our caller has managed encodings for us,\n    # and we don't need to deal with it.\n    if isinstance(source, str):\n        payload = msg.get_payload()\n        assert isinstance(payload, str)\n        return payload\n    # If our source is a bytes, then we're managing the encoding and we need\n    # to deal with it.\n    else:\n        bpayload = msg.get_payload(decode=True)\n        assert isinstance(bpayload, bytes)\n        try:\n            return bpayload.decode(\"utf8\", \"strict\")\n        except UnicodeDecodeError as exc:\n            raise ValueError(\"payload in an invalid encoding\") from exc\n\n\n# The various parse_FORMAT functions here are intended to be as lenient as\n# possible in their parsing, while still returning a correctly typed\n# RawMetadata.\n#\n# To aid in this, we also generally want to do as little touching of the\n# data as possible, except where there are possibly some historic holdovers\n# that make valid data awkward to work with.\n#\n# While this is a lower level, intermediate format than our ``Metadata``\n# class, some light touch ups can make a massive difference in usability.\n\n# Map METADATA fields to RawMetadata.\n_EMAIL_TO_RAW_MAPPING = {\n    \"author\": \"author\",\n    \"author-email\": \"author_email\",\n    \"classifier\": \"classifiers\",","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/packaging/metadata.py#L220-L256","documentation":"Raised as ValueError('payload in an invalid encoding') by _get_payload in packaging.metadata when the METADATA body bytes cannot be decoded as strict UTF-8. packaging assumes PEP 621/643 metadata is UTF-8; any non-UTF-8 byte sequence is rejected.","triggerScenarios":"Passing bytes source to from_email where the message body contains Latin-1, CP1252, or CJK bytes; a PKG-INFO / METADATA file saved as Latin-1 by an old tool; an XML/encoding declaration in the body that contradicts the actual bytes.","commonSituations":"Reading legacy sdists whose METADATA was authored pre-UTF-8; files edited on Windows in CP1252; mojibake introduced by a misconfigured build backend.","solutions":["Re-save the METADATA file as UTF-8 (e.g. iconv -f latin1 -t utf-8).","If you must pass str, decode the bytes yourself with the correct encoding first and pass the str to from_email.","Strip or fix the offending non-UTF-8 bytes before parsing.","Use twine check / build to validate the sdist metadata before consumption."],"exampleFix":"# before\nfrom_email(raw_latin1_bytes)\n# after\nfrom_email(raw_latin1_bytes.decode('latin-1'))","handlingStrategy":"validation","validationCode":"def is_utf8(b: bytes) -> bool:\n    try:\n        b.decode('utf-8', 'strict')\n        return True\n    except UnicodeDecodeError:\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    md = Metadata.from_email(raw_bytes)\nexcept ValueError as e:\n    if 'invalid encoding' in str(e):\n        md = Metadata.from_email(raw_bytes.decode('latin-1'))","preventionTips":["Always author METADATA as UTF-8.","If loading legacy files, decode with the source encoding then pass str to from_email.","Strip mojibake before parsing.","Run twine check on built artifacts."],"tags":["metadata","encoding","utf-8","validation"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}