{"record":{"id":"88d4ca8c20bf1ec6","repo":"clockworklabs/SpacetimeDB","slug":"call-view-dunder-export-is-not-a-function","errorCode":null,"errorMessage":"{CALL_VIEW_DUNDER} export is not a function","messagePattern":"(.+?) export is not a function","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/core/src/host/wasmtime/wasmtime_module.rs","lineNumber":469,"sourceCode":"\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`].\n///\n/// Similar to [`get_call_procedure`], but for anonymous views.\nfn get_call_view_anon(store: &mut Store<WasmInstanceEnv>, instance: &Instance) -> Option<CallViewAnonType> {\n    let export = instance.get_export(store.as_context_mut(), CALL_VIEW_ANON_DUNDER)?;\n    Some(\n        export\n            .into_func()\n            .unwrap_or_else(|| panic!(\"{CALL_VIEW_ANON_DUNDER} export is not a function\"))\n            .typed(store)\n            .unwrap_or_else(|err| panic!(\"{CALL_VIEW_ANON_DUNDER} export is a function with incorrect type: {err}\")),\n    )\n}","sourceCodeStart":451,"sourceCodeEnd":487,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/core/src/host/wasmtime/wasmtime_module.rs#L451-L487","documentation":"When hooking up a module instance, get_call_view resolves the `__call_view__` export (the generated entry point for SQL views over the module). `Export::into_func()` returns None when the export is a memory, global, or table instead of a function, and the host panics immediately. A non-function export carrying that reserved name is treated as a malformed module. The export itself is optional (get_export returning None yields None from the function), so the panic only fires when something occupies the name with the wrong kind.","triggerScenarios":"Instantiating a module that exports `__call_view__` as a global, memory, or table rather than a wasm function; hit inside get_call_view's `into_func().unwrap_or_else(panic!)` during publish or database start.","commonSituations":"Name collision: a static, memory, or custom export accidentally named `__call_view__` (e.g. via #[export_name]); hand-written WAT exporting a global with the reserved name; codegen changes between SDK versions exporting the wrong kind.","solutions":["Find the offending export: `wasm-objdump -x module.wasm | grep -A2 __call_view__` shows whether it is a global/memory/table.","Rename or remove the conflicting export in module source (check any #[export_name] attributes) and rebuild.","Rebuild with the SDK matching the server so codegen emits the function export correctly.","Reserve the `__call_*__` dunder names for generated code only."],"exampleFix":"// before: accidental export-kind collision with the reserved name\n#[export_name = \"__call_view__\"]\nstatic VIEW_FLAG: AtomicBool = AtomicBool::new(false);\n\n// after: do not shadow the reserved dunder export name\nstatic VIEW_FLAG: AtomicBool = AtomicBool::new(false);","handlingStrategy":"type-guard","validationCode":"use wasmtime::{Engine, Module, ExternType};\n\nfn no_dunder_name_collisions(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            match exp.ty() {\n                ExternType::Func(_) => {}\n                other => return Err(format!(\"{name} exported as {other:?}, expected a function\")),\n            }\n        }\n    }\n    Ok(())\n}","typeGuard":"fn is_func_export(ty: &ExternType) -> bool { matches!(ty, ExternType::Func(_)) }","tryCatchPattern":"let r = std::panic::catch_unwind(|| host.instantiate(module));\nif let Err(p) = r {\n    if panic_message(&p).contains(\"__call_view__ export is not a function\") {\n        // a non-function item holds the reserved name: fix module exports and rebuild\n    }\n}","preventionTips":["Treat the `__call_*__` names as reserved in lint rules for module code.","Audit #[export_name] attributes before publishing.","Run an export-kind check in CI on built wasm artifacts."],"tags":["wasm","wasmtime","export-kind","spacetimedb","name-collision"],"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-08T10:18:20.063Z"}