wasmerio/wasmer · error

Table.copy is not natively supported in Javascript

Error message

Table.copy is not natively supported in Javascript

What it means

`Table::copy` on the JS backend is a stub: the WebAssembly `table.copy` instruction is not exposed through the JS API surface used by wasmer, so calling copy panics instead of copying elements.

Source

Thrown at lib/api/src/backend/js/entities/table.rs:146

        delta: u32,
        init: Value,
    ) -> Result<u32, RuntimeError> {
        let initial_value = get_table_item(store, init)?;
        self.handle
            .table
            .grow_with_value(delta, initial_value)
            .map_err(Into::into)
    }

    pub fn copy(
        _store: &mut impl AsStoreMut,
        _dst_table: &Self,
        _dst_index: u32,
        _src_table: &Self,
        _src_index: u32,
        _len: u32,
    ) -> Result<(), RuntimeError> {
        unimplemented!("Table.copy is not natively supported in Javascript");
    }

    pub(crate) fn from_vm_extern(_store: &mut impl AsStoreMut, vm_extern: VMExternTable) -> Self {
        Self {
            handle: vm_extern.unwrap_js(),
        }
    }

    pub fn is_from_store(&self, _store: &impl AsStoreRef) -> bool {
        true
    }
}

impl crate::Table {
    /// Consume [`self`] into [`crate::backend::js::table::Table`].
    pub fn into_js(self) -> crate::backend::js::table::Table {
        match self.0 {
            BackendTable::Js(s) => s,

View on GitHub (pinned to 8c4b9ee9d3)

Solutions

  1. Implement the copy manually: loop over `get`/`set` for the index range (only viable for externref tables on the js backend)
  2. Recompile the guest to avoid `table.copy`, or run that module on a native backend
  3. Skip the call behind a backend/runtime capability check

Example fix

// before
table.copy(&mut store, &dst, dst_i, &src, src_i, len)?;
// after
for k in 0..len {
    let v = src.get(&mut store, src_i + k)?;
    dst.set(&mut store, dst_i + k, v)?;
}
Defensive patterns

Strategy: validation

Validate before calling

// Avoid calling Table::copy on js backend; detect at compile time
#[cfg(target_arch = "wasm32")]
fn table_copy(...) -> Result<(), RuntimeError> { /* element-wise loop */ }

Type guard

fn table_copy_supported() -> bool {
    cfg!(not(target_arch = "wasm32"))
}

Try / catch

if table_copy_supported() {
    table.copy(&mut store, &dst, di, &src, si, len)?;
} else {
    for k in 0..len { /* get/set loop */ }
}

Prevention

When it happens

Trigger: Calling `Table::copy(&mut store, dst_table, dst_index, src_table, src_index, len)` in code compiled with the `js` backend.

Common situations: Host code that compacts/rearranges table entries, or module trap recovery that copies table regions; runs fine natively, panics in the browser build.

Related errors


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