clockworklabs/SpacetimeDB · error
`table_id` must not be `TableId::SENTINEL` in `{seq:#?}`
Error message
`table_id` must not be `TableId::SENTINEL` in `{seq:#?}` What it means
MutTxId::create_sequence rejects a SequenceSchema whose table_id equals TableId::SENTINEL. A sequence must be attached to a concrete existing table column; the sentinel indicates the field was never populated, so creation is refused before any st_sequences row is written.
Source
Thrown at crates/datastore/src/locking_tx_datastore/mut_tx.rs:2147
get_sequence_mut(seq_state, seq_id)?
.gen_next_value()
.ok_or_else(|| SequenceError::UnableToAllocate(seq_id).into())
}
impl MutTxId {
/// Create a sequence.
/// Requires:
/// - `seq.sequence_id == SequenceId::SENTINEL`
/// - `seq.table_id != TableId::SENTINEL`
/// - `seq.sequence_name` must not be used for any other database entity.
///
/// Ensures:
/// - The sequence metadata is inserted into the system tables (and other data structures reflecting them).
/// - The returned ID is unique and not `SequenceId::SENTINEL`.
pub fn create_sequence(&mut self, seq: SequenceSchema) -> Result<SequenceId> {
if seq.table_id == TableId::SENTINEL {
return Err(anyhow::anyhow!("`table_id` must not be `TableId::SENTINEL` in `{seq:#?}`").into());
}
let table_id = seq.table_id;
let matching_system_table_schema = system_tables().iter().find(|s| s.table_id == table_id).cloned();
if seq.sequence_id != SequenceId::SENTINEL && matching_system_table_schema.is_none() {
return Err(anyhow::anyhow!("`sequence_id` must be `SequenceId::SENTINEL` in `{:#?}`", seq).into());
}
let sequence_id = seq.sequence_id;
log::trace!(
"SEQUENCE CREATING: {} for table: {} and col: {}",
seq.sequence_name,
table_id,
seq.col_pos
);
View on GitHub (pinned to 9e0d92412f)
Solutions
- Resolve the owning table's id (by name lookup in the transaction) and set seq.table_id before calling create_sequence
- Assert at construction time that table_id differs from TableId::SENTINEL to fail closer to the bug
Example fix
// before
let seq = SequenceSchema { table_id: TableId::SENTINEL, .. };
let sequence_id = tx.create_sequence(seq)?;
// after
let table_id = tx
.table_id_from_name("t")
.ok_or_else(|| anyhow::anyhow!("table t does not exist"))?
.into();
let seq = SequenceSchema { table_id, .. };
let sequence_id = tx.create_sequence(seq)?; Defensive patterns
Strategy: type-guard
Validate before calling
// Resolve the owning table before building the sequence schema
let table_id = tx
.table_id_from_name("t")
.ok_or_else(|| anyhow::anyhow!("table t does not exist"))?
.into();
let seq = SequenceSchema { table_id, .. }; Type guard
fn sequence_schema_has_table(seq: &SequenceSchema) -> bool {
seq.table_id != TableId::SENTINEL
} Try / catch
match tx.create_sequence(seq) {
Err(e) if e.to_string().contains("table_id` must not be `TableId::SENTINEL``") => {
// Set the owning table id and retry
}
other => other,
} Prevention
- Derive table ids from live lookups, never from templates or defaults
- Validate schema structs before handing them to datastore APIs
When it happens
Trigger: Calling create_sequence with a SequenceSchema built with the default/sentinel table_id - e.g. constructing the schema programmatically without resolving the owning table.
Common situations: Schema tooling and migrations that build SequenceSchema values from partial metadata; tests copying template schemas.
Related errors
- `sequence_id` must be `SequenceId::SENTINEL` in `{:#?}`
- `table_id` must not be `TableId::SENTINEL` in `{index_schema
- `table_id` must not be `TableId::SENTINEL` in `{constraint:#
- unique constraint on table {table_id} column(s) {col_list:?}
- Index '${indexLabel}' on table '${tableLabel}' must define a
AI-assisted analysis of clockworklabs/SpacetimeDB@9e0d92412f (2026-08-20).
Data as JSON: /api/errors/2d47e35678f82d9b.
Report an issue: GitHub.