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

  1. Fix the guest module to free each closure index exactly once and only after `closure_prepare` succeeded
  2. Verify the closure index passed to the syscall is within the allocated range before freeing
  3. Serialize closure allocation/free across threads or use the runtime's locking helpers to prevent double-free races
  4. 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

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


AI-assisted analysis of wasmerio/wasmer@8c4b9ee9d3 (2026-09-01). Data as JSON: /api/errors/f6315b798dcbc4a1. Report an issue: GitHub.