666ghj/MiroFish · error · StarHistoryError

generated SVG contains a forbidden element

Error message

generated SVG contains a forbidden element

What it means

Raised by `_validate_svg`'s element walk (scripts/star_history.py:1197) when an element's local name is not in the fixed allowlist `allowed_attributes` mapping (svg, title, desc, rect, path, text, image, ...). The chart is rendered from a reviewed template; any element outside that vocabulary means generated or injected content was never reviewed, so validation fails.

Source

Thrown at scripts/star_history.py:1197

        "baseFrequency": {"0.05"},
        "scale": {"5"},
        "fill-opacity": {"0.92"},
        "stroke-linecap": {"round"},
        "stroke-linejoin": {"round"},
        "text-anchor": {"start", "middle", "end"},
        "font-size": {"15", "16", "17", "20"},
        "font-weight": {"700"},
        "transform": {"rotate(-90 22 272)"},
    }
    avatar_count = 0
    watermark_count = 0
    for element in root.iter():
        if not isinstance(element.tag, str) or not element.tag.startswith(svg_namespace):
            raise StarHistoryError("generated SVG contains a foreign namespace")
        local_name = element.tag[len(svg_namespace) :]
        allowed_for_element = allowed_attributes.get(local_name)
        if allowed_for_element is None:
            raise StarHistoryError("generated SVG contains a forbidden element")
        if local_name == "image":
            avatar_attributes = {
                "x": "316",
                "y": "12",
                "width": "22",
                "height": "22",
                "href": OWNER_AVATAR_DATA_URI,
                "clip-path": "url(#clip-circle-title)",
            }
            watermark_attributes = {
                "x": "635",
                "y": "508.333",
                "width": "20",
                "height": "20",
                "href": WATERMARK_LOGO_DATA_URI,
            }
            if element.attrib == avatar_attributes:
                avatar_count += 1

View on GitHub (pinned to b5b53acc57)

Solutions

  1. If you intentionally added a new element type in a fork, add its local name plus its reviewed attributes to `allowed_attributes` and its constrained values to the exact-value table — keep the review discipline.
  2. Remove `<style>`, `<script>`, filters, and gradients copied from external SVGs; the template expresses everything via reviewed attributes.
  3. Run `_validate_svg(render_svg(...))` in CI after any template change so new elements fail the build instead of publishing.
  4. Check for accidental pasted markup inside the template string (a stray `<g>` from a design tool is enough).

Example fix

# fork adding a reviewed <circle> decoration
# before: template gains <circle cx="10" .../> -> 'forbidden element'

# after: extend the allowlist with reviewed attributes only
allowed_attributes: dict[str, set[str]] = {
    ...,
    "circle": {"cx", "cy", "r", "fill", "fill-opacity"},
}
Defensive patterns

Strategy: try-catch

Validate before calling

ALLOWED_ELEMENTS = {"svg", "title", "desc", "rect", "path", "text", "image"}  # keep in sync with _validate_svg

def only_allowed_elements(payload: bytes) -> bool:
    root = ET.fromstring(payload)
    return all(el.tag.split('}')[-1] in ALLOWED_ELEMENTS for el in root.iter())

Try / catch

try:
    _validate_svg(payload)
except StarHistoryError as exc:
    if "forbidden element" in str(exc):
        raise ValueError("template introduced an element outside the reviewed allowlist") from exc
    raise

Prevention

When it happens

Trigger: Any SVG element whose local name is absent from the allowlist — e.g. `<script>`, `<foreignObject>`, `<use>`, `<style>`, `<animate>`, or legitimate-but-new elements introduced by fork code (e.g. adding `<circle>` for a new decoration) without extending the allowlist.

Common situations: Forks extending the chart with new shapes but forgetting to allowlist them; sanitizers/injectors that add `<style>` blocks; template edits that copy elements from other SVGs (defs/gradients/filters are not part of the reviewed set).

Understand the failure class

Related errors


AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14). Data as JSON: /api/errors/9c2515da863757d6. Report an issue: GitHub.