clockworklabs/SpacetimeDB · error

ChangeIndexSourceName: `{index_name}` not found in new modul

Error message

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

What it means

Applying AutoMigrateStep::ChangeIndexSourceName: plan.new.find_storing_table(namespace, index_name) returns None - no table in the NEW module def stores the index, even though the plan claims the index survives with a changed source name. The step's index key does not resolve in the new defs, a plan/def inconsistency. The publish aborts.

Source

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

                log!(
                    logger,
                    "Changing column accessor name for `{}`.`{}` to `{}`",
                    table_name,
                    col_name,
                    new_col_def.accessor_name,
                );
                stdb.alter_column_accessor_name(tx, table_id, col_schema.col_pos, new_col_def.accessor_name.clone())?;
            }
            spacetimedb_schema::auto_migrate::AutoMigrateStep::ChangeIndexSourceName(key) => {
                let (namespace, index_name) = key;
                let (_old_owning_def, old_table_def) =
                    plan.old.find_storing_table(namespace, index_name).ok_or_else(|| {
                        anyhow::anyhow!("ChangeIndexSourceName: `{index_name}` not found in old module def")
                    })?;
                let (_new_owning_def, new_table_def) =
                    plan.new.find_storing_table(namespace, index_name).ok_or_else(|| {
                        anyhow::anyhow!("ChangeIndexSourceName: `{index_name}` not found in new module def")
                    })?;
                let table_full_name = joined(namespace, &old_table_def.name);
                let stored_name = namespace.join_raw(&index_name.clone().into());
                let new_index_def = new_table_def
                    .indexes
                    .get(index_name)
                    .ok_or_else(|| anyhow::anyhow!("Index `{index_name}` not found in table `{table_full_name}`"))?;

                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}`"))?;
                let new_source_name = namespace.join_raw(&new_index_def.source_name.clone().into());

                log!(

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Clean-rebuild and republish to eliminate def/plan desync.
  2. Split the migration: change the index source in one publish, rename/drop the index in another.
  3. Pin the index name with #[index(name = "...")] on both old and new versions.
  4. Align SDK/CLI/server versions with the database's provenance.
  5. Dev: spacetime publish --delete-data <db>.
  6. Report persistent cases as an auto_migrate planner bug.

Example fix

// before: rename the indexed column and the index in one publish
#[spacetimedb::index(name = "by_level", btree)] // was `by_hp` on field `hp` -> `level`

// after: two publishes
// 1) #[spacetimedb::column(name = "hp")] + #[spacetimedb::index(name = "by_hp", btree)] pub level: u32;
// 2) rename the index alone
Defensive patterns

Strategy: validation

Validate before calling

use spacetimedb_schema::auto_migrate::AutoMigrateStep;
for step in &plan.steps {
    if let AutoMigrateStep::ChangeIndexSourceName((namespace, index_name)) = step {
        if plan.new.find_storing_table(namespace, index_name).is_none() {
            anyhow::bail!("new def lacks index {} - plan/def desync", index_name);
        }
    }
}

Type guard

fn index_in_new_def<'a>(plan: &'a AutoMigratePlan, ns: &str, idx: &str) -> bool {
    plan.new.find_storing_table(ns, idx).is_some()
}

Try / catch

match update_database(&stdb, tx, &plan, ...).await {
    Err(e) if e.to_string().contains("ChangeIndexSourceName")
        && e.to_string().contains("new module def") => {
        // Split publishes: source rename first, index rename/drop in a later publish.
    }
    result => result?,
}

Prevention

When it happens

Trigger: Renaming or dropping the index (or its table) in the same publish as the source rename, so the new def no longer contains the index under that key; index-name normalization or accessor-derived naming differences between the def the planner diffed and the def being applied.

Common situations: Bundling index renames with column renames in one publish; unpinned #[index(btree)] attribute names that shift when the annotated field is renamed; toolchain version changes between publishes.

Related errors


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