Error Handling
convert() returns Result<ConversionResult, ConversionError> in Rust. Every other binding maps the error to its native idiom: Python raises an exception, Go returns (result, error), Java throws a checked exception, and so on.
Non-fatal issues never produce an error. They accumulate in result.warnings and the call still succeeds.
ConversionError Variants
Section titled “ConversionError Variants”Eight variants. All carry a String message except IoError, which wraps std::io::Error via #[from].
| Variant | Payload | Cause |
|---|---|---|
ParseError |
String |
Malformed HTML the parser could not recover from. |
SanitizationError |
String |
Reserved for binding use. The core library never constructs this variant today — there is no sanitization pass; convert() does not reject or clean unsafe markup. |
ConfigError |
String |
ConversionOptions contains an invalid combination (unknown format string, out-of-range width, etc.). |
IoError |
std::io::Error |
Reading a file, reading stdin, or writing output failed. |
Panic |
String |
A panic was caught inside the conversion core. The FFI boundaries catch unwinds so other bindings see a normal error instead of a crash. |
InvalidInput |
String |
Binary/corrupted data detected (compressed data, excess NUL or control bytes, undeclared UTF-16), or decoding failure for a wrong encoding setting. There is no input size cap — see Security. |
Visitor |
String |
A visitor callback returned VisitResult::Error(...). Only compiled with features = ["visitor"]. Rust users on default features never see this variant. |
Other |
String |
Catch-all for anything that does not fit above. |
Warnings
Section titled “Warnings”result.warnings is a Vec<ProcessingWarning>. Each warning has a kind and a message. The CLI prints them to stderr with --show-warnings; in library code, iterate and log them yourself.
Warnings are the right place to surface “this was weird but the conversion worked” signals: skipped oversized images, unknown class attributes on code blocks, malformed table rows that were repaired. None of these halt the call.
Handling Patterns
Section titled “Handling Patterns”use html_to_markdown_rs::convert;use html_to_markdown_rs::error::ConversionError;
fn main() { // Binary data (detected via magic bytes) is rejected before parsing. let html = "%PDF-1.4 not actually HTML";
match convert(html, None) { Ok(result) => println!("{}", result.content.unwrap_or_default()), Err(ConversionError::InvalidInput(message)) => { eprintln!("invalid input: {message}"); } Err(ConversionError::ParseError(message)) => { eprintln!("parse error: {message}"); } Err(other) => eprintln!("conversion failed: {other}"), }}from html_to_markdown import convertfrom html_to_markdown.exceptions import InvalidInputError
# Binary data (detected via magic bytes) is rejected before parsing.html = "%PDF-1.4 not actually HTML"
try: result = convert(html) markdown = result.contentexcept InvalidInputError as error: print(f"invalid input: {error}")import { convert } from "@xberg-io/html-to-markdown";
// Binary data (detected via magic bytes) is rejected before parsing.const html = "%PDF-1.4 not actually HTML";
try { const result = convert(html); console.log(result.content ?? "");} catch (error) { // The native binding surfaces conversion failures as a standard Error. console.error("conversion failed:", (error as Error).message);}package main
import ( "fmt"
htmltomarkdown "github.com/xberg-io/html-to-markdown/packages/go/v3")
func main() { // Binary data (detected via magic bytes) is rejected before parsing. html := "%PDF-1.4 not actually HTML"
result, err := htmltomarkdown.Convert(html, nil) if err != nil { // Convert wraps the FFI error as "[<code>] <message>". fmt.Println("conversion failed:", err) return }
if result.Content != nil { fmt.Println(*result.Content) }}require 'html_to_markdown'
# Binary data (detected via magic bytes) is rejected before parsing.html = "%PDF-1.4 not actually HTML"
begin result = HtmlToMarkdown.convert(html) markdown = result.contentrescue RuntimeError => e # Native conversion failures surface as RuntimeError with the Rust error message. warn "conversion failed: #{e.message}"enduse HtmlToMarkdown\HtmlToMarkdownApi;
// Binary data (detected via magic bytes) is rejected before parsing.$html = '%PDF-1.4 not actually HTML';
try { $result = HtmlToMarkdownApi::convert($html); echo $result->content;} catch (\Exception $e) { // Native conversion failures surface as \Exception, prefixed with the // Rust error variant, e.g. "[InvalidInput] Invalid input: ...". fwrite(STDERR, 'conversion failed: ' . $e->getMessage() . "\n");}import io.xberg.htmltomarkdown.HtmlToMarkdown;import io.xberg.htmltomarkdown.ConversionResult;import io.xberg.htmltomarkdown.InvalidInputException;import io.xberg.htmltomarkdown.HtmlToMarkdownRsException;
public class Example { public static void main(String[] args) { // Binary data (detected via magic bytes) is rejected before parsing. String html = "%PDF-1.4 not actually HTML";
try { ConversionResult result = HtmlToMarkdown.convert(html); System.out.println(result.content()); } catch (InvalidInputException e) { System.err.println("invalid input: " + e.getMessage()); } catch (HtmlToMarkdownRsException e) { System.err.println("conversion failed: " + e.getMessage()); } }}using HtmlToMarkdown;
// Binary data (detected via magic bytes) is rejected before parsing.var html = "%PDF-1.4 not actually HTML";
try{ var result = HtmlToMarkdownConverter.Convert(html, null); Console.WriteLine(result.Content);}catch (InvalidInputException e){ Console.Error.WriteLine($"invalid input: {e.Message}");}catch (ConversionErrorException e){ Console.Error.WriteLine($"conversion failed: {e.Message}");}# Binary data (detected via magic bytes) is rejected before parsing.html = "%PDF-1.4 not actually HTML"
case HtmlToMarkdown.convert(html) do {:ok, result} -> IO.puts(result.content)
{:error, message} -> IO.puts(:stderr, "conversion failed: #{message}")endlibrary(htmltomarkdown)
# Binary data (detected via magic bytes) is rejected before parsing.html <- "%PDF-1.4 not actually HTML"
result <- tryCatch( convert(html), error = function(e) { message("conversion failed: ", conditionMessage(e)) NULL })
if (!is.null(result)) { cat(result$content)}#include "html_to_markdown.h"#include <stdio.h>
int main(void) { /* Binary data (detected via magic bytes) is rejected before parsing. */ HTMAlefHandle result = htm_convert("%PDF-1.4 not actually HTML", 0); if (result == 0) { fprintf(stderr, "convert failed (code %d): %s\n", htm_last_error_code(), htm_last_error_context()); return 1; }
char *content = htm_conversion_result_content(result); if (content != NULL) { printf("%s\n", content); htm_free_string(content); }
htm_conversion_result_free(result); return 0;}import HtmlToMarkdown
do { let result = try convert(html: "<h1>Hello</h1>") print(result.content()?.toString() ?? "")} catch let ConversionError.parseError(message, _) { print("Parse failed: \(message)")} catch let error as ConversionError { print("Conversion failed: \(error)")}import 'package:h2m/h2m.dart';import 'package:h2m/src/html_to_markdown_rs_bridge_generated/frb_generated.dart' show RustLib;
Future<void> main() async { await RustLib.init();
try { final result = await H2mBridge.convert('<h1>Hello</h1>'); print(result.content); } catch (error) { // ConversionError variants surface via flutter_rust_bridge as thrown errors. print('Conversion failed: $error'); }}import io.xberg.android.HtmlToMarkdownimport io.xberg.android.HtmlToMarkdownRsBridgeException
fun main() { try { val result = HtmlToMarkdown.convert("<h1>Hello</h1>") println(result.content) } catch (error: HtmlToMarkdownRsBridgeException) { System.err.println("Conversion failed: ${error.message}") }}const std = @import("std");const html_to_markdown = @import("html_to_markdown_rs");
pub fn main() !void { const result_json = html_to_markdown.convert("<h1>Hello</h1>", null) catch |err| switch (err) { html_to_markdown.ConversionError.ParseError => { std.debug.print("Parse failed\n", .{}); return; }, else => return err, }; defer std.heap.c_allocator.free(result_json);
std.debug.print("{s}\n", .{result_json});}CLI Warnings
Section titled “CLI Warnings”The CLI hides warnings by default. Pass --show-warnings to print each one to stderr in the format Warning [<kind>]: <message>. The flag works with or without --json. See CLI: JSON Output.
Found a bug or mistake on this page?
If something here is wrong or out of date, open an issue on GitHub or contribute a fix via pull request.