siyuan-note/siyuan · error

parse svg failed

Error message

parse svg failed: %w

What it means

SanitizeSVG parses SVG input with encoding/xml in strict mode using RawToken. Any XML parsing error (malformed markup, invalid entities, bad UTF-8, unexpected EOF) aborts sanitization and is wrapped in this error. The sanitizer intentionally refuses to guess at malformed XML, because HTML/XML parsing differences are the classic vector for SVG XSS bypasses.

Solutions

  1. Validate the SVG with an XML parser (e.g. xmllint --noout file.svg) and fix the reported syntax error
  2. Ensure the file is complete and UTF-8 encoded, not truncated in transfer
  3. If the source is HTML-ish SVG, convert it to well-formed XML (self-close tags, escape & as &)
  4. Re-export the SVG from the design tool with XML-compliant output options

Example fix

// before (invalid XML)
<svg><desc>a & b</desc></svg>
// after
<svg><desc>a &amp; b</desc></svg>
Defensive patterns

Strategy: validation

Validate before calling

func isWellFormedXML(svg string) bool {
    d := xml.NewDecoder(strings.NewReader(svg))
    d.Strict = true
    for {
        _, err := d.RawToken()
        if err == io.EOF { return true }
        if err != nil { return false }
    }
}

Try / catch

clean, err := util.SanitizeSVG(input)
if err != nil && strings.HasPrefix(err.Error(), "parse svg failed") {
    return fmt.Errorf("input is not well-formed XML, re-export the SVG: %w", err)
}

Prevention

When it happens

Trigger: Calling SanitizeSVG (directly, via custom emoji normalization, or the serveSVG HTTP path) with input that is not well-formed XML: unclosed tags, stray '<' or '&' characters, invalid entity references, non-UTF-8 bytes, or truncated files.

Common situations: Users paste SVG copied from HTML pages (HTML-tolerant markup that isn't valid XML), corrupted downloaded SVG files, SVG exported by tools that emit non-XML syntax, or clipper-captured fragments cut mid-tag.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/aee9595fac752222. Report an issue: GitHub.

Appendix: source

Thrown at kernel/util/misc.go:358

	decoder := xml.NewDecoder(strings.NewReader(svgInput))
	decoder.Strict = true

	var buf bytes.Buffer
	encoder := xml.NewEncoder(&buf)
	rootSeen := false
	rootClosed := false
	depth := 0
	skipDepth := 0
	tokenCount := 0
	var elementStack []xml.Name

	for {
		token, err := decoder.RawToken()
		if err == io.EOF {
			break
		}
		if err != nil {
			return "", fmt.Errorf("parse svg failed: %w", err)
		}
		tokenCount++
		if tokenCount > maxSVGTokens {
			return "", fmt.Errorf("svg contains too many tokens")
		}

		switch typed := token.(type) {
		case xml.StartElement:
			elementStack = append(elementStack, typed.Name)
			depth++
			if depth > maxSVGDepth {
				return "", fmt.Errorf("svg nesting depth exceeds %d", maxSVGDepth)
			}
			if rootClosed {
				return "", fmt.Errorf("svg contains multiple root elements")
			}
			if !rootSeen {
				if !strings.EqualFold(typed.Name.Local, "svg") {

View on GitHub (pinned to 9f775e8a12)