clockworklabs/SpacetimeDB · error · anyhow::Error
module definition is unavailable while committing a procedur
Error message
module definition is unavailable while committing a procedure transaction
What it means
During WasmInstanceEnv::refresh_views, which runs while committing a procedure (reducer) transaction, caller.data().module_def was None. The instance env must hold the module definition to resolve views for refresh; its absence means instance state was cleared (e.g. during module update or teardown) while a procedure transaction was still committing. The transaction is rolled back and the error returned.
Source
Thrown at crates/core/src/host/wasmtime/wasm_instance_env.rs:1759
.commit_procedure_tx(tx)
.map_err(WasmError::from)?;
Ok(0u16.into())
})();
res.or_else(|err| Self::convert_wasm_result(AbiCall::ProcedureCommitMutTransaction, err))
})
}
/// Refresh all views made stale by a procedure `tx`.
///
/// This runs each pending view call in the same mutable transaction and writes the refreshed rows
/// into the corresponding backing view tables. If any step fails (missing metadata, view execution,
/// row decoding, SQL execution, or materialization), this method rolls back `tx` and returns an error.
///
/// On success, it returns the same transaction handle so the caller can commit it.
fn refresh_views<'a>(caller: &mut Caller<'a, Self>, tx: MutTxId) -> Result<MutTxId, WasmError> {
let Some(module_def) = caller.data().module_def.clone() else {
caller.data_mut().instance_env.rollback_procedure_tx(tx);
return Err(WasmError::Wasm(anyhow!(
"module definition is unavailable while committing a procedure transaction"
)));
};
let views_for_refresh = tx.views_for_refresh().cloned().collect::<Vec<_>>();
let mut tx = Some(tx);
let mut tx_slot = caller.data().instance_env.tx.clone();
for view_call in views_for_refresh {
let res: anyhow::Result<()> = (|| {
let resolved = crate::host::module_host::resolve_view_for_refresh(
tx.as_ref().expect("procedure tx missing during view refresh"),
&module_def,
&view_call,
)?;
let table_id = resolved.table_id;
let view_def = resolved.view_def;View on GitHub (pinned to 6dee26c6ef)
Solutions
- Retry the reducer call once the module update completes - the transaction was rolled back safely, so no partial state was written
- Drain or quiesce reducer traffic before publishing module updates
- If it recurs outside update windows, capture server logs and report it - module_def should never be missing mid-commit
Defensive patterns
Strategy: retry
Try / catch
match commit_result {
Err(e) if e.to_string().contains("module definition is unavailable") => {
// Tx was rolled back safely: wait for the module update to settle, then retry the reducer once
}
other => other,
} Prevention
- Drain or pause reducer traffic while publishing module updates
- Make reducers idempotent so a post-update retry is safe
- Alert on this error outside maintenance windows - it signals a lifecycle race
When it happens
Trigger: A module update or instance teardown racing with an in-flight reducer commit on the wasmtime instance: the module def is swapped out before commit_procedure_tx finishes.
Common situations: Publishing a new module version while reducers are executing under load; node restarts during hot-swap; lifecycle bugs in the host.
Related errors
- {CALL_PROCEDURE_DUNDER} export is not a function
- {CALL_PROCEDURE_DUNDER} export is a function with incorrect
- {CALL_VIEW_DUNDER} export is not a function
- {CALL_VIEW_DUNDER} export is a function with incorrect type:
- {CALL_VIEW_ANON_DUNDER} export is not a function
AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20).
Data as JSON: /api/errors/88fa797debb9bdc9.
Report an issue: GitHub.