clockworklabs/SpacetimeDB · error
RemoveView: view `{view_name}` not found in database
Error message
RemoveView: view `{view_name}` not found in database What it means
Auto-migrate step RemoveView: view_id_from_name_mut found no view with the plan's name in the database. The plan (built from the old def) believes the view exists, but the live database does not have it — the database schema and the old module def have drifted.
Source
Thrown at crates/engine/src/update.rs:307
.ok_or_else(|| anyhow::anyhow!("AddTable: table `{table_name}` not found in new module def"))?;
log!(logger, "Creating table `{table_name}`");
create_table_from_def_with_prefix(stdb, tx, owning_def, table_def, namespace)?;
}
spacetimedb_schema::auto_migrate::AutoMigrateStep::AddView(view_name_key) => {
let (namespace, local) = view_name_key;
let view_name = joined(namespace, local);
let (owning_def, view_def) = plan
.new
.find_view(view_name_key)
.ok_or_else(|| anyhow::anyhow!("AddView: view `{view_name}` not found in new module def"))?;
create_table_from_view_def_with_prefix(stdb, tx, owning_def, view_def, namespace)?;
}
spacetimedb_schema::auto_migrate::AutoMigrateStep::RemoveView(view_name_key) => {
let (namespace, local) = view_name_key;
let view_name = joined(namespace, local);
let view_id = stdb
.view_id_from_name_mut(tx, &view_name)?
.ok_or_else(|| anyhow::anyhow!("RemoveView: view `{view_name}` not found in database"))?;
stdb.drop_view(tx, view_id)?;
}
spacetimedb_schema::auto_migrate::AutoMigrateStep::UpdateView(_) => {
// if we already have to disconnect clients, no need to set
// `EvaluateSubscribedViews` as clients will be disconnected anyway
if !matches!(res, UpdateResult::RequiresClientDisconnect) {
res = UpdateResult::EvaluateSubscribedViews;
}
}
spacetimedb_schema::auto_migrate::AutoMigrateStep::AddIndex(key) => {
let (namespace, index_name) = key;
let (owning_def, table_def) = plan
.new
.find_storing_table(namespace, index_name)
.ok_or_else(|| anyhow::anyhow!("AddIndex: `{index_name}` not found in new module def"))?;
let table_full_name = joined(namespace, &table_def.name);
let index_def: &IndexDef = plan
.newView on GitHub (pinned to 6dee26c6ef)
Solutions
- Refresh the old module def from the database's actual state and regenerate the plan
- If the view is genuinely gone, remove the stale RemoveView step (or republish the module cleanly)
- For disposable databases, publish to a fresh database instead of reconciling drift
Example fix
// before: apply a plan whose RemoveView targets a nonexistent view
update_database(&stdb, &mut tx, auth, plan, &logger)?;
// after: pre-check the view exists before planning its removal
if stdb.view_id_from_name_mut(&mut tx, &view_name)?.is_none() {
log::warn!("view {view_name} already absent; skipping");
} Defensive patterns
Strategy: validation
Validate before calling
// Before planning a view removal, confirm it exists in the DB
match stdb.view_id_from_name_mut(&mut tx, &view_name)? {
Some(_) => { /* plan RemoveView */ }
None => log::warn!("view {view_name} already absent; skipping removal"),
} Type guard
fn view_exists(stdb: &RelationalDB, tx: &mut MutTx, name: &str) -> bool {
stdb.view_id_from_name_mut(tx, name).ok().flatten().is_some()
} Try / catch
match auto_migrate_database(&stdb, &mut tx, auth, &plan, &logger) {
Err(e) if e.to_string().contains("RemoveView:") && e.to_string().contains("not found in database") => {
// schema drift: refresh the old def from the DB and regenerate the plan
anyhow::bail!("drift detected: {e:#}; rebuild the plan from the database's actual schema");
}
r => r,
} Prevention
- Avoid dropping views manually when modules manage them
- After a failed migration, refresh defs before retrying
- Publish fresh databases in tests rather than reusing drifted fixtures
When it happens
Trigger: The view was already dropped in the database (earlier failed migration, manual DDL) while the old def still lists it; view name/prefix mismatch between the plan key and the stored name; stale migration plan computed against an outdated def.
Common situations: Retrying a migration after a partially applied earlier one; mixing manual SQL view drops with module publishes; namespace-prefix differences for submodule views.
Related errors
- AddView: view `{view_name}` not found in new module def
- Index `{index_name}` not found in table `{table_full_name}`
- table {} not found in old_module_def
- Precheck: sequence `{sequence_name}` not found in new module
- Precheck failed: added sequence {sequence_name} refers to un
AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20).
Data as JSON: /api/errors/56e311e1af160481.
Report an issue: GitHub.