{"record":{"id":"818e09803c977ce9","repo":"clockworklabs/SpacetimeDB","slug":"cannot-determine-module-type-from-file-extension","errorCode":null,"errorMessage":"Cannot determine module type from file extension","messagePattern":"Cannot determine module type from file extension","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cli/src/schema_extract.rs","lineNumber":29,"sourceCode":"};\nuse tokio::io::AsyncReadExt;\n\nfn extractor_path() -> anyhow::Result<PathBuf> {\n    std::env::var_os(\"SPACETIMEDB_SCHEMA_EXTRACTOR\")\n        .map(PathBuf::from)\n        .map(Ok)\n        .unwrap_or_else(|| crate::util::resolve_sibling_binary(\"spacetimedb-standalone\"))\n}\n\n/// Keep generate's synchronous injectable function API. Its small dedicated\n/// runtime works both inside and outside a caller's Tokio runtime; process\n/// ownership and validation are identical to publish's async path.\npub(crate) fn from_path(path: &Path) -> anyhow::Result<ModuleDef> {\n    let bytes = read_program(path)?;\n    let host_type = match path.extension().and_then(|ext| ext.to_str()) {\n        Some(\"wasm\") => \"Wasm\",\n        Some(\"js\") => \"Js\",\n        _ => anyhow::bail!(\"Cannot determine module type from file extension\"),\n    };\n    inspect_blocking(extractor_path()?, bytes, host_type.into())\n}\n\nfn inspect_blocking(extractor: PathBuf, bytes: Vec<u8>, host_type: String) -> anyhow::Result<ModuleDef> {\n    std::thread::spawn(move || {\n        tokio::runtime::Builder::new_current_thread()\n            .enable_all()\n            .build()?\n            .block_on(inspect_with(extractor, bytes, host_type, INSPECT_TIMEOUT))\n    })\n    .join()\n    .map_err(|_| anyhow::anyhow!(\"Local module inspection thread failed\"))?\n}\n\npub(crate) fn read_program(path: &std::path::Path) -> anyhow::Result<Vec<u8>> {\n    use std::io::Read;\n    let mut bytes = Vec::new();","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/eddf9f5014579a50d4b67630e28b6e15cad9c4af/crates/cli/src/schema_extract.rs#L11-L47","documentation":"schema_extract::from_path infers the module host type from the file extension: .wasm maps to Wasm and .js to Js. Any other (or missing) extension makes host-type inference impossible, so the function bails with this anyhow error instead of guessing.","triggerScenarios":"Running `spacetime schema extract` (or generate client bindings offline) on a program file whose extension is not exactly .wasm or .js — e.g. .wat, .wasm.tmp, no extension, or a copied binary without its suffix.","commonSituations":"Pointing the CLI at a build artifact with a hash/temp suffix, a symlink without extension, or a module written in a language outputting another container format.","solutions":["Rename/copy the module file so it ends in .wasm or .js.","Verify you are passing the compiled module path, not a source file (.rs, .ts) or intermediate artifact.","Check the path for typos and that the file actually exists with the expected extension."],"exampleFix":"// before\nspacetime schema extract ./target/server_component\n// after\ncp ./target/server_component ./target/server_component.wasm\nspacetime schema extract ./target/server_component.wasm","handlingStrategy":"validation","validationCode":"const ok = /\\.(wasm|js)$/.test(modulePath); if (!ok) throw new Error(`Module path must end in .wasm or .js: ${modulePath}`);","typeGuard":null,"tryCatchPattern":"// CLI: anyhow bail is surfaced; wrap invocation and print extension guidance","preventionTips":["Always point the CLI at the final .wasm/.js artifact","Avoid hash-suffixed temp filenames in build scripts","Check file extension in scripts before invoking spacetime schema extract"],"tags":["cli","file-extension","module","rust"],"backgroundTag":"invalid-argument-format","analyzedSha":"eddf9f5014579a50d4b67630e28b6e15cad9c4af","analyzedAt":"2026-09-20T12:15:59.611Z","contentChangedAt":"2026-09-20T12:15:59.611Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}