{"record":{"id":"44e6463079423a08","repo":"siyuan-note/siyuan","slug":"html-to-markdown-panicked-v","errorCode":null,"errorMessage":"HTML to Markdown panicked: %v","messagePattern":"HTML to Markdown panicked: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/webfetch.go","lineNumber":125,"sourceCode":"\tdefault: // markdown\n\t\tmd, mdErr := safeHTML2Markdown(engine, htmlStr)\n\t\tif mdErr != nil {\n\t\t\treturn \"\", errors.New(\"HTML to Markdown conversion failed: \" + mdErr.Error())\n\t\t}\n\t\tresult = md\n\t}\n\n\tif result == \"\" {\n\t\treturn htmlStr, nil\n\t}\n\n\treturn truncateRunes(result, maxWebFetchChars), nil\n}\n\nfunc safeHTML2Markdown(engine *lute.Lute, htmlStr string) (result string, err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\terr = fmt.Errorf(\"HTML to Markdown panicked: %v\", r)\n\t\t}\n\t}()\n\tresult, err = engine.HTML2Markdown(htmlStr)\n\treturn\n}\n\nfunc safeHTML2Text(engine *lute.Lute, htmlStr string) (result string, err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\terr = fmt.Errorf(\"HTML to text panicked: %v\", r)\n\t\t}\n\t}()\n\tresult = engine.HTML2Text(htmlStr)\n\treturn\n}\n\nfunc truncateRunes(s string, maxChars int) string {\n\trunes := []rune(s)","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/util/webfetch.go#L107-L143","documentation":"This is the panic-derived error constructed inside safeHTML2Markdown (webfetch.go:122-127). engine.HTML2Markdown panicked and the deferred recover() caught it, converting the runtime panic value into fmt.Errorf(\"HTML to Markdown panicked: %v\", r). It surfaces as the inner cause wrapped by error 1186. It signals an internal parser/stack fault, not a routine parse error.","triggerScenarios":"Stack overflow from pathological DOM nesting, nil-pointer dereference inside lute on unexpected input, recursive grammar blow-up, or an invariant violation in lute's AST handling.","commonSituations":"Adversarial/hand-crafted HTML, very large deeply nested tables, pages engineered to stress parsers, a lute version regression.","solutions":["Switch to format=\"text\" (safeHTML2Text) or accept the raw HTML fallback path.","Upgrade lute from 88250/lute and rebuild — panic fixes land upstream.","Binary-search the input to find the minimal HTML fragment that triggers the panic and report it upstream with that sample.","Because truncation happens AFTER conversion, pre-truncating huge HTML before calling may avoid stack blow-up."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":"func isHTML2MarkdownPanic(err error) bool {\n    return err != nil && strings.HasPrefix(err.Error(), \"HTML to Markdown panicked:\")\n}","tryCatchPattern":"// safeHTML2Markdown already recovers the panic, so the caller sees an error,\n// not a crash. Fall back to text or raw HTML.\nout, err := util.WebFetch(raw, \"markdown\")\nif err != nil && isHTML2MarkdownPanic(err) {\n    out, err = util.WebFetch(raw, \"text\")\n}","preventionTips":["Treat any panic-derived error as a lute bug to report upstream with a reduced HTML sample.","Pre-truncate huge HTML before converting — truncation currently happens only AFTER conversion.","Keep lute upgraded; parser panic fixes land in 88250/lute."],"tags":["panic","lute","parsing","recover"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}