666ghj/MiroFish · error · StarHistoryError
generated SVG root is invalid
Error message
generated SVG root is invalid
What it means
Raised by `_validate_svg` (scripts/star_history.py:1090) when the parsed XML root element is not `{http://www.w3.org/2000/svg}svg` — i.e. the document's outermost element is something else (a wrapper `<div>`, `<g>`, or an `<svg>` missing its namespace declaration). The validator then walks only known-namespaced children, so a wrong root aborts immediately.
Source
Thrown at scripts/star_history.py:1090
decoded_payload = payload.decode("utf-8", errors="strict")
except UnicodeDecodeError as exc:
raise StarHistoryError("generated SVG must be strict UTF-8") from exc
if decoded_payload.startswith("\ufeff") or "\x00" in decoded_payload:
raise StarHistoryError("generated SVG must be canonical UTF-8")
upper_payload = decoded_payload.upper()
if (
"<!DOCTYPE" in upper_payload
or "<!ENTITY" in upper_payload
or "<?" in decoded_payload
):
raise StarHistoryError("generated SVG contains forbidden XML directives")
try:
root = ET.fromstring(decoded_payload)
except ET.ParseError as exc:
raise StarHistoryError("generated SVG is not valid XML") from exc
svg_namespace = "{http://www.w3.org/2000/svg}"
if root.tag != f"{svg_namespace}svg":
raise StarHistoryError("generated SVG root is invalid")
allowed_attributes: dict[str, set[str]] = {
"svg": {
"viewBox",
"width",
"height",
"preserveAspectRatio",
"role",
"aria-labelledby",
},
"title": {"id"},
"desc": {"id"},
"rect": {
"x",
"y",
"width",
"height",
"rx",
"fill",View on GitHub (pinned to b5b53acc57)
Solutions
- Ensure the document's first and only root element is `<svg xmlns="http://www.w3.org/2000/svg" ...>` with the exact namespace URI.
- Remove wrapper elements — if you need surrounding markup, keep it outside the validated artifact and embed the SVG via `<img>`/`<object>` or inline after validation.
- If a sanitizer stripped xmlns, re-add it: `root.set("xmlns", "http://www.w3.org/2000/svg")` before serialization (or serialize with ET which handles namespaces).
- Check for accidental content before the root (comments are fine; elements are not).
Example fix
# before: wrapper element becomes the root payload = b"<div>" + svg_body + b"</div>" # after: svg stays the root; wrapper lives outside svg = render_svg(state, theme) # root is <svg xmlns=...> html = b"<div>" + svg + b"</div>" # embed after validation
Defensive patterns
Strategy: try-catch
Validate before calling
import xml.etree.ElementTree as ET
SVG_NS = "{http://www.w3.org/2000/svg}"
def has_svg_root(payload: bytes) -> bool:
try:
return ET.fromstring(payload).tag == f"{SVG_NS}svg"
except ET.ParseError:
return False Try / catch
try:
_validate_svg(payload)
except StarHistoryError as exc:
if "root is invalid" in str(exc):
raise ValueError("document must be a single root <svg xmlns=...> element") from exc
raise Prevention
- Never wrap the SVG in container elements before validation — embed afterwards instead.
- Keep xmlns="http://www.w3.org/2000/svg" on the root; sanitizers that strip it will fail here.
- Ensure no stray elements precede the <svg> root in concatenated output.
When it happens
Trigger: Payload parses as XML but the root tag lacks `xmlns="http://www.w3.org/2000/svg"` (then the tag is plain `svg`, not the namespaced one), or the document is wrapped (e.g. someone put the whole chart inside `<html>` or prepended another element before `<svg>`).
Common situations: Forks that wrap the SVG in an outer container for embedding; templates that omit the xmlns attribute; tools that 'clean' the SVG and drop the namespace; embedding logic that concatenates a banner element before the svg root.
Related errors
- generated SVG contains a foreign namespace
- generated SVG contains forbidden XML directives
- generated SVG is not valid XML
- generated SVG must be strict UTF-8
- generated SVG must be canonical UTF-8
AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14).
Data as JSON: /api/errors/7d07a7351653bc63.
Report an issue: GitHub.