wasmerio/wasmer · error
Failed to free closure index: {e}
Error message
Failed to free closure index: {e} What it means
The `closure_free` syscall asks the linker to release a previously allocated closure slot in the `__indirect_function_table`. The library considers any failure from `free_closure_index` an impossible state ("Should never happen"), so instead of returning an errno it panics with the underlying error embedded in the message.
Source
Thrown at lib/wasix/src/syscalls/wasix/closure_free.rs:23
/// After calling this it is undefined behavior to call the function at the given index.
#[instrument(level = "trace", fields(%closure), ret)]
pub fn closure_free(
mut ctx: FunctionEnvMut<'_, WasiEnv>,
closure: u32,
) -> Result<Errno, WasiError> {
WasiEnv::do_pending_operations(&mut ctx)?;
let (env, mut store) = ctx.data_and_store_mut();
let Some(linker) = env.inner().linker().cloned() else {
error!("Closures only work for dynamic modules.");
return Ok(Errno::Notsup);
};
let free_result = linker.free_closure_index(&mut ctx, closure);
if let Err(e) = free_result {
// Should never happen
panic!("Failed to free closure index: {e}");
}
return Ok(Errno::Success);
}
View on GitHub (pinned to 8c4b9ee9d3)
Solutions
- Fix the guest module to free each closure index exactly once and only after `closure_prepare` succeeded
- Verify the closure index passed to the syscall is within the allocated range before freeing
- Serialize closure allocation/free across threads or use the runtime's locking helpers to prevent double-free races
- Rebuild the guest module against the current wasix closure ABI if versions mismatch
Defensive patterns
Strategy: validation
Validate before calling
// Guest/host side: only free indices that were successfully prepared and not yet freed
if !allocated_closures.contains(&closure) {
return; // skip free instead of calling closure_free with a bogus index
} Try / catch
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| closure_free(ctx, closure)));
if result.is_err() { /* log double-free/invalid index; recover by rebuilding the instance */ } Prevention
- Track prepared closure indices and free each exactly once
- Serialize closure alloc/free across WASIX threads
- Validate indices are in range before the syscall
- Match the guest's closure ABI version to the runtime's
When it happens
Trigger: Calling the `closure_free` syscall with a closure index that is invalid, already freed, or out of range; freeing a closure in an environment whose linker state is inconsistent (e.g. after a failed dynamic-link operation); double-free of the same closure index from two threads.
Common situations: Guest code bugs that free a closure twice or free a never-prepared index; race conditions where two WASIX threads free closures concurrently; modules compiled against a different closure ABI than the runtime supports.
Related errors
- Cannot load reference type
- Failed to load newly built in-memory module: {e}
- Internal error: failed to resolve exported function {}: {e:?
- Internal error: Tried to import TLS symbol from module {} th
- Internal error: missing import resolution '{0}'.{1}
AI-assisted analysis of wasmerio/wasmer@8c4b9ee9d3 (2026-09-01).
Data as JSON: /api/errors/f6315b798dcbc4a1.
Report an issue: GitHub.