siyuan-note/siyuan · error
root element is not svg
Error message
root element is not svg
What it means
SanitizeSVG requires the first (root) XML element of the input to be an <svg> element. When the first StartElement token has a local name other than 'svg' (compared case-insensitively), the sanitizer refuses the input entirely because anything wrapped in a non-SVG root is not a valid standalone SVG image and could be an attempt to smuggle other content.
Source
Thrown at kernel/util/misc.go:377
}
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") {
return "", fmt.Errorf("root element is not svg")
}
rootSeen = true
}
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)
}View on GitHub (pinned to 8641553a1f)
Solutions
- Make the root element of the input a plain <svg> element (namespace http://www.w3.org/2000/svg), e.g. wrap fragments: <svg xmlns="http://www.w3.org/2000/svg">...</svg>
- Verify no leading non-element markup that could be mis-parsed as an element; comments/procinsts are allowed before the root
- Check the namespace prefix of the root: with decoder.Strict=true an undeclared prefix makes Space!=Local=='svg'; declare xmlns:s="http://www.w3.org/2000/svg" so the local name resolves correctly
- Strip surrounding HTML/wrapper markup before calling SanitizeSVG
Example fix
// before
SanitizeSVG("<g><rect/></g>") // root element is not svg
// after
SanitizeSVG("<svg xmlns=\"http://www.w3.org/2000/svg\"><g><rect/></g></svg>") Defensive patterns
Strategy: validation
Validate before calling
func looksLikeSVG(input string) bool {
s := strings.TrimSpace(input)
for strings.HasPrefix(s, "<?") { if i := strings.Index(s, "?>"); i >= 0 { s = strings.TrimSpace(s[i+2:]) } else { break } }
return strings.HasPrefix(strings.ToLower(s), "<svg") || strings.HasPrefix(strings.ToLower(s), "<!doctype")
} Type guard
func isSVGRoot(input string) bool {
dec := xml.NewDecoder(strings.NewReader(input))
for {
tok, err := dec.RawToken()
if err != nil { return false }
switch t := tok.(type) {
case xml.StartElement:
return strings.EqualFold(t.Name.Local, "svg")
case xml.Comment, xml.ProcInst, xml.Directive, xml.CharData:
continue
default:
return false
}
}
} Try / catch
clean, err := util.SanitizeSVG(input)
if err != nil {
if strings.Contains(err.Error(), "root element is not svg") {
input = wrapAsSVGDocument(input) // add <svg xmlns=...> wrapper
clean, err = util.SanitizeSVG(input)
}
if err != nil { return fmt.Errorf("invalid svg icon: %w", err) }
} Prevention
- Always pass a complete SVG document whose first element is <svg>, not a fragment
- Declare the SVG namespace xmlns="http://www.w3.org/2000/svg" on the root
- Trim whitespace and strip HTML wrappers from user pastes before sanitizing
- Pre-validate the first element with a strict XML token read
When it happens
Trigger: Calling SanitizeSVG with input whose first element is not <svg>: an HTML fragment, a <defs> or <g> fragment pasted from another file, a prefixed root like <s:svg> whose namespace prefix the strict decoder does not resolve, or any markup before the svg tag (the first element seen must be svg).
Common situations: Users pasting partial SVG snippets (inner content only) into custom emoji / dynamic icon fields; templates that wrap icons in wrapper elements; documents that begin with comments/DOCTYPE are fine, but documents that begin with another element (e.g. <html> or an <img> wrapper) are not.
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 text outside the root element
- svg contains an unexpected closing element
- svg closing element %q does not match %q
- svg directives are not allowed
- svg root element is incomplete
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/a8304a6159b8b69f.
Report an issue: GitHub.