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
                    .new

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Refresh the old module def from the database's actual state and regenerate the plan
  2. If the view is genuinely gone, remove the stale RemoveView step (or republish the module cleanly)
  3. 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

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


AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20). Data as JSON: /api/errors/56e311e1af160481. Report an issue: GitHub.