clockworklabs/SpacetimeDB · error

RemoveIndex: `{index_name}` not found in old module def

Error message

RemoveIndex: `{index_name}` not found in old module def

What it means

Auto-migrate step RemoveIndex: find_storing_table over plan.old failed — the old module def has no table that stores the index the plan wants to drop. The removal step references an index whose owning table is missing from the old def, an internal plan/old-def inconsistency.

Source

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

                    .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));

                stdb.create_index(tx, index_schema, is_unique)?;
            }
            spacetimedb_schema::auto_migrate::AutoMigrateStep::RemoveIndex(key) => {
                let (namespace, index_name) = key;
                let (_owning_def, table_def) = plan
                    .old
                    .find_storing_table(namespace, index_name)
                    .ok_or_else(|| anyhow::anyhow!("RemoveIndex: `{index_name}` not found in old module def"))?;
                let table_full_name = joined(namespace, &table_def.name);
                let stored_name = namespace.join_raw(&index_name.clone().into());
                let table_id = stdb.table_id_from_name_mut(tx, &table_full_name)?.unwrap();
                let table_schema = stdb.schema_for_table_mut(tx, table_id)?;

                let index_schema = table_schema
                    .indexes
                    .iter()
                    .find(|index| index.index_name == stored_name)
                    .ok_or_else(|| anyhow::anyhow!("Index `{index_name}` not found in table `{table_full_name}`"))?;

                log!(logger, "Dropping index `{index_name}` on table `{table_full_name}`");
                stdb.drop_index(tx, index_schema.index_id)?;
            }
            spacetimedb_schema::auto_migrate::AutoMigrateStep::ChangeTableAccessorName(table_name_key) => {
                let (namespace, local) = table_name_key;
                let table_name = joined(namespace, local);
                let (_, new_table_def): (&ModuleDef, &spacetimedb_schema::def::TableDef) =

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Regenerate the plan from the old def that matches the currently published module
  2. Verify the (namespace, index name) key resolves in plan.old before applying
  3. Report upstream if the differ emitted the stale 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("RemoveIndex:") && e.to_string().contains("not found in old module def") => {
        anyhow::bail!("plan/old-def desync: {e:#}; rebuild the plan from the currently published module");
    }
    r => r,
}

Prevention

When it happens

Trigger: RemoveIndex steps computed against an older def revision where the table existed; the storing table was renamed/removed while the index step survived; hand-built plans with dangling keys.

Common situations: Cached migration plans reused across module edits; upstream differ bugs; submodule reorganization between def versions.

Related errors


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