← Back to Lessons Lesson 17 of 28
Intermediate getting-started

Error Handling in Wasm

Why Error Handling Matters in Wasm

When Rust panics in Wasm, the browser shows a cryptic unreachable error. Proper error handling converts Rust errors into meaningful JavaScript exceptions.

The Two Approaches

1. Result<T, JsValue> — Errors become JS exceptions

#[wasm_bindgen]
pub fn safe_divide(a: f64, b: f64) -> Result<f64, JsValue> {
    if b == 0.0 {
        Err(JsValue::from_str("Division by zero"))
    } else {
        Ok(a / b)
    }
}

In JavaScript:

try {
    const result = safe_divide(10, 0);
} catch (e) {
    console.error(e); // "Division by zero"
}

2. Option<T> — Returns undefined on failure

#[wasm_bindgen]
pub fn find_user(id: u32) -> Option<String> {
    if id == 1 { Some("Alice".to_string()) } else { None }
}

In JavaScript:

const user = find_user(99);
if (user === undefined) {
    console.log("User not found");
}

Converting Between Error Types

The ? operator works with Result, but Wasm needs JsValue errors:

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn parse_and_double(input: &str) -> Result<i32, JsValue> {
    let num: i32 = input.parse()
        .map_err(|e: std::num::ParseIntError| {
            JsValue::from_str(&format!("Parse error: {}", e))
        })?;
    Ok(num * 2)
}

Custom Error Types

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub struct WasmError {
    code: u32,
    message: String,
}

#[wasm_bindgen]
impl WasmError {
    pub fn code(&self) -> u32 { self.code }
    pub fn message(&self) -> String { self.message.clone() }
}

fn make_error(code: u32, msg: &str) -> JsValue {
    let err = WasmError { code, message: msg.to_string() };
    JsValue::from(err)
}

Panic Hook — Last Resort

For panics you can't prevent, install the panic hook to get readable messages:

use console_error_panic_hook;

#[wasm_bindgen(start)]
pub fn init() {
    console_error_panic_hook::set_once();
}

Without it: RuntimeError: unreachable With it: panicked at 'index out of bounds: the len is 3 but the index is 5'

Best Practices

Do Don't
Return Result<T, JsValue> from exported functions Let functions panic
Use ? with .map_err() to convert errors Use .unwrap() in exported functions
Install console_error_panic_hook Ignore panics
Give meaningful error messages Return generic "error occurred"
Use Option<T> for "not found" cases Return sentinel values (-1, empty string)

Try It

Click Run to see the error handling patterns in action. Notice how each error type produces a clear, descriptive message.

Try It

Chapter Quiz

Pass all questions to complete this lesson