clockworklabs/SpacetimeDB · error · anyhow::Error
Cannot remove table `{table_name}`: table contains data. Cle
Error message
Cannot remove table `{table_name}`: table contains data. Clear the table's rows (e.g. via a reducer) before removing it from your schema. What it means
Thrown by the auto-migrator when a new module version removes a table that still contains rows. SpacetimeDB refuses to drop non-empty tables during an automatic migration because that would silently destroy live data, so the whole update transaction is aborted with anyhow::bail.
Source
Thrown at crates/engine/src/update.rs:274
{
anyhow::bail!("Precheck failed: added sequence {sequence_name} already has values in range",);
}
}
}
}
log::info!("Running database update steps: {}", stdb.database_identity());
let mut res = UpdateResult::Success;
for step in plan.steps {
match step {
spacetimedb_schema::auto_migrate::AutoMigrateStep::RemoveTable(table_name_key) => {
let (namespace, local) = table_name_key;
let table_name = joined(namespace, local);
let table_id = stdb.table_id_from_name_mut(tx, &table_name)?.unwrap();
if stdb.table_row_count_mut(tx, table_id).unwrap_or(0) > 0 {
anyhow::bail!(
"Cannot remove table `{table_name}`: table contains data. \
Clear the table's rows (e.g. via a reducer) before removing it from your schema."
);
}
log!(logger, "Dropping table `{table_name}`");
stdb.drop_table(tx, table_id)?;
}
spacetimedb_schema::auto_migrate::AutoMigrateStep::AddTable(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!("AddTable: table `{table_name}` not found in new module def"))?;
log!(logger, "Creating table `{table_name}`");
create_table_from_def_with_prefix(stdb, tx, owning_def, table_def, namespace)?;
}View on GitHub (pinned to 6dee26c6ef)
Solutions
- Clear the table's rows before publishing, e.g. spacetime sql <db> "DELETE FROM <table>", or call a cleanup reducer that deletes all rows.
- If the data is disposable, delete and republish the database (spacetime delete <db> && spacetime publish <db>) so the table never exists at publish time.
- Keep the table in the schema for one more publish cycle and remove it only after confirming it is empty.
- Use the manual migration tooling (spacetime migrate) to author an explicit data-preserving migration instead of relying on auto-migrate.
Example fix
-- before: publish removes table, rows still present -> error spacetime publish my-db -- after: clear rows first, then publish spacetime sql my-db "DELETE FROM old_table" spacetime publish my-db
Defensive patterns
Strategy: validation
Validate before calling
-- before publishing a version that removes a table: spacetime sql my-db "SELECT COUNT(*) AS n FROM old_table" -- if n > 0, clear it first: spacetime sql my-db "DELETE FROM old_table"
Try / catch
match publish(&db, &module).await {
Err(e) if e.to_string().contains("table contains data") => {
// clear rows via reducer/SQL, then retry the publish once
}
other => other,
} Prevention
- Treat table removal as a two-step deploy: clear rows first, publish the removal second.
- Keep a cleanup reducer per disposable table so purging before schema changes is one call.
- Run publishes against a disposable dev database first to surface destructive diffs.
When it happens
Trigger: Publishing a module whose schema no longer declares a table that exists in the database, while stdb.table_row_count_mut(tx, table_id) returns > 0 for that table in the AutoMigrateStep::RemoveTable branch of the update plan.
Common situations: Renaming a table (old table dropped, new one added) on a database with data; cleaning up 'unused' tables that actually hold rows; iterating on schemas against a dev database that accumulated test data instead of being republished fresh.
Related errors
- table should exist in the database for AddConstraint
- Precheck failed: added sequence {sequence_name} already has
- Adding schedules is not yet implemented
- Removing schedules is not yet implemented
- TableId `{return_id}` does not exist
AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20).
Data as JSON: /api/errors/130f3d2a2ed51b80.
Report an issue: GitHub.