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
- Validate the wasm module first (`wasm-tools validate`) to rule out a malformed binary
- Upgrade wasmtime — this invariant violation is typically fixed in newer releases
- If you control the module pipeline, check for double-compilation of the same module (e.g. caching compiled artifacts instead of recompiling)
- If running a fork, diff your intrinsics.rs against upstream to find the duplicate registration
- 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
- Always run wasmparser::Validator::validate_all on untrusted modules before compilation
- Compile each module once and reuse the Module/Instance instead of recompiling
- Keep wasmtime and its object/wasmtime-env dependencies on versions from the same lockfile
- Compile on a worker thread so a compiler panic does not abort the host process
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
- Can't form ExtraInfo with two pending canonicalization
- Unhandled internal variant
- internal error: entered unreachable code
- Symbol {} in DWARF not recognized
- internal error: entered unreachable code
AI-assisted analysis of wasmerio/wasmer@8c4b9ee9d3 (2026-09-01).
Data as JSON: /api/errors/9b20f63f86110821.
Report an issue: GitHub.