clockworklabs/SpacetimeDB · error
`table_id` must not be `TableId::SENTINEL` in `{index_schema
Error message
`table_id` must not be `TableId::SENTINEL` in `{index_schema:#?}` What it means
MutTxId::create_index rejects an IndexSchema whose table_id equals TableId::SENTINEL. The sentinel is the unset marker; a real, datastore-allocated table id is required so the index can be attached to an existing table (the code also verifies the table exists via table_name). Passing the sentinel means the schema was built without resolving the target table first.
Source
Thrown at crates/datastore/src/locking_tx_datastore/mut_tx.rs:1774
Ok(table_id)
}
/// Create an index.
///
/// Requires:
/// - `index.index_name` must not be used for any other database entity.
/// - `index.index_id == IndexId::SENTINEL`
/// - `index.table_id != TableId::SENTINEL`
/// - `is_unique` must be `true` if and only if a unique constraint will exist on
/// `ColSet::from(&index.index_algorithm.columns())` after this transaction is committed.
///
/// Ensures:
/// - The index metadata is inserted into the system tables (and other data structures reflecting them).
/// - The returned ID is unique and is not `IndexId::SENTINEL`.
pub fn create_index(&mut self, mut index_schema: IndexSchema, is_unique: bool) -> Result<IndexId> {
let table_id = index_schema.table_id;
if table_id == TableId::SENTINEL {
return Err(anyhow::anyhow!("`table_id` must not be `TableId::SENTINEL` in `{index_schema:#?}`").into());
}
log::trace!(
"INDEX CREATING: {} for table: {} and algorithm: {:?}",
index_schema.index_name,
table_id,
index_schema.index_algorithm
);
if self.table_name(table_id).is_none() {
return Err(TableError::IdNotFoundState(table_id).into());
}
// Insert the index row into `st_indexes` and write back the `IndexId`.
// NOTE: Because `st_indexes` has a unique index on `index_name`,
// this will fail if the index already exists.
let row: StIndexRow = index_schema.clone().into();
let index_id = self
.insert_via_serialize_bsatn(ST_INDEX_ID, &row)?View on GitHub (pinned to 9e0d92412f)
Solutions
- Resolve the real table id first (look the table up by name in the same transaction) and set index_schema.table_id before calling create_index
- Add a debug assertion at schema construction sites that table_id != TableId::SENTINEL
- Check the error's schema dump to see which index was built incorrectly
Example fix
// before
let schema = IndexSchema { table_id: TableId::SENTINEL, .. };
let index_id = tx.create_index(schema, true)?;
// after
let table_id = tx
.table_id_from_name("t")
.ok_or_else(|| anyhow::anyhow!("table t does not exist"))?
.into();
let schema = IndexSchema { table_id, .. };
let index_id = tx.create_index(schema, true)?; Defensive patterns
Strategy: type-guard
Validate before calling
// Resolve the table id before building the index schema
let table_id = tx
.table_id_from_name("t")
.ok_or_else(|| anyhow::anyhow!("table t does not exist"))?
.into();
let schema = IndexSchema { table_id, .. }; Type guard
fn index_schema_has_table(schema: &IndexSchema) -> bool {
schema.table_id != TableId::SENTINEL
} Try / catch
match tx.create_index(schema, is_unique) {
Err(e) if e.to_string().contains("table_id` must not be `TableId::SENTINEL``") => {
// Fill in the real table id and rebuild the schema
}
other => other,
} Prevention
- Always resolve table ids from names in the same transaction before building schemas
- Assert non-sentinel ids in schema constructors in debug builds
- Log the full schema dump on failure - it names the offending index
When it happens
Trigger: Calling create_index with an IndexSchema constructed with the default/sentinel table_id - e.g. building the schema from partial metadata or copying a template without setting table_id.
Common situations: Programmatic schema construction in tools and tests; DDL translation layers that forget the table-id lookup step.
Related errors
- `table_id` must not be `TableId::SENTINEL` in `{seq:#?}`
- `sequence_id` must be `SequenceId::SENTINEL` in `{:#?}`
- `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/392c7c56705dcbc9.
Report an issue: GitHub.