tracel-ai/burn · critical

burn-store: a panic escaped Module::map during ModuleSnapsho

Error message

burn-store: a panic escaped Module::map during ModuleSnapshot::apply, leaving the module moved-from

What it means

ModuleSnapshot::apply mutates a module in place via Module::map, temporarily moving fields out. If a user-supplied closure panics during that window, the module is left moved-from (partially destroyed). The Drop guard detects this and re-panics with this message (after aborting on std) so the invariant violation is loud instead of silently corrupt. It only fires when a panic escaped your `map` closure.

Source

Thrown at crates/burn-store/src/traits.rs:39

/// The same reasoning is why `take_mut` and `replace_with` abort rather than recover. A
/// `Default` placeholder would be the alternative, but [`Module`] carries no such bound.
struct AbortOnUnwind;

impl Drop for AbortOnUnwind {
    fn drop(&mut self) {
        // Only reached while unwinding; the success path forgets the guard.
        #[cfg(feature = "std")]
        {
            eprintln!(
                "burn-store: a panic escaped Module::map during ModuleSnapshot::apply, leaving \
                 the module moved-from. Aborting rather than dropping it twice."
            );
            std::process::abort();
        }
        // `abort` needs `std`. A panic raised while another is already unwinding ends the
        // process the same way, so no-std gets the same guarantee by a different route.
        #[cfg(not(feature = "std"))]
        panic!(
            "burn-store: a panic escaped Module::map during ModuleSnapshot::apply, leaving the \
             module moved-from"
        );
    }
}

/// Extension trait for modules that provides tensor storage functionality.
///
/// This trait provides convenient methods to collect tensors from any Burn module and apply
/// them back. Collection is lazy: each [`burn_pack::Tensor`] it returns reads its data back
/// from the device only when that data is asked for.
pub trait ModuleSnapshot: Module {
    /// Collects the module's tensors for inspection without copying data.
    ///
    /// Returns [`burn_pack::Tensor`]s that materialize their data lazily, each named by its
    /// full path in the module (`tensor.name`).
    ///
    /// # Arguments

View on GitHub (pinned to d16f7ba2ed)

Solutions

  1. Fix the panic in the closure you pass to Module::map — inspect the original panic message printed before this one.
  2. Validate snapshot compatibility (shapes, dtypes, device) before calling apply instead of asserting inside the closure.
  3. Return Result/error values from your mapping logic rather than unwrapping inside the closure.

Example fix

// before
snapshot.apply(&mut model, |param, _| Ok(param.tensor.unwrap())); // unwrap may panic -> module corrupted
// after
snapshot.apply(&mut model, |param, _| {
    param.tensor.ok_or_else(|| Error::MissingParam(param.path.clone()))
})?;
Defensive patterns

Strategy: try-catch

Validate before calling

// validate snapshot compatibility before apply
snapshot.apply(&mut model, |param, _| {
    param.tensor.as_ref().map(|_| ()).ok_or_else(|| format!("missing tensor for {}", param.path))
})?;

Try / catch

let result = std::panic::catch_unwind(AssertUnwindSafe(||
    snapshot.apply(&mut model, mapping_closure)
));
if result.is_err() { /* model may be moved-from; rebuild it */ }

Prevention

When it happens

Trigger: Calling `ModuleSnapshot::apply` (or snapshot-based load/remap of a module) with a function passed to `Module::map` that panics — e.g. unwrapping a failed tensor conversion, indexing out of bounds, or asserting inside the mapping closure.

Common situations: Applying a snapshot whose tensors don't match expected shapes/dtypes, causing an unwrap/assert inside the user closure to fail; a panicking custom initializer or post-processing hook during load/remap; double-panic scenarios during error handling.

Related errors


AI-assisted analysis of tracel-ai/burn@d16f7ba2ed (2026-09-05). Data as JSON: /api/errors/e121098fe5a0d00b. Report an issue: GitHub.