clockworklabs/SpacetimeDB · error

RemoveConstraint: `{constraint_name}` not found in old modul

Error message

RemoveConstraint: `{constraint_name}` not found in old module def

What it means

Applying RemoveConstraint: the diff planned dropping a constraint that exists in the database but not in the new module, yet plan.old.find_storing_table(namespace, constraint_name) cannot find its owning table in the old module def. The old-def reconstruction does not contain a constraint the database appears to have - the old def and the database's actual history disagree. The publish aborts.

Source

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

                    .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!(
                    logger,
                    "Changing index source name for `{}` on table `{}` from `{}` to `{}`",
                    index_name,
                    table_full_name,
                    index_schema.alias.as_deref().unwrap_or(""),
                    new_source_name,
                );
                stdb.alter_index_source_name(tx, index_schema.index_id, new_source_name)?;
            }
            spacetimedb_schema::auto_migrate::AutoMigrateStep::RemoveConstraint(key) => {
                let (namespace, constraint_name) = key;
                let (_owning_def, table_def) =
                    plan.old.find_storing_table(namespace, constraint_name).ok_or_else(|| {
                        anyhow::anyhow!("RemoveConstraint: `{constraint_name}` not found in old module def")
                    })?;
                let table_full_name = joined(namespace, &table_def.name);
                let stored_name = namespace.join_raw(&constraint_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 constraint_schema = table_schema
                    .constraints
                    .iter()
                    .find(|constraint| constraint.constraint_name == stored_name)
                    .unwrap();

                log!(
                    logger,
                    "Dropping constraint `{constraint_name}` on table `{table_full_name}`"
                );
                stdb.drop_constraint(tx, constraint_schema.constraint_id)?;
            }

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Clean-rebuild and republish (removes stale def artifacts).
  2. Publish constraint changes alone - no renames, moves, or drops in the same build.
  3. Pin constraint names where supported (e.g. #[unique(name = "...")]) on both module versions.
  4. Match the toolchain version that published the live database, then migrate stepwise.
  5. Dev: spacetime publish --delete-data <db>.
  6. Report persistent cases with the module diff and constraint names.

Example fix

// before: drop #[unique] and rename its column in one publish
pub struct Player {
    #[spacetimedb::column(name = "level")] // was `hp`, still unique-keyed before
    pub level: u32,
}

// after: two publishes
// 1) remove #[unique] only, keep names
// 2) rename the column separately
Defensive patterns

Strategy: fallback

Validate before calling

use spacetimedb_schema::auto_migrate::AutoMigrateStep;
for step in &plan.steps {
    if let AutoMigrateStep::RemoveConstraint((namespace, cname)) = step {
        if plan.old.find_storing_table(namespace, cname).is_none() {
            anyhow::bail!("old def lacks constraint {} - schema drift", cname);
        }
    }
}

Type guard

fn constraint_in_old_def(plan: &AutoMigratePlan, ns: &str, cname: &str) -> bool {
    plan.old.find_storing_table(ns, cname).is_some()
}

Try / catch

match update_database(&stdb, tx, &plan, ...).await {
    Err(e) if e.to_string().contains("RemoveConstraint")
        && e.to_string().contains("old module def") => {
        // Fall back: publish the exact prior build first, then remove the constraint stepwise.
    }
    result => result?,
}

Prevention

When it happens

Trigger: Constraint auto-names (unique, primary-key-backed) differing between the compiler build that published the database and the current one; renaming/dropping the table or constraint in the same publish as other changes; submodule constraint namespace-prefix drift.

Common situations: Adding or removing #[unique]/#[primary_key] plus renaming fields or tables in one publish; upgrading compiler versions between publishes; moving constrained tables into submodules.

Related errors


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