siyuan-note/siyuan · error

svg contains an unexpected closing element

Error message

svg contains an unexpected closing element

What it means

The decoder produced an EndElement when the element stack is empty or depth is already 0, meaning the input contains a closing tag with no matching open tag. Go's strict XML tokenizer surfaces these malformations and SanitizeSVG treats any unbalanced markup as invalid SVG.

Source

Thrown at kernel/util/misc.go:398

			}

			if skipDepth > 0 {
				skipDepth++
				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)
			}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Remove the extra/unmatched closing tag from the input
  2. Re-generate the SVG rather than hand-editing it
  3. Run the input through a strict XML parser first to confirm well-formedness
  4. Check any template/concatenation code for duplicated closing tags

Example fix

// before
SanitizeSVG("<svg><rect/></svg></svg>") // unexpected closing element
// after
SanitizeSVG("<svg xmlns=\"http://www.w3.org/2000/svg\"><rect/></svg>")
Defensive patterns

Strategy: validation

Validate before calling

func xmlWellFormed(input string) error {
	dec := xml.NewDecoder(strings.NewReader(input))
	dec.Strict = true
	depth := 0
	for {
		tok, err := dec.RawToken()
		if err == io.EOF { return nil }
		if err != nil { return err }
		switch tok.(type) {
		case xml.StartElement: depth++
		case xml.EndElement:
			depth--
			if depth < 0 { return errors.New("closing tag without matching open tag") }
		}
	}
}

Try / catch

if err := xmlWellFormed(input); err != nil {
	return fmt.Errorf("svg markup is unbalanced: %w", err)
}
clean, err := util.SanitizeSVG(input)
if err != nil { return err }

Prevention

When it happens

Trigger: Input like '<svg></svg></svg>' or '</svg>' alone; a stray extra close tag at top level; text containing '</' sequences that parse as tags because the input is being fed as XML.

Common situations: Manual edits to SVG files deleting an element but leaving its close tag; truncated/corrupted pastes; string concatenation bugs that append an extra '</svg>'.

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/92fb32dac8997571. Report an issue: GitHub.