{"record":{"id":"5cf09c4339a5340e","repo":"clockworklabs/SpacetimeDB","slug":"index-index-name-not-found-in-table-table-fu","errorCode":null,"errorMessage":"Index `{index_name}` not found in table `{table_full_name}`","messagePattern":"Index `(.+?)` not found in table `(.+?)`","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/engine/src/update.rs","lineNumber":363,"sourceCode":"\n                stdb.create_index(tx, index_schema, is_unique)?;\n            }\n            spacetimedb_schema::auto_migrate::AutoMigrateStep::RemoveIndex(key) => {\n                let (namespace, index_name) = key;\n                let (_owning_def, table_def) = plan\n                    .old\n                    .find_storing_table(namespace, index_name)\n                    .ok_or_else(|| anyhow::anyhow!(\"RemoveIndex: `{index_name}` not found in old module def\"))?;\n                let table_full_name = joined(namespace, &table_def.name);\n                let stored_name = namespace.join_raw(&index_name.clone().into());\n                let table_id = stdb.table_id_from_name_mut(tx, &table_full_name)?.unwrap();\n                let table_schema = stdb.schema_for_table_mut(tx, table_id)?;\n\n                let index_schema = table_schema\n                    .indexes\n                    .iter()\n                    .find(|index| index.index_name == stored_name)\n                    .ok_or_else(|| anyhow::anyhow!(\"Index `{index_name}` not found in table `{table_full_name}`\"))?;\n\n                log!(logger, \"Dropping index `{index_name}` on table `{table_full_name}`\");\n                stdb.drop_index(tx, index_schema.index_id)?;\n            }\n            spacetimedb_schema::auto_migrate::AutoMigrateStep::ChangeTableAccessorName(table_name_key) => {\n                let (namespace, local) = table_name_key;\n                let table_name = joined(namespace, local);\n                let (_, new_table_def): (&ModuleDef, &spacetimedb_schema::def::TableDef) =\n                    plan.new.find_table(table_name_key).ok_or_else(|| {\n                        anyhow::anyhow!(\"ChangeTableAccessorName: `{table_name}` not found in new module def\")\n                    })?;\n\n                let table_id = stdb.table_id_from_name_mut(tx, &table_name)?.unwrap();\n                let new_alias = namespace.join(new_table_def.accessor_name.clone());\n\n                log!(\n                    logger,\n                    \"Changing table accessor name for `{table_name}` to `{new_alias}`\",","sourceCodeStart":345,"sourceCodeEnd":381,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/engine/src/update.rs#L345-L381","documentation":"Auto-migrate step RemoveIndex: the index was found in the old def, but scanning the database's table schema (table_schema.indexes) found no index whose index_name equals the namespace-joined stored name. The database does not have the index the plan intends to drop — drift between old def and live DB, or a stored-name/prefix mismatch.","triggerScenarios":"The index was already dropped in the database while the old def still lists it; stored name mismatch because submodule index names are stored prefixed (namespace.join_raw) and the lookup key differs; an earlier partially applied migration removed the index.","commonSituations":"Retrying migrations after partial application; alias/prefix changes for submodule indexes; manual index drops via SQL alongside module-managed indexes.","solutions":["Refresh the old def from the database's actual schema and regenerate the plan","Compare the stored index_name (with namespace prefix and alias applied) against the plan's name to spot prefixing mismatches","For disposable databases, republish fresh instead of reconciling drift"],"exampleFix":"// before: drop straight from the plan's key\nlet index_schema = table_schema.indexes.iter()\n    .find(|i| i.index_name == stored_name)\n    .ok_or_else(|| anyhow!(\"Index `{index_name}` not found in table `{table_full_name}`\"))?;\n\n// after: resolve by column set when the prefixed name is uncertain\nlet index_schema = table_schema.indexes.iter()\n    .find(|i| ColSet::from(i.algorithm.columns()) == index_cols)\n    .ok_or_else(|| anyhow!(\"Index `{index_name}` not found in table `{table_full_name}`\"))?;","handlingStrategy":"validation","validationCode":"// Before RemoveIndex, confirm the index exists under its stored (prefixed) name\nlet stored_name = namespace.join_raw(&index_name.clone().into());\nanyhow::ensure!(\n    stdb.schema_for_table_mut(&mut tx, table_id)?.indexes.iter()\n        .any(|i| i.index_name == stored_name),\n    \"index {index_name} absent from {table_full_name}; regenerate the plan\"\n);","typeGuard":"fn index_present(schema: &TableSchema, stored_name: &str) -> bool {\n    schema.indexes.iter().any(|i| i.index_name == stored_name)\n}","tryCatchPattern":"match auto_migrate_database(&stdb, &mut tx, auth, &plan, &logger) {\n    Err(e) if e.to_string().contains(\"not found in table\") => {\n        // drift or prefix mismatch: compare stored index names before retrying\n        for i in &stdb.schema_for_table_mut(&mut tx, table_id)?.indexes {\n            log::warn!(\"stored index: {}\", i.index_name);\n        }\n        anyhow::bail!(\"{e:#}\");\n    }\n    r => r,\n}","preventionTips":["Keep index aliases and submodule prefixes stable across publishes","Do not drop module-managed indexes with raw SQL","After partial migrations, refresh the old def from the DB before retrying"],"tags":["rust","spacetimedb","migration","index","schema-drift"],"backgroundTag":"migration-schema-mismatch","analyzedSha":"6dee26c6efc2856793e12b148a59742964f5d783","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}