siyuan-note/siyuan · error
svg root element is incomplete
Error message
svg root element is incomplete
What it means
After consuming all tokens, SanitizeSVG requires: a root was seen, it was closed, depth returned to 0, no unsafe-subtree skip was in progress, and the element stack is empty. If any of these invariants fail — truncated input, unclosed unsafe element, or the root never closed — the input is not a complete SVG document and is rejected.
Source
Thrown at kernel/util/misc.go:450
}
case xml.Comment:
if skipDepth == 0 && rootSeen && !rootClosed {
if err = encoder.EncodeToken(typed); err != nil {
return "", fmt.Errorf("render svg failed: %w", err)
}
}
case xml.Directive:
if !isBenignSVGDoctype(string(typed)) {
return "", fmt.Errorf("svg directives are not allowed")
}
// 良性 DOCTYPE 声明不写入输出,与 XML 声明(ProcInst)的处理方式一致,不影响浏览器渲染
case xml.ProcInst:
// XML 声明和处理指令不影响 SVG 图像内容,输出时统一省略。
}
}
if !rootSeen || !rootClosed || depth != 0 || skipDepth != 0 || len(elementStack) != 0 {
return "", fmt.Errorf("svg root element is incomplete")
}
if err := encoder.Close(); err != nil {
return "", fmt.Errorf("render svg failed: %w", err)
}
return buf.String(), nil
}
func preserveXMLName(name xml.Name) xml.Name {
if name.Space != "" {
name.Local = name.Space + ":" + name.Local
name.Space = ""
}
return name
}
// isBenignSVGDoctype 判断 DOCTYPE 是否仅为 svg 根元素的无内部子集声明。
// Go 的 xml.Directive 是 <! 与 > 之间的内容;内部子集 [...] 内可声明实体,存在 XXE 风险,一律拒绝。
func isBenignSVGDoctype(d string) bool {View on GitHub (pinned to 8641553a1f)
Solutions
- Provide the complete '<svg>...</svg>' document including all closing tags
- Check for truncation: compare input length/hash against the source file, or verify it ends with '</svg>' (modulo trailing whitespace)
- Ensure no element (especially filtered ones like <script>) is left unclosed, which leaves skipDepth non-zero
- If accepting fragments, wrap them in a complete svg root and close all elements before sanitizing
Example fix
// before
SanitizeSVG("<svg><rect/></svg") // truncated -> svg root element is incomplete
// after
SanitizeSVG("<svg xmlns=\"http://www.w3.org/2000/svg\"><rect/></svg>") Defensive patterns
Strategy: validation
Validate before calling
func svgDocComplete(input string) bool {
s := strings.TrimSpace(input)
return strings.HasPrefix(strings.ToLower(s), "<") && strings.HasSuffix(s, "</svg>")
} Type guard
func isCompleteSVG(input string) bool {
if !strings.Contains(strings.ToLower(input), "<svg") { return false }
if !strings.Contains(strings.ToLower(input), "</svg>") { return false }
dec := xml.NewDecoder(strings.NewReader(input))
_, err := xmldecAll(dec) // any full-token loop that runs to io.EOF without error
return err == nil
} Try / catch
clean, err := util.SanitizeSVG(input)
if err != nil && strings.Contains(err.Error(), "incomplete") {
return fmt.Errorf("svg upload appears truncated; re-upload the full file: %w", err)
} Prevention
- Verify uploads end with '</svg>' before passing to the sanitizer
- Watch for size limits on input fields that may truncate large icons
- Check network/file-transfer code for partial reads (compare byte counts)
- Reject fragments: require a full document with every tag closed
When it happens
Trigger: Input truncated mid-document: '<svg><rect/>' with no closing tags; a <script> or other unsafe element opened but its close tag cut off (skipDepth never returns to 0); input consisting only of text/comments with no elements at all (rootSeen=false).
Common situations: Paste cut off by a size-limited input field; network transfer truncation; string processing that dropped the tail of the file; partial fragments saved as icon files.
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
- root element is not svg
- svg contains an unexpected closing element
- svg closing element %q does not match %q
- svg contains text outside the root element
- render svg failed: %w
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/3d6483e9c460bd66.
Report an issue: GitHub.