clockworklabs/SpacetimeDB · error

AddConstraint: constraint `{constraint_name}` not found in n

Error message

AddConstraint: constraint `{constraint_name}` not found in new module def

What it means

AddConstraint resolved the storing table via find_storing_table, but plan.new.lookup::<ConstraintDef>(key) returned None: the constraint is not registered as a lookupable entity in the new module def set even though a table references it. The def set's index is internally inconsistent (typically a namespace-key drift for submodule constraints). The publish aborts.

Source

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

                    .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)?;
            }
            spacetimedb_schema::auto_migrate::AutoMigrateStep::AddConstraint(key) => {
                let (namespace, constraint_name) = key;
                let (owning_def, table_def) = plan
                    .new
                    .find_storing_table(namespace, constraint_name)
                    .ok_or_else(|| anyhow::anyhow!("AddConstraint: `{constraint_name}` not found in new module def"))?;
                let table_full_name = joined(namespace, &table_def.name);
                let constraint_def: &ConstraintDef = plan.new.lookup(key).ok_or_else(|| {
                    anyhow::anyhow!("AddConstraint: constraint `{constraint_name}` not found in new module def")
                })?;
                let table_id = stdb
                    .table_id_from_name_mut(tx, &table_full_name)?
                    .expect("table should exist in the database for AddConstraint");
                let mut constraint_schema =
                    ConstraintSchema::from_module_def(owning_def, constraint_def, table_id, ConstraintId::SENTINEL);

                // Apply namespace prefix for submodule constraints
                constraint_schema.constraint_name = namespace.join_raw(&constraint_schema.constraint_name);
                log!(
                    logger,
                    "Adding constraint `{constraint_name}` on table `{table_full_name}`"
                );
                stdb.create_constraint(tx, constraint_schema)?;
            }
            spacetimedb_schema::auto_migrate::AutoMigrateStep::AddSequence(key) => {
                let (namespace, sequence_name) = key;
                let (owning_def, table_def) = plan

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Full clean rebuild (delete target/ entirely, not just the crate), spacetime build, republish.
  2. Move the constrained table to the crate root (or a stable module path) for the publish that adds the constraint, then relocate afterwards.
  3. Ensure exactly one SDK/macro version appears in the dependency tree (cargo tree -i spacetimedb).
  4. Dev: spacetime publish --delete-data <db>.
  5. Report as a def-indexing bug with the submodule layout.

Example fix

// before: unique constraint on a submodule table fails to resolve in the def registry
mod guild {
    #[spacetimedb::table(name = "members")]
    pub struct Member { #[unique] pub name: String }
}

// after: add the constraint while the table is at the root, move it in a later publish
#[spacetimedb::table(name = "members")]
pub struct Member { #[unique] pub name: String }
Defensive patterns

Strategy: validation

Validate before calling

use spacetimedb_schema::auto_migrate::AutoMigrateStep;
use spacetimedb_schema::def::ConstraintDef;
for step in &plan.steps {
    if let AutoMigrateStep::AddConstraint(key) = step {
        anyhow::ensure!(
            plan.new.lookup::<ConstraintDef>(key).is_some(),
            "constraint {:?} missing from the new def registry", key
        );
    }
}

Type guard

fn constraint_registered(plan: &AutoMigratePlan, key: (&str, &str)) -> bool {
    plan.new.lookup::<ConstraintDef>(key).is_some()
}

Try / catch

match update_database(&stdb, tx, &plan, ...).await {
    Err(e) if e.to_string().contains("AddConstraint: constraint") => {
        // Def registry desync: full clean rebuild; add the constraint at the crate root first.
    }
    result => result?,
}

Prevention

When it happens

Trigger: Constraints on tables inside submodules where the constraint's registration namespace differs from the table's namespace; module defs generated by mismatched SDK/macro versions so the constraint map and the entity registry disagree.

Common situations: Constrained tables declared inside submodules; upgrading the spacetimedb SDK macro version between builds; partial clean builds mixing artifacts from two versions.

Related errors


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