wasmerio/wasmer · error

Internal error: Module with handle {module_handle:?} was alr

Error message

Internal error: Module with handle {module_handle:?} was already instantiated in this group

What it means

allocate_function_table_for_existing_module panics if the given ModuleHandle is already present in the group's side_instances map. Each module in a dynamic-linking group must be instantiated at most once; re-instantiating the same handle would allocate duplicate table/memory regions and corrupt the group state.

Source

Thrown at lib/wasix/src/state/linker/instance_group/table.rs:104

            let existing = table.get(store, index).unwrap();
            if let Value::FuncRef(Some(_)) = existing {
                panic!("Internal error: function table index {index} already occupied");
            }
        }

        let ty = func.ty(store).to_string();
        trace!(?index, ?ty, "Placing function in table at index");
        table.set(store, index, Value::FuncRef(Some(func)))
    }

    pub(super) fn allocate_function_table_for_existing_module(
        &mut self,
        linker_state: &LinkerState,
        store: &mut impl AsStoreMut,
        module_handle: ModuleHandle,
    ) -> Result<(), LinkError> {
        if self.side_instances.contains_key(&module_handle) {
            panic!(
                "Internal error: Module with handle {module_handle:?} \
                was already instantiated in this group"
            )
        };

        let dl_module = linker_state
            .side_modules
            .get(&module_handle)
            .expect("Internal error: module not loaded into linker");

        let table_base = self
            .allocate_function_table(
                store,
                dl_module.dylink_info.mem_info.table_size,
                dl_module.dylink_info.mem_info.table_alignment,
            )
            .map_err(LinkError::TableAllocationError)?;

View on GitHub (pinned to 8c4b9ee9d3)

Solutions

  1. Deduplicate dlopen calls: check whether the module is already loaded in the group before requesting instantiation
  2. Reset/rebuild the InstanceGroup if you intentionally want a fresh instantiation of the same module
  3. Ensure dlopen caching semantics are honored (same path returns the same handle, not a new load)

Example fix

// before
let h = runtime.dlopen("libfoo.so")?;
let h2 = runtime.dlopen("libfoo.so")?; // panics on second instantiate
// after
let h = runtime.dlopen("libfoo.so")?;
// reuse h for subsequent calls; dlopen is idempotent per group
Defensive patterns

Strategy: validation

Validate before calling

fn can_instantiate(group: &InstanceGroup, h: &ModuleHandle) -> bool {
    !group.side_instances.contains_key(h)
}
// before apply_dl_operation: assert!(can_instantiate(&group, &handle));

Type guard

fn is_fresh_handle(h: &ModuleHandle, loaded: &HashSet<ModuleHandle>) -> bool {
    !loaded.contains(h)
}

Prevention

When it happens

Trigger: apply_dl_operation issuing a load/instantiate for a module handle that was already instantiated in this instance group; dlopen called twice for the same module without deduplication; replaying an operation log that contains a duplicate load.

Common situations: Application code calling dlopen on the same .so twice expecting a fresh instance; a dynamic loader replaying DL operations after a partial failure and retry without state reset.

Related errors


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