{"record":{"id":"e2ab0582372d5fb5","repo":"666ghj/MiroFish","slug":"generated-svg-must-be-strict-utf-8","errorCode":null,"errorMessage":"generated SVG must be strict UTF-8","messagePattern":"generated SVG must be strict UTF-8","errorType":"exception","errorClass":"StarHistoryError","httpStatus":null,"severity":"error","filePath":"scripts/star_history.py","lineNumber":1074,"sourceCode":"    if OWNER_AVATAR_MEDIA_TYPE == \"image/jpeg\":\n        if not payload.startswith(b\"\\xff\\xd8\\xff\") or not payload.endswith(b\"\\xff\\xd9\"):\n            return None\n        for marker in (0xC0, 0xC1, 0xC2, 0xC3, 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB, 0xCD, 0xCE, 0xCF):\n            offset = payload.find(bytes((0xFF, marker)))\n            if offset >= 0 and offset + 9 <= len(payload):\n                return (\n                    int.from_bytes(payload[offset + 7 : offset + 9], \"big\"),\n                    int.from_bytes(payload[offset + 5 : offset + 7], \"big\"),\n                )\n        return None\n    return None\n\n\ndef _validate_svg(payload: bytes) -> None:\n    try:\n        decoded_payload = payload.decode(\"utf-8\", errors=\"strict\")\n    except UnicodeDecodeError as exc:\n        raise StarHistoryError(\"generated SVG must be strict UTF-8\") from exc\n    if decoded_payload.startswith(\"\\ufeff\") or \"\\x00\" in decoded_payload:\n        raise StarHistoryError(\"generated SVG must be canonical UTF-8\")\n    upper_payload = decoded_payload.upper()\n    if (\n        \"<!DOCTYPE\" in upper_payload\n        or \"<!ENTITY\" in upper_payload\n        or \"<?\" in decoded_payload\n    ):\n        raise StarHistoryError(\"generated SVG contains forbidden XML directives\")\n    try:\n        root = ET.fromstring(decoded_payload)\n    except ET.ParseError as exc:\n        raise StarHistoryError(\"generated SVG is not valid XML\") from exc\n    svg_namespace = \"{http://www.w3.org/2000/svg}\"\n    if root.tag != f\"{svg_namespace}svg\":\n        raise StarHistoryError(\"generated SVG root is invalid\")\n    allowed_attributes: dict[str, set[str]] = {\n        \"svg\": {","sourceCodeStart":1056,"sourceCodeEnd":1092,"githubUrl":"https://github.com/666ghj/MiroFish/blob/b5b53acc57189a4a42e44a23e149dc655c98fe82/scripts/star_history.py#L1056-L1092","documentation":"Raised by the post-render self-check `_validate_svg` (scripts/star_history.py:1074) when the generated SVG bytes cannot be decoded as strict UTF-8. Everything the renderer emits should be ASCII/UTF-8 by construction, so this guard ensures the bytes about to be published are decodable before they reach badge consumers.","triggerScenarios":"`render_svg` output being post-processed and re-encoded (e.g. re-saved with a legacy codec, concatenated behind a BOM-stripping step gone wrong), or a fork introducing non-UTF-8 bytes into text elements. Triggered only when `payload.decode(\"utf-8\", errors=\"strict\")` raises UnicodeDecodeError.","commonSituations":"Downstream code that opens the SVG file with `open(path, \"w\", encoding=\"latin-1\")` and re-validates; piping the bytes through a tool that re-encodes; adding localized/emoji text to the renderer without keeping strings UTF-8.","solutions":["If you modified the renderer's text content, ensure all literals are UTF-8 (Python 3 source default) — avoid manually encoded byte splices.","If validating external bytes, decode with `errors=\"strict\"` and re-encode properly: `payload = payload.decode(\"utf-8\").encode(\"utf-8\")` only succeeds if it was UTF-8; otherwise fix the producer.","Write SVG files in binary mode (`open(path, \"wb\")`) so no implicit codec re-encodes them.","Keep unmodified `render_svg` output — its templates are pure ASCII, and this error then indicates post-processing corrupted the bytes."],"exampleFix":"# before: text-mode write re-encodes on Windows (cp1252) -> later strict decode fails\nwith open(path, \"w\") as f:\n    f.write(svg.decode(\"utf-8\"))\n\n# after: write bytes verbatim\nwith open(path, \"wb\") as f:\n    f.write(svg)","handlingStrategy":"try-catch","validationCode":"def is_strict_utf8(payload: bytes) -> bool:\n    try:\n        payload.decode(\"utf-8\", errors=\"strict\")\n        return True\n    except UnicodeDecodeError:\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    _validate_svg(payload)\nexcept StarHistoryError as exc:\n    if \"strict UTF-8\" in str(exc):\n        raise ValueError(\"SVG bytes were re-encoded after generation; use render_svg output verbatim\") from exc\n    raise","preventionTips":["Write SVG artifacts in binary mode and never round-trip them through text codecs.","Keep renderer literals plain ASCII/UTF-8 strings; avoid byte-level splicing into the payload.","Verify external files with a strict decode before validating or publishing."],"tags":["svg","utf-8","encoding","self-check","validation"],"backgroundTag":null,"analyzedSha":"b5b53acc57189a4a42e44a23e149dc655c98fe82","analyzedAt":"2026-08-14T22:29:33.146Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}