{"record":{"id":"aee9595fac752222","repo":"siyuan-note/siyuan","slug":"parse-svg-failed-w","errorCode":null,"errorMessage":"parse svg failed: %w","messagePattern":"parse svg failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/misc.go","lineNumber":358,"sourceCode":"\tdecoder := xml.NewDecoder(strings.NewReader(svgInput))\n\tdecoder.Strict = true\n\n\tvar buf bytes.Buffer\n\tencoder := xml.NewEncoder(&buf)\n\trootSeen := false\n\trootClosed := false\n\tdepth := 0\n\tskipDepth := 0\n\ttokenCount := 0\n\tvar elementStack []xml.Name\n\n\tfor {\n\t\ttoken, err := decoder.RawToken()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"parse svg failed: %w\", err)\n\t\t}\n\t\ttokenCount++\n\t\tif tokenCount > maxSVGTokens {\n\t\t\treturn \"\", fmt.Errorf(\"svg contains too many tokens\")\n\t\t}\n\n\t\tswitch typed := token.(type) {\n\t\tcase xml.StartElement:\n\t\t\telementStack = append(elementStack, typed.Name)\n\t\t\tdepth++\n\t\t\tif depth > maxSVGDepth {\n\t\t\t\treturn \"\", fmt.Errorf(\"svg nesting depth exceeds %d\", maxSVGDepth)\n\t\t\t}\n\t\t\tif rootClosed {\n\t\t\t\treturn \"\", fmt.Errorf(\"svg contains multiple root elements\")\n\t\t\t}\n\t\t\tif !rootSeen {\n\t\t\t\tif !strings.EqualFold(typed.Name.Local, \"svg\") {","sourceCodeStart":340,"sourceCodeEnd":376,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/util/misc.go#L340-L376","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Validate the SVG with an XML parser (e.g. xmllint --noout file.svg) and fix the reported syntax error","Ensure the file is complete and UTF-8 encoded, not truncated in transfer","If the source is HTML-ish SVG, convert it to well-formed XML (self-close tags, escape & as &amp;)","Re-export the SVG from the design tool with XML-compliant output options"],"exampleFix":"// before (invalid XML)\n<svg><desc>a & b</desc></svg>\n// after\n<svg><desc>a &amp; b</desc></svg>","handlingStrategy":"validation","validationCode":"func isWellFormedXML(svg string) bool {\n    d := xml.NewDecoder(strings.NewReader(svg))\n    d.Strict = true\n    for {\n        _, err := d.RawToken()\n        if err == io.EOF { return true }\n        if err != nil { return false }\n    }\n}","typeGuard":null,"tryCatchPattern":"clean, err := util.SanitizeSVG(input)\nif err != nil && strings.HasPrefix(err.Error(), \"parse svg failed\") {\n    return fmt.Errorf(\"input is not well-formed XML, re-export the SVG: %w\", err)\n}","preventionTips":["Pre-validate user SVG uploads with a strict XML parser","Reject HTML-flavored markup at ingestion time","Ensure files are complete and UTF-8 before sanitizing","Never hand-edit SVG tags; re-export from the tool"],"tags":["svg","xml","parsing","sanitization"],"backgroundTag":"xml-parse-error","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}