wasmerio/wasmer · error · anyhow::Error
env.__indirect_function_table import for Wasm C API module i
Error message
env.__indirect_function_table import for Wasm C API module is not a table
What it means
Analogous to the memory case: if the module needs the imported table `env.__indirect_function_table` and the imports already contain an export of that name which is not an Extern::Table, register_imports bails. The C API layer stores the Table handle in its state and cannot substitute another extern type.
Source
Thrown at lib/c-api-imports/src/lib.rs:168
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 {
let table = Table::new(&mut *store, table_type, Value::FuncRef(None))?;
io.define("env", "__indirect_function_table", table.clone());
self.set_table(store, &table)?;
}
}
Ok(())
}
fn set_memory(&self, store: &mut StoreMut<'_>, memory: &Memory) -> Result<()> {
let Some(func_env) = self.func_env()? else {
return Ok(());
};View on GitHub (pinned to 8c4b9ee9d3)
Solutions
- Define "env" "__indirect_function_table" as an actual Table (initialized with Value::FuncRef(None))
- Remove or rename the conflicting non-table export
- Omit the pre-defined import so Wasmer creates the table from the module's declared table type
Example fix
// before
io.define("env", "__indirect_function_table", my_memory.clone());
// after
let table = Table::new(&mut store, table_type, Value::FuncRef(None))?;
io.define("env", "__indirect_function_table", table); Defensive patterns
Strategy: validation
Validate before calling
if let Some(e) = io.get_export("env", "__indirect_function_table") {
if !matches!(e, Extern::Table(_)) {
return Err("__indirect_function_table is defined but not a Table");
}
} Type guard
fn is_table_export(e: Option<&Extern>) -> bool {
matches!(e, Some(Extern::Table(_)))
} Try / catch
match result {
Err(e) if e.to_string().contains("is not a table") => fix_env_table_import_and_retry(),
other => other?,
} Prevention
- Define env.__indirect_function_table only with Table instances
- Do not repurpose the C API standard table name for other exports
- Let Wasmer create the table when your module declares one instead of pre-defining it
When it happens
Trigger: Instantiating a Wasm C API module requiring __indirect_function_table while the Imports set defines "env" "__indirect_function_table" as a memory/function/global, via add_imports.
Common situations: Custom table assigned under the standard C API table name but with the wrong extern type; collision with an existing host export of the same name; copy-pasted import wiring between modules.
Related errors
- env.memory import for Wasm C API module is not a memory
- unsupported Wasm C API import version: {version:?}
- unimplemented operator {operator:?}
- Table.copy is not natively supported in Javascript
- Copying tables is currently not implemented!
AI-assisted analysis of wasmerio/wasmer@8c4b9ee9d3 (2026-09-01).
Data as JSON: /api/errors/2360b69083e9aea9.
Report an issue: GitHub.