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

  1. Fix the mismatched close tag so it matches the innermost open element
  2. Run the SVG through an XML linter/formatter (e.g. xmllint) which pinpoints the mismatch line
  3. Re-export the icon from its design tool instead of hand-editing
  4. 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

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


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/ed43442b88f6c873. Report an issue: GitHub.