{"record":{"id":"84f413631df8b736","repo":"clockworklabs/SpacetimeDB","slug":"call-procedure-dunder-export-is-a-function-with","errorCode":null,"errorMessage":"{CALL_PROCEDURE_DUNDER} export is a function with incorrect type: {err}","messagePattern":"(.+?) export is a function with incorrect type: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/core/src/host/wasmtime/wasmtime_module.rs","lineNumber":457,"sourceCode":"/// Panics if the `instance` has an export at the expected name,\n/// but it is not a function or is a function of an inappropriate type.\n/// For new modules, this will be caught during publish.\n/// Old modules from before the introduction of procedures might have an export at that name,\n/// but it follows the double-underscore pattern of reserved names,\n/// so we're fine to break those modules.\nfn get_call_procedure(store: &mut Store<WasmInstanceEnv>, instance: &Instance) -> Option<CallProcedureType> {\n    // Wasmtime uses `anyhow` for error reporting, vexing library users the world over.\n    // This means we can't distinguish between the failure modes of `Instance::get_typed_func`.\n    // Instead, we type out the body of that method ourselves,\n    // but with error handling appropriate to our needs.\n    let export = instance.get_export(store.as_context_mut(), CALL_PROCEDURE_DUNDER)?;\n\n    Some(\n        export\n            .into_func()\n            .unwrap_or_else(|| panic!(\"{CALL_PROCEDURE_DUNDER} export is not a function\"))\n            .typed(store)\n            .unwrap_or_else(|err| panic!(\"{CALL_PROCEDURE_DUNDER} export is a function with incorrect type: {err}\")),\n    )\n}\n\n/// Look up the `instance`'s export named by [`CALL_VIEW_DUNDER`].\n///\n/// Similar to [`get_call_procedure`], but for views.\nfn get_call_view(store: &mut Store<WasmInstanceEnv>, instance: &Instance) -> Option<CallViewType> {\n    let export = instance.get_export(store.as_context_mut(), CALL_VIEW_DUNDER)?;\n    Some(\n        export\n            .into_func()\n            .unwrap_or_else(|| panic!(\"{CALL_VIEW_DUNDER} export is not a function\"))\n            .typed(store)\n            .unwrap_or_else(|err| panic!(\"{CALL_VIEW_DUNDER} export is a function with incorrect type: {err}\")),\n    )\n}\n\n/// Look up the `instance`'s export named by [`CALL_VIEW_ANON_DUNDER`].","sourceCodeStart":439,"sourceCodeEnd":475,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/core/src/host/wasmtime/wasmtime_module.rs#L439-L475","documentation":"SpacetimeDB's wasmtime host resolves the `__call_procedure__` export on every instantiated module and converts it to a TypedFunc via `Func::typed`. The comment in get_call_procedure explains that wasmtime reports typing failures as opaque anyhow errors, so the host hand-rolls the lookup and panics when typing fails. This panic means the export exists and is a function, but its wasm signature does not match `CallProcedureType` (aliased to `CallReducerType`: a u32 ReducerId followed by the sender and argument parameters). It is almost always a module/host ABI mismatch, not a fault in your reducer logic.","triggerScenarios":"Instantiating or publishing a wasm module whose `__call_procedure__` export has a different signature than the TypedFunc<(u32 /* ReducerId */, sender, args, ...)> expected by this server build; reached on publish, database start/restart, or any call that instantiates the module host.","commonSituations":"Module artifact built with an SDK older or newer than the running spacetimedb server (bindgen emits a different entry signature); publishing a stale wasm under target/ after upgrading the CLI or SDK; hand-written WAT/wasm exporting the dunder name with wrong parameters.","solutions":["Rebuild the module with the spacetimedb SDK/CLI version that matches the server, clearing stale artifacts under target/ first, then republish.","Inspect the export: `wasm-objdump -x module.wasm` (or `wasm2wat module.wasm`) and compare `__call_procedure__` param/result types against the signature your server version expects.","Verify CLI, SDK, and server version alignment (`spacetime --version`, server version endpoint) and read release notes for ABI-breaking changes.","If hand-authoring wasm, copy the exact export signature emitted by the official SDK for your server version."],"exampleFix":"// before: publish a module compiled against an older SDK\nspacetime publish my-db\n\n// after: align SDK + CLI with the server, rebuild clean, republish\ncargo update -p spacetimedb --precise <version-matching-server>\nrm -rf target/wasm32-*\nspacetime build && spacetime publish my-db -y","handlingStrategy":"type-guard","validationCode":"use wasmtime::{Engine, Module, ExternType};\n\n/// Reject modules whose dunder entry exports exist but are not functions.\nfn check_export_kinds(engine: &Engine, wasm: &[u8]) -> Result<(), String> {\n    let module = Module::new(engine, wasm).map_err(|e| e.to_string())?;\n    for name in [\"__call_procedure__\", \"__call_view__\", \"__call_view_anon__\", \"__call_http_handler__\"] {\n        if let Some(exp) = module.get_export(name) {\n            if !matches!(exp.ty(), ExternType::Func(_)) {\n                return Err(format!(\"{name} exported as non-function\"));\n            }\n            // additionally compare exp.ty() params/results against the server's expected TypedFunc signature\n        }\n    }\n    Ok(())\n}","typeGuard":"fn is_func_export(ty: &ExternType) -> bool { matches!(ty, ExternType::Func(_)) }","tryCatchPattern":"// last resort at the embedding boundary\nlet inst = std::panic::catch_unwind(|| instantiate_module(module));\nif let Err(p) = inst {\n    if panic_message(&p).contains(\"__call_procedure__\") {\n        // ABI mismatch: rebuild the module with a matching SDK; do not retry as-is\n    }\n}","preventionTips":["Pin the module SDK and spacetimedb server to a verified-compatible pair in CI.","Smoke-test `spacetime publish` against a staging server after every toolchain upgrade.","Never hand-write the `__call_*__` dunder exports; generate them with spacetimedb-bindgen.","Verify exported signatures with wasm-objdump before deploying hand-modified wasm."],"tags":["wasm","wasmtime","abi-mismatch","spacetimedb","module-publish"],"backgroundTag":"wasm-abi-mismatch","analyzedSha":"6dee26c6efc2856793e12b148a59742964f5d783","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}