wasmerio/wasmer · error

Internal error: function table index

Error message

Internal error: function table index {index} already occupied

What it means

place_in_function_table_at panics when trying to write a resolved function reference into an element of the indirect function table that already holds a live FuncRef. The linker assumes each allocated table slot is empty before placement; a non-null entry means the allocation/placement bookkeeping is out of sync. It is an internal invariant check for the dynamic-linking (dlopen-style) function table.

Solutions

  1. Ensure each shared module is instantiated only once per InstanceGroup (deduplicate dlopen of the same path)
  2. Recompile the shared modules so their dylink metadata (table_size, table_base, alignment) is consistent with the current compiler version
  3. Avoid calling finalize_pending_resolutions_from_linker / populate_imports_from_linker more than once for the same group
  4. Clear or rebuild the instance group if it was reused across link runs

Example fix

// before: reusing the same instance group for a second dlopen of the same module
group.apply_dl_operation(DlOperation::Load { module: same_handle, ... });
// after: check before loading
if !group.contains_module(&same_handle) {
    group.apply_dl_operation(DlOperation::Load { module: same_handle, ... });
}
Defensive patterns

Strategy: validation

Validate before calling

fn slot_is_free(store: &impl AsStoreRef, table: &Table, index: u64) -> bool {
    !matches!(table.get(store, index), Some(Value::FuncRef(Some(_))))
}
// check before placement: if !slot_is_free(store, &table, index) { skip or reallocate }

Type guard

fn is_free_slot(v: Option<&Value>) -> bool {
    !matches!(v, Some(Value::FuncRef(Some(_))))
}

Prevention

When it happens

Trigger: apply_dl_operation / populate_imports_from_linker / finalize_pending_resolutions_from_linker placing two resolved functions at the same table index; re-running apply_resolved_function for an index that was already populated; a table_base misalignment causing index overlap.

Common situations: Loading the same shared module twice into one instance group; table_size/table_alignment metadata (dylink info) of the compiled shared module not matching what the linker assumed; repeated finalize calls on the same linker state.

Related errors


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

Appendix: source

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

            ?func,
            "Placing function in table at pre-defined index"
        );

        let table = &self.indirect_function_table;
        let size = table.size(store);

        if size <= index {
            let delta = index - size + 1;
            trace!(
                current_size = ?size,
                ?delta,
                "Growing indirect function table"
            );
            table.grow(store, delta, Value::FuncRef(None))?;
        } else {
            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"

View on GitHub (pinned to 8c4b9ee9d3)