wasmerio/wasmer · error · anyhow::Error

env.memory import for Wasm C API module is not a memory

Error message

env.memory import for Wasm C API module is not a memory

What it means

When the Wasm C API module requires an imported memory `env.memory`, register_imports checks whether the module instance already exports something under ("env","memory"). If that export exists but is not an Extern::Memory, the type contract is violated and it bails instead of coercing. The C API state needs a real Memory handle to operate.

Source

Thrown at lib/c-api-imports/src/lib.rs:155

        self.validate_supported()?;
        if self.version.is_none() {
            return Ok(());
        }

        let func_env = FunctionEnv::new(
            &mut *store,
            WasmCapiEnv {
                resolve_module_sync: self.resolve_module_sync.clone(),
                ..WasmCapiEnv::default()
            },
        );
        self.func_env = Some(func_env.clone());
        register_wasm_c_api_imports(store, &func_env, io);

        if let Some(memory_type) = self.imported_memory_type {
            if let Some(existing) = io.get_export("env", "memory") {
                let Extern::Memory(memory) = existing else {
                    bail!("env.memory import for Wasm C API module is not a memory");
                };
                self.set_memory(store, &memory)?;
            } else {
                let memory = Memory::new(&mut *store, memory_type)?;
                io.define("env", "memory", memory.clone());
                self.set_memory(store, &memory)?;
            }
        }

        if let Some(table_type) = self.imported_table_type {
            if let Some(existing) = io.get_export("env", "__indirect_function_table") {
                let Extern::Table(table) = existing else {
                    bail!(
                        "env.__indirect_function_table import for Wasm C API module is not a table"
                    );
                };
                self.set_table(store, &table)?;
            } else {

View on GitHub (pinned to 8c4b9ee9d3)

Solutions

  1. Ensure the "env" "memory" export in the Imports object is an actual Memory instance
  2. Rename/remove the conflicting non-memory export registered under ("env","memory")
  3. Let Wasmer create the memory by not pre-defining env.memory (it will allocate Memory::new with the module's declared type)

Example fix

// before
io.define("env", "memory", host_func.clone()); // function, not memory
// after
let mem = Memory::new(&mut store, memory_type)?;
io.define("env", "memory", mem);
Defensive patterns

Strategy: validation

Validate before calling

if let Some(Extern::Memory(_)) = io.get_export("env", "memory") { /* ok */ } else if io.get_export("env", "memory").is_some() {
    return Err("env.memory is defined but not a Memory");
}

Type guard

fn is_memory_export(e: Option<&Extern>) -> bool {
    matches!(e, Some(Extern::Memory(_)))
}

Try / catch

match result {
    Err(e) if e.to_string().contains("is not a memory") => fix_env_memory_import_and_retry(),
    other => other?,
}

Prevention

When it happens

Trigger: Instantiating a module with an `env.memory` import while the imports object already defines "env.memory" as a function/table/global (anything but a Memory), then calling add_imports.

Common situations: Name collision: a host function registered as env.memory; a stale/wrong import defined earlier in the same Imports set; mixing two modules' import sets where one's memory name matches the other's export of a different kind.

Related errors


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