siyuan-note/siyuan · error
svg closing element %q does not match %q
Error message
svg closing element %q does not match %q
What it means
A closing tag's element name does not equal the name of the innermost open element, i.e. mismatched start/end tags such as <rect>...</circle>. Strict XML forbids this; the sanitizer keeps a stack of open element names and compares each EndElement against the top of the stack.
Source
Thrown at kernel/util/misc.go:402
continue
}
if _, unsafe := unsafeSVGElements[strings.ToLower(typed.Name.Local)]; unsafe {
skipDepth = 1
continue
}
typed.Name = preserveXMLName(typed.Name)
typed.Attr = sanitizeSVGAttributes(typed.Attr)
if err = encoder.EncodeToken(typed); err != nil {
return "", fmt.Errorf("render svg failed: %w", err)
}
case xml.EndElement:
if depth <= 0 || len(elementStack) == 0 {
return "", fmt.Errorf("svg contains an unexpected closing element")
}
startName := elementStack[len(elementStack)-1]
if startName != typed.Name {
return "", fmt.Errorf("svg closing element %q does not match %q", typed.Name.Local, startName.Local)
}
elementStack = elementStack[:len(elementStack)-1]
if skipDepth > 0 {
skipDepth--
depth--
if depth == 0 {
rootClosed = true
}
continue
}
typed.Name = preserveXMLName(typed.Name)
if err = encoder.EncodeToken(typed); err != nil {
return "", fmt.Errorf("render svg failed: %w", err)
}
depth--
if depth == 0 {
rootClosed = true
}View on GitHub (pinned to 8641553a1f)
Solutions
- Fix the mismatched close tag so it matches the innermost open element
- Run the SVG through an XML linter/formatter (e.g. xmllint) which pinpoints the mismatch line
- Re-export the icon from its design tool instead of hand-editing
- Validate with xml.Unmarshal in Go before calling SanitizeSVG
Example fix
// before
SanitizeSVG("<svg><g></rect></g></svg>") // closing element "rect" does not match "g"
// after
SanitizeSVG("<svg xmlns=\"http://www.w3.org/2000/svg\"><g></g></svg>") Defensive patterns
Strategy: validation
Validate before calling
func tagsBalanced(input string) error {
var stack []string
dec := xml.NewDecoder(strings.NewReader(input))
for {
tok, err := dec.RawToken()
if err == io.EOF { return nil }
if err != nil { return err }
switch t := tok.(type) {
case xml.StartElement: stack = append(stack, t.Name.Local)
case xml.EndElement:
if len(stack) == 0 || stack[len(stack)-1] != t.Name.Local {
return fmt.Errorf("mismatched tag %q", t.Name.Local)
}
stack = stack[:len(stack)-1]
}
}
} Try / catch
clean, err := util.SanitizeSVG(input)
if err != nil && strings.Contains(err.Error(), "does not match") {
input, err = reformatXML(input) // e.g. pipe through xmllint or gofmt-XML style formatter
if err == nil { clean, err = util.SanitizeSVG(input) }
}
if err != nil { return err } Prevention
- Never mix HTML tag-soup habits with SVG; every tag must close in LIFO order
- Use self-closing syntax <tag/> for empty elements to avoid pairing mistakes
- Lint icon assets with xmllint in CI
- Avoid manual merge edits across SVG versions
When it happens
Trigger: '<svg><g></rect></g></svg>' — nested tags closed in the wrong order; HTML-style tag soup fed to an XML parser; typos in tag names between open and close.
Common situations: Copy-paste editing that reorders or deletes tags; HTML-generated SVG where a browser's tag-soup recovery hid the mismatch; minifiers or hand-merges that break tag pairing.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- svg contains an unexpected closing element
- root element is not svg
- svg contains text outside the root element
- svg root element is incomplete
- render svg failed: %w
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/ed43442b88f6c873.
Report an issue: GitHub.