clockworklabs/SpacetimeDB · critical

Someone put a forbidden variant in the system table!

Error message

Someone put a forbidden variant in the system table!

What it means

Constraint rows read from the st_constraints system table are converted into ConstraintSchema via From<StConstraintRow> when loading schema. The StConstraintData::Unused variant is the catch-all for forbidden/unknown constraint tags, and converting it panics. Seeing this panic means a system-table row decoded to an unrecognized constraint kind: version skew between the build that wrote the data and the build reading it, or corrupted system-table data.

Source

Thrown at crates/datastore/src/system_tables.rs:1407

        read_via_bsatn(row)
    }
}

impl From<StConstraintRow> for ProductValue {
    fn from(x: StConstraintRow) -> Self {
        to_product_value(&x)
    }
}

impl From<StConstraintRow> for ConstraintSchema {
    fn from(x: StConstraintRow) -> Self {
        Self {
            constraint_id: x.constraint_id,
            constraint_name: x.constraint_name,
            table_id: x.table_id,
            data: match x.constraint_data {
                StConstraintData::Unique { columns } => ConstraintData::Unique(UniqueConstraintData { columns }),
                StConstraintData::Unused(_) => panic!("Someone put a forbidden variant in the system table!"),
            },
        }
    }
}

/// System Table [ST_ROW_LEVEL_SECURITY_NAME]
///
/// | table_id | sql          |
/// |----------|--------------|
/// | 1        | "SELECT ..." |
#[derive(Debug, Clone, PartialEq, Eq, SpacetimeType)]
#[sats(crate = spacetimedb_lib)]
pub struct StRowLevelSecurityRow {
    pub table_id: TableId,
    pub sql: RawSql,
}

impl TryFrom<RowRef<'_>> for StRowLevelSecurityRow {

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Open the database with the spacetimedb version that wrote it (or one that maps the tag), then export and reimport the data.
  2. Check release notes for constraint-variant changes and pick a compatible version.
  3. If it reproduces on a freshly created database, report upstream with the offending constraint row.
Defensive patterns

Strategy: try-catch

Try / catch

// wrap schema loading so an unrecognized constraint variant is reported, not fatal
let loaded = std::panic::catch_unwind(|| db.load_schema());
match loaded {
    Ok(schema) => schema,
    Err(p) if panic_message(&p).contains("forbidden variant") => {
        // system table contains a constraint tag unknown to this build:
        // reopen with the version that wrote the data, then export/reimport
    }
    Err(p) => std::panic::resume_unwind(p),
}

Prevention

When it happens

Trigger: Booting or loading schema for a database whose st_constraints rows contain a constraint tag that the running build maps to StConstraintData::Unused, hitting the From impl during schema load.

Common situations: Opening a commitlog/database written by a different spacetimedb version with renamed constraint variants; forks that added constraint variants; bit-rot in stored system tables.

Understand the failure class

Related errors


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