wasmerio/wasmer · error

duplicate function

Error message

duplicate function

What it means

This panic comes from `unreachable!("duplicate function")` in wasmtime's LLVM intrinsics translator. The function cache (`cached_functions` map keyed by `function_index`) is being inserted into for an index that already has a cached `FunctionCache`, which the code assumes can never happen. It means the translation pipeline tried to define/declare the same function twice, violating the one-entry-per-function invariant.

Source

Thrown at lib/compiler-llvm/src/translator/intrinsics.rs:1869

                        value_type: type_to_llvm(intrinsics, global_value_type)?,
                    },
                });

                Ok(ret)
            }
        }
    }

    pub fn add_func(
        &mut self,
        function_index: FunctionIndex,
        func: PointerValue<'ctx>,
        llvm_func_type: FunctionType<'ctx>,
        vmctx: BasicValueEnum<'ctx>,
        attrs: &[(Attribute, AttributeLoc)],
    ) {
        match self.cached_functions.entry(function_index) {
            Entry::Occupied(_) => unreachable!("duplicate function"),
            Entry::Vacant(entry) => {
                entry.insert(FunctionCache {
                    func,
                    llvm_func_type,
                    vmctx,
                    imported_include_m0_param: None,
                    attrs: attrs.to_vec(),
                });
            }
        }
    }

    #[allow(clippy::too_many_arguments)]
    pub fn local_func(
        &mut self,
        _local_function_index: LocalFunctionIndex,
        function_index: FunctionIndex,
        intrinsics: &Intrinsics<'ctx>,

View on GitHub (pinned to 8c4b9ee9d3)

Solutions

  1. Validate the wasm module first (`wasm-tools validate`) to rule out a malformed binary
  2. Upgrade wasmtime — this invariant violation is typically fixed in newer releases
  3. If you control the module pipeline, check for double-compilation of the same module (e.g. caching compiled artifacts instead of recompiling)
  4. If running a fork, diff your intrinsics.rs against upstream to find the duplicate registration
  5. File a wasmtime issue with the reproducing module

Example fix

// before: recompiling the same module per instantiation
for _ in 0..2 { engine.compile(&module_bytes)?; }
// after
let module = Module::new(&engine, &module_bytes)?; // compile once, reuse the Module
Defensive patterns

Strategy: try-catch

Validate before calling

// catch process-level panics from the compiler thread so a bad module cannot kill the host
std::panic::set_hook(Box::new(|info| log::error!("wasmtime compiler panic: {info}")));

Try / catch

let result = std::panic::catch_unwind(|| {
    Module::new(&engine, &bytes).map_err(|e| anyhow::anyhow!(e))
});
match result {
    Ok(Ok(module)) => module,
    Ok(Err(e)) | Err(_) => { validate_and_report_module(&bytes); bail!("compile failed (possible double registration)"); }
}

Prevention

When it happens

Trigger: The same `function_index` is passed twice to the cache-filling helper during LLVM translation — e.g. a module whose function index space maps two entries to one intrinsic definition, or a bug/regression in the translation driver that re-invokes function translation for an already-cached index.

Common situations: Corrupted or hand-crafted wasm binaries with inconsistent function index spaces; wasmtime version mismatches where multi-memory or multi-value features shift index mapping; forks of wasmtime with custom intrinsic handling.

Related errors


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