clockworklabs/SpacetimeDB · error
ChangePrimaryKey: table `{table_name}` not found in new modu
Error message
ChangePrimaryKey: table `{table_name}` not found in new module def What it means
Applying ChangePrimaryKey, which moves a table's primary key to another column: plan.new.find_table fails, so the new primary key cannot be read from the new def. The primary-key change was bundled with a table key that no longer resolves - plan/def desync. The publish aborts.
Source
Thrown at crates/engine/src/update.rs:588
let access = if let Some((_owning_def, table_def)) = plan.new.find_table(table_name_key) {
table_def.table_access
} else {
let (_owning_def, view_def) = plan.new.find_view(table_name_key).ok_or_else(|| {
anyhow::anyhow!("ChangeAccess: `{table_name}` not found as a table or view in new module def")
})?;
if view_def.is_public {
TableAccess::Public
} else {
TableAccess::Private
}
};
stdb.alter_table_access(tx, &table_name, access.into())?;
}
spacetimedb_schema::auto_migrate::AutoMigrateStep::ChangePrimaryKey(table_name_key) => {
let (namespace, local) = table_name_key;
let table_name = joined(namespace, local);
let (_owning_def, table_def) = plan.new.find_table(table_name_key).ok_or_else(|| {
anyhow::anyhow!("ChangePrimaryKey: table `{table_name}` not found in new module def")
})?;
log!(logger, "Changing primary key for table `{table_name}`");
stdb.alter_table_primary_key(tx, &table_name, table_def.primary_key)?;
}
spacetimedb_schema::auto_migrate::AutoMigrateStep::AddSchedule(_) => {
anyhow::bail!("Adding schedules is not yet implemented");
}
spacetimedb_schema::auto_migrate::AutoMigrateStep::RemoveSchedule(_) => {
anyhow::bail!("Removing schedules is not yet implemented");
}
spacetimedb_schema::auto_migrate::AutoMigrateStep::AddRowLevelSecurity(sql_rls) => {
log!(logger, "Adding row-level security `{sql_rls}`");
let rls = plan.new.lookup::<RawRowLevelSecurityDefV9>(sql_rls).ok_or_else(|| {
anyhow::anyhow!("AddRowLevelSecurity: RLS `{sql_rls}` not found in new module def")
})?;
let rls = RowLevelExpr::build_row_level_expr(tx, &auth_ctx, rls)?;
stdb.create_row_level_security(tx, rls.def)?;View on GitHub (pinned to 6dee26c6ef)
Solutions
- Clean-rebuild and republish.
- Publish the primary-key change alone: same table name, same column names.
- Pin table and column names with #[table(name = ...)] / #[column(name = ...)].
- Align SDK/CLI/server versions with the live database.
- Dev: spacetime publish --delete-data <db> (recreating loses rows; export first if needed).
- Report as a planner bug if a clean single-change publish fails.
Example fix
// before: change #[primary_key] column AND rename the table in one publish
#[spacetimedb::table(name = "members")] // was `players`
pub struct Member { #[primary_key] pub name: String, pub id: u64 /* was PK */ }
// after: two publishes
// 1) re-key keeping name `players`
#[spacetimedb::table(name = "players")]
pub struct Player { #[primary_key] pub name: String, pub id: u64 }
// 2) rename the table separately Defensive patterns
Strategy: validation
Validate before calling
use spacetimedb_schema::auto_migrate::AutoMigrateStep;
for step in &plan.steps {
if let AutoMigrateStep::ChangePrimaryKey(key) = step {
if plan.new.find_table(key).is_none() {
anyhow::bail!("ChangePrimaryKey step references table {:?} missing from new def", key);
}
}
} Type guard
fn pk_table_in_new_def(plan: &AutoMigratePlan, key: (&str, &str)) -> bool {
plan.new.find_table(key).is_some()
} Try / catch
match update_database(&stdb, tx, &plan, ...).await {
Err(e) if e.to_string().contains("ChangePrimaryKey") => {
// Split: re-key with a stable table/column naming; rename in a follow-up publish.
}
result => result?,
} Prevention
- Re-key tables in a publish with no renames of the table or PK column.
- Pin table and column names before changing #[primary_key].
- Export data before re-keying, since fallbacks may require --delete-data.
- Clean-build and align toolchain versions before the migration.
When it happens
Trigger: Moving #[primary_key] to a different column while renaming/moving the table, or changing the PK column's stored name, in the same publish; def/plan desync from stale artifacts or version mismatch.
Common situations: Re-keying tables (e.g. from auto_inc id to a composite/natural key) during broader refactors; renaming the PK column in the same commit as the re-key.
Related errors
- ChangeTableAccessorName: `{table_name}` not found in new mod
- ChangeColumnAccessorName: `{table_name}` not found in new mo
- Column `{col_name}` not found in table `{table_name}`
- ChangeIndexSourceName: `{index_name}` not found in old modul
- ChangeIndexSourceName: `{index_name}` not found in new modul
AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20).
Data as JSON: /api/errors/1ec4b4622c8485b3.
Report an issue: GitHub.