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`).
///
/// # ArgumentsView on GitHub (pinned to d16f7ba2ed)
Solutions
- Fix the panic in the closure you pass to Module::map — inspect the original panic message printed before this one.
- Validate snapshot compatibility (shapes, dtypes, device) before calling apply instead of asserting inside the closure.
- 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
- Never unwrap/panic inside closures passed to Module::map
- Validate shapes/dtypes/devices against the snapshot before applying
- Treat the module as unusable after this panic — rebuild from source
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
- Failed to load record
- capture tensor operations must run inside CaptureDevice::cap
- Capture tensors do not support autodiff
- Autodiff should not wrap an autodiff tensor.
- Requires autodiff tensor.
AI-assisted analysis of tracel-ai/burn@d16f7ba2ed (2026-09-05).
Data as JSON: /api/errors/e121098fe5a0d00b.
Report an issue: GitHub.