wasmerio/wasmer · critical
Metering::transform_module_info: Attempting to use a `Meteri
Error message
Metering::transform_module_info: Attempting to use a `Metering` middleware from multiple modules.
What it means
The Metering middleware stores per-module state (a global index for remaining points) inside itself. transform_module_info detects that this state was already set, meaning the same Metering instance is being applied to a second module, which would corrupt cost accounting. It panics to enforce one-Metering-per-module usage.
Source
Thrown at lib/middlewares/src/metering.rs:169
impl<F: Fn(&Operator) -> u64 + Send + Sync + 'static> ModuleMiddleware for Metering<F> {
/// Generates a `FunctionMiddleware` for a given function.
fn generate_function_middleware<'a>(
&self,
_: LocalFunctionIndex,
) -> Box<dyn FunctionMiddleware<'a> + 'a> {
Box::new(FunctionMetering {
cost_function: self.cost_function.clone(),
global_indexes: self.global_indexes.lock().unwrap().clone().unwrap(),
accumulated_cost: 0,
})
}
/// Transforms a `ModuleInfo` struct in-place. This is called before application on functions begins.
fn transform_module_info(&self, module_info: &mut ModuleInfo) -> Result<(), MiddlewareError> {
let mut global_indexes = self.global_indexes.lock().unwrap();
if global_indexes.is_some() {
panic!(
"Metering::transform_module_info: Attempting to use a `Metering` middleware from multiple modules."
);
}
// Append a global for remaining points and initialize it.
let remaining_points_global_index = module_info
.globals
.push(GlobalType::new(Type::I64, Mutability::Var));
module_info
.global_initializers
.push(GlobalInit::I64Const(self.initial_limit as i64));
module_info.exports.insert(
"wasmer_metering_remaining_points".to_string(),
ExportIndex::Global(remaining_points_global_index),
);
View on GitHub (pinned to 8c4b9ee9d3)
Solutions
- Create a fresh Metering instance for every module you compile (inside the per-module loop).
- If you share middleware, wrap Metering construction in a closure/factory instead of sharing the instance.
- Check whether the shared object is an Arc<Metering> and clone semantics silently reuse the same global state; replace with per-use construction.
Example fix
// before
let metering = Arc::new(Metering::new(cost_fn, 10_000));
for wasm in modules {
Module::new_with_middleware(&engine, &wasm, vec![metering.clone()])?;
}
// after
for wasm in modules {
let metering = Arc::new(Metering::new(cost_fn, 10_000)); // fresh per module
Module::new_with_middleware(&engine, &wasm, vec![metering])?;
} Defensive patterns
Strategy: validation
Validate before calling
// Never reuse a Metering across modules; enforce with a factory
fn metering_chain() -> Vec<Arc<dyn Middleware>> {
vec![Arc::new(Metering::new(cost_fn, 10_000))] // fresh per call
} Type guard
fn assert_fresh_metering(m: &Metering) { /* construct per module; Metering carries per-module global state, so there is no safe shared-handle check — always build new */ } Prevention
- Construct a new Metering::new(...) inside every module-compilation loop iteration.
- Never clone/Share an Arc<Metering> across Module::new calls.
- Store a middleware factory (closure) rather than middleware instances in shared app state.
- Write a test that compiles two modules with your middleware chain to catch accidental reuse.
When it happens
Trigger: Constructing one `Metering::new(cost_function, initial_points)` and adding it to the middleware chain of more than one module compilation (e.g. looping over several modules each with `.push_metering(metering.clone())` or reusing a shared Arc<Metering> across Module::new calls).
Common situations: Batch-compiling multiple Wasm modules with a single shared middleware; caching a middleware chain in app state and reusing it per request; misunderstanding that Metering holds mutable per-module state rather than being stateless.
Related errors
- not a `sys` backend!
- Unsupported backend kind {v:?}
- unimplemented operator {operator:?}
- wasmer_env_set_memory() is not supported
- Unable to determine the wasmer dir: {e}
AI-assisted analysis of wasmerio/wasmer@8c4b9ee9d3 (2026-09-01).
Data as JSON: /api/errors/95270c587af69354.
Report an issue: GitHub.