siyuan-note/siyuan · error

HTML to Markdown panicked: %v

Error message

HTML to Markdown panicked: %v

What it means

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.

Source

Thrown at kernel/util/webfetch.go:125

	default: // markdown
		md, mdErr := safeHTML2Markdown(engine, htmlStr)
		if mdErr != nil {
			return "", errors.New("HTML to Markdown conversion failed: " + mdErr.Error())
		}
		result = md
	}

	if result == "" {
		return htmlStr, nil
	}

	return truncateRunes(result, maxWebFetchChars), nil
}

func safeHTML2Markdown(engine *lute.Lute, htmlStr string) (result string, err error) {
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("HTML to Markdown panicked: %v", r)
		}
	}()
	result, err = engine.HTML2Markdown(htmlStr)
	return
}

func safeHTML2Text(engine *lute.Lute, htmlStr string) (result string, err error) {
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("HTML to text panicked: %v", r)
		}
	}()
	result = engine.HTML2Text(htmlStr)
	return
}

func truncateRunes(s string, maxChars int) string {
	runes := []rune(s)

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Switch to format="text" (safeHTML2Text) or accept the raw HTML fallback path.
  2. Upgrade lute from 88250/lute and rebuild — panic fixes land upstream.
  3. Binary-search the input to find the minimal HTML fragment that triggers the panic and report it upstream with that sample.
  4. Because truncation happens AFTER conversion, pre-truncating huge HTML before calling may avoid stack blow-up.
Defensive patterns

Strategy: fallback

Type guard

func isHTML2MarkdownPanic(err error) bool {
    return err != nil && strings.HasPrefix(err.Error(), "HTML to Markdown panicked:")
}

Try / catch

// safeHTML2Markdown already recovers the panic, so the caller sees an error,
// not a crash. Fall back to text or raw HTML.
out, err := util.WebFetch(raw, "markdown")
if err != nil && isHTML2MarkdownPanic(err) {
    out, err = util.WebFetch(raw, "text")
}

Prevention

When it happens

Trigger: 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.

Common situations: Adversarial/hand-crafted HTML, very large deeply nested tables, pages engineered to stress parsers, a lute version regression.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/44e6463079423a08. Report an issue: GitHub.