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
- Deduplicate dlopen calls: check whether the module is already loaded in the group before requesting instantiation
- Reset/rebuild the InstanceGroup if you intentionally want a fresh instantiation of the same module
- 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
- Cache dlopen results by path and reuse the existing handle
- Reset the InstanceGroup before replaying load operations
- Treat dlopen as idempotent per group
- Track loaded handles explicitly in your loader wrapper
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
- Internal error: $ORIGIN or ${{ORIGIN}} in RUNPATH, but no ca
- Internal error: missing symbol resolution record for '{0}'.{
- Internal error: failed to resolve function {}: {e:?}
- Internal error: resolution record for symbol {name} indicate
- Internal error: function table index {index} already occupie
AI-assisted analysis of wasmerio/wasmer@8c4b9ee9d3 (2026-09-01).
Data as JSON: /api/errors/b0172981f4a531a2.
Report an issue: GitHub.