{"record":{"id":"392c7c56705dcbc9","repo":"clockworklabs/SpacetimeDB","slug":"table-id-must-not-be-tableid-sentinel-in-in","errorCode":null,"errorMessage":"`table_id` must not be `TableId::SENTINEL` in `{index_schema:#?}`","messagePattern":"`table_id` must not be `TableId::SENTINEL` in `(.+?)`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/datastore/src/locking_tx_datastore/mut_tx.rs","lineNumber":1774,"sourceCode":"        Ok(table_id)\n    }\n\n    /// Create an index.\n    ///\n    /// Requires:\n    /// - `index.index_name` must not be used for any other database entity.\n    /// - `index.index_id == IndexId::SENTINEL`\n    /// - `index.table_id != TableId::SENTINEL`\n    /// - `is_unique` must be `true` if and only if a unique constraint will exist on\n    ///   `ColSet::from(&index.index_algorithm.columns())` after this transaction is committed.\n    ///\n    /// Ensures:\n    /// - The index metadata is inserted into the system tables (and other data structures reflecting them).\n    /// - The returned ID is unique and is not `IndexId::SENTINEL`.\n    pub fn create_index(&mut self, mut index_schema: IndexSchema, is_unique: bool) -> Result<IndexId> {\n        let table_id = index_schema.table_id;\n        if table_id == TableId::SENTINEL {\n            return Err(anyhow::anyhow!(\"`table_id` must not be `TableId::SENTINEL` in `{index_schema:#?}`\").into());\n        }\n\n        log::trace!(\n            \"INDEX CREATING: {} for table: {} and algorithm: {:?}\",\n            index_schema.index_name,\n            table_id,\n            index_schema.index_algorithm\n        );\n        if self.table_name(table_id).is_none() {\n            return Err(TableError::IdNotFoundState(table_id).into());\n        }\n\n        // Insert the index row into `st_indexes` and write back the `IndexId`.\n        // NOTE: Because `st_indexes` has a unique index on `index_name`,\n        // this will fail if the index already exists.\n        let row: StIndexRow = index_schema.clone().into();\n        let index_id = self\n            .insert_via_serialize_bsatn(ST_INDEX_ID, &row)?","sourceCodeStart":1756,"sourceCodeEnd":1792,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/9e0d92412ff2248f401a8ad12d535f2b5ac30912/crates/datastore/src/locking_tx_datastore/mut_tx.rs#L1756-L1792","documentation":"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.","triggerScenarios":"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.","commonSituations":"Programmatic schema construction in tools and tests; DDL translation layers that forget the table-id lookup step.","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"],"exampleFix":"// before\nlet schema = IndexSchema { table_id: TableId::SENTINEL, .. };\nlet index_id = tx.create_index(schema, true)?;\n\n// after\nlet table_id = tx\n    .table_id_from_name(\"t\")\n    .ok_or_else(|| anyhow::anyhow!(\"table t does not exist\"))?\n    .into();\nlet schema = IndexSchema { table_id, .. };\nlet index_id = tx.create_index(schema, true)?;","handlingStrategy":"type-guard","validationCode":"// Resolve the table id before building the index schema\nlet table_id = tx\n    .table_id_from_name(\"t\")\n    .ok_or_else(|| anyhow::anyhow!(\"table t does not exist\"))?\n    .into();\nlet schema = IndexSchema { table_id, .. };","typeGuard":"fn index_schema_has_table(schema: &IndexSchema) -> bool {\n    schema.table_id != TableId::SENTINEL\n}","tryCatchPattern":"match tx.create_index(schema, is_unique) {\n    Err(e) if e.to_string().contains(\"table_id` must not be `TableId::SENTINEL``\") => {\n        // Fill in the real table id and rebuild the schema\n    }\n    other => other,\n}","preventionTips":["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"],"tags":["spacetimedb","datastore","index","schema","sentinel"],"backgroundTag":"sentinel-id-misuse","analyzedSha":"9e0d92412ff2248f401a8ad12d535f2b5ac30912","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}