clockworklabs/SpacetimeDB · error

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

Error message

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

What it means

Auto-migrate step AddIndex: the storing table was found, but plan.new.lookup(key) returned None for the IndexDef itself. The index key resolves to a table yet the def's index map has no entry — plan and def disagree, an internal invariant break.

Source

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

            }
            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());

                // Apply namespace prefix for submodule indexes
                index_schema.index_name = namespace.join_raw(&index_schema.index_name);
                index_schema.alias = index_schema.alias.as_ref().map(|alias| namespace.join_raw(alias));

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Rebuild plan and plan.new from a single consistent ModuleDef
  2. Never mix keys from one def with lookups into another
  3. Report upstream with the key if machine-generated
Defensive patterns

Strategy: try-catch

Try / catch

match auto_migrate_database(&stdb, &mut tx, auth, &plan, &logger) {
    Err(e) if e.to_string().contains("index") && e.to_string().contains("not found in new module def") => {
        // storing table resolved but IndexDef missing: rebuild plan from a single def, retry once
        let plan2 = MigratePlan::Auto(diff_defs(old_def, new_def)?);
        auto_migrate_database(&stdb, &mut tx, auth, &plan2, &logger)
    }
    r => r,
}

Prevention

When it happens

Trigger: A def revision where the index was removed after the step list was computed; hand-assembled plans mixing key sets and def maps; differ bug leaving the storing-table edge without the index definition.

Common situations: Manual plan construction; schema crate version skew; tests mutating defs between diff and apply.

Related errors


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