clockworklabs/SpacetimeDB · error
view {} not found in module_def
Error message
view {} not found in module_def What it means
When (re)initializing views during publish/update, the host computes each view's full namespaced canonical name (prefix joined with the local name, matching how create_view registered it) and looks it up in module_def via view_by_name_with_global_fn_ptr. A miss means the database expects a view the current module does not define under that exact name. Because the name includes the namespace prefix, moving a view between submodules changes it.
Source
Thrown at crates/core/src/host/wasm_common/module_host_actor.rs:1530
owner_identity: Identity,
) -> Result<Vec<CallViewParams>, anyhow::Error> {
let mut view_calls = Vec::new();
for (prefix, owning_def, view) in module_def.all_views_with_prefix() {
let ViewDef {
name: local_name,
is_anonymous,
product_type_ref,
..
} = view;
// Full namespaced canonical name: matches both the st_view registration
// (create_view / create_view_with_prefix) and `view_by_name_with_global_fn_ptr`.
let view_name = prefix.join(local_name.clone());
let (global_fn_ptr, _, _) = module_def
.view_by_name_with_global_fn_ptr(&view_name)
.ok_or_else(|| anyhow::anyhow!("view {} not found in module_def", view_name))?;
let st_view = tx
.view_from_name(&view_name)?
.ok_or_else(|| anyhow::anyhow!("view {} not found in database", view_name))?;
let view_id = st_view.view_id;
let table_id = st_view
.table_id
.ok_or_else(|| anyhow::anyhow!("view {} does not have a backing table in database", view_name))?;
let subs = tx.materialized_view_instances_for_view(view_id);
let view_typespace = Arc::new(owning_def.typespace().clone());
if *is_anonymous {
if subs.is_empty() {
continue;
}
view_calls.push(CallViewParams {
view_name: view_name.clone(),View on GitHub (pinned to 524b4487d9)
Solutions
- Check the deployed module's view list and make the canonical name (including namespace prefix) match on both sides.
- If the view was renamed intentionally, remove the stale registration (drop the view, or recreate the database if disposable) and republish.
- Republish the module that defines the view under the name the database expects.
- After renames, verify the view catalog is consistent before relying on materialized state.
Defensive patterns
Strategy: validation
Validate before calling
// before publish: canonical view names must exist in both module and database catalog
let module_views: HashSet<_> = module_def.view_names().collect();
let db_views: HashSet<_> = tx.view_names()?;
for name in module_views.symmetric_difference(&db_views) {
anyhow::bail!("view catalog mismatch: {name}");
} Prevention
- Avoid renaming or moving views between publishes; if unavoidable, drop old registrations in the same release.
- Remember the canonical name includes the submodule namespace prefix.
- Re-verify the view catalog after every publish that touches views.
When it happens
Trigger: Renaming or moving a view between publishes so an old st_view registration survives under the previous name; publishing a module revision that dropped a view still registered in the database; submodule reorganization changing the prefixed canonical name.
Common situations: Iterative development where views are renamed or deleted across publishes; cleanups that update module code but not the database's view catalog; multi-module layouts with changing namespaces.
Related errors
- view {} not found in database
- view {} does not have a backing table in database
- Manual database migrations are not yet implemented
- No database target matches '{}'. Available databases: {}
- Aborted.
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/6ce0291de13bca44.
Report an issue: GitHub.