clockworklabs/SpacetimeDB · error

AddIndex: `{index_name}` not found in new module def

Error message

AddIndex: `{index_name}` not found in new module def

What it means

Auto-migrate step AddIndex: find_storing_table(namespace, index_name) failed — no table in the new module def stores the index named in the step. The plan references an index whose owning table is absent from plan.new; an internal plan/def inconsistency.

Source

Thrown at crates/engine/src/update.rs:322

                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
                    .lookup(key)
                    .ok_or_else(|| anyhow::anyhow!("AddIndex: index `{index_name}` not found in new module def"))?;
                let table_id = stdb.table_id_from_name_mut(tx, &table_full_name)?.unwrap();

                let index_cols = ColSet::from(index_def.algorithm.columns());

                let is_unique = table_def
                    .constraints
                    .iter()
                    .filter_map(|(_, c)| c.data.unique_columns())
                    .any(|unique_cols| unique_cols == &index_cols);

                log!(logger, "Creating index `{index_name}` on table `{table_full_name}`");

                let mut index_schema = IndexSchema::from_module_def(owning_def, index_def, table_id, 0.into());

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Regenerate the plan from the same def that provides plan.new
  2. Check the (namespace, index name) key resolves to a storing table in the new def
  3. Report upstream if the differ produced the dangling step
Defensive patterns

Strategy: try-catch

Try / catch

match auto_migrate_database(&stdb, &mut tx, auth, &plan, &logger) {
    Err(e) if e.to_string().contains("AddIndex:") && e.to_string().contains("not found in new module def") => {
        anyhow::bail!("plan/def desync: {e:#}; regenerate the plan from one consistent def");
    }
    r => r,
}

Prevention

When it happens

Trigger: AddIndex step generated from a different def revision than plan.new; index-to-table association changed between diff and apply; hand-built plans with dangling index keys.

Common situations: Cached plans reused after def edits; upstream differ bugs; submodule index namespace mismatches.

Related errors


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