clockworklabs/SpacetimeDB · critical

{CALL_HTTP_HANDLER_DUNDER} export is not a function

Error message

{CALL_HTTP_HANDLER_DUNDER} export is not a function

What it means

get_call_http_handler resolves the `__call_http_handler__` export, the entry point invoked when an HTTP request routes to a module handler. If the name is exported as a memory, global, or table, `into_func()` yields None and the host panics. HTTP handler entry is optional (absent name yields None), so the panic only fires when the name is occupied by a non-function.

Source

Thrown at crates/core/src/host/wasmtime/wasmtime_module.rs:497

    let export = instance.get_export(store.as_context_mut(), CALL_VIEW_ANON_DUNDER)?;
    Some(
        export
            .into_func()
            .unwrap_or_else(|| panic!("{CALL_VIEW_ANON_DUNDER} export is not a function"))
            .typed(store)
            .unwrap_or_else(|err| panic!("{CALL_VIEW_ANON_DUNDER} export is a function with incorrect type: {err}")),
    )
}

/// Look up the `instance`'s export named by [`CALL_HTTP_HANDLER_DUNDER`].
///
/// Similar to [`get_call_procedure`], but for HTTP handlers.
fn get_call_http_handler(store: &mut Store<WasmInstanceEnv>, instance: &Instance) -> Option<CallHttpHandlerType> {
    let export = instance.get_export(store.as_context_mut(), CALL_HTTP_HANDLER_DUNDER)?;
    Some(
        export
            .into_func()
            .unwrap_or_else(|| panic!("{CALL_HTTP_HANDLER_DUNDER} export is not a function"))
            .typed(store)
            .unwrap_or_else(|err| panic!("{CALL_HTTP_HANDLER_DUNDER} export is a function with incorrect type: {err}")),
    )
}

// `__call_procedure__` takes the same arguments as `__call_reducer__`.
type CallProcedureType = CallReducerType;

/// The function signature of `__call_reducer__`
type CallReducerType = TypedFunc<
    (
        // ReducerId
        u32,
        // sender_0
        u64,
        // sender_1
        u64,
        // sender_2

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Inspect the export kind with `wasm-objdump -x module.wasm | grep -A2 __call_http_handler__`.
  2. Remove or rename the conflicting export and rebuild with the official SDK.
  3. Confirm the SDK's http-handler feature matches the server's supported module ABI version.
Defensive patterns

Strategy: type-guard

Validate before calling

use wasmtime::{Engine, Module, ExternType};

fn http_handler_export_is_func(engine: &Engine, wasm: &[u8]) -> Result<(), String> {
    let module = Module::new(engine, wasm).map_err(|e| e.to_string())?;
    if let Some(exp) = module.get_export("__call_http_handler__") {
        if !matches!(exp.ty(), ExternType::Func(_)) {
            return Err(format!("__call_http_handler__ exported as {:?}, not a function", exp.ty()));
        }
    }
    Ok(())
}

Type guard

fn is_func_export(ty: &ExternType) -> bool { matches!(ty, ExternType::Func(_)) }

Prevention

When it happens

Trigger: Instantiating a module that exports `__call_http_handler__` as a non-function item; reached in get_call_http_handler during publish or host startup of a module declaring HTTP handlers.

Common situations: Export-name collisions in hand-written code; modules generated by tools that emit globals for handler metadata under the reserved name; partial codegen when the http feature flag is mismatched between SDK and server.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20). Data as JSON: /api/errors/6d9fa841154c94fc. Report an issue: GitHub.