clockworklabs/SpacetimeDB · error

IndexId `{index_id}` does not exist

Error message

IndexId `{index_id}` does not exist

What it means

TxId::with_index found the table but get_index_by_id_with_table returned None: no index with the given IndexId is attached to that table. The index was dropped, belongs to a different table, or has not been created yet (e.g. its creation is still a pending schema change).

Source

Thrown at crates/datastore/src/locking_tx_datastore/tx.rs:141

        self.committed_state_shared_lock.iter_by_col_eq(table_id, cols, value)
    }
}

impl TxId {
    fn with_index<'a, R>(
        &'a self,
        table_id: TableId,
        index_id: IndexId,
        seek: impl FnOnce(TableAndIndex<'a>) -> R,
    ) -> anyhow::Result<R> {
        self.committed_state_shared_lock
            .get_table(table_id)
            .ok_or_else(|| anyhow::anyhow!("TableId `{table_id}` does not exist"))
            .and_then(|table| {
                table
                    .get_index_by_id_with_table(&self.committed_state_shared_lock.blob_store, index_id)
                    .map(seek)
                    .ok_or_else(|| anyhow::anyhow!("IndexId `{index_id}` does not exist"))
            })
    }

    /// Release this read-only transaction,
    /// allowing new mutable transactions to start if this was the last read-only transaction.
    ///
    /// Returns:
    /// - [`TxOffset`], the smallest transaction offset visible to this transaction.
    /// - [`TxMetrics`], various measurements of the work performed by this transaction.
    /// - `ReducerName`, the name of the reducer which ran within this transaction.
    pub(super) fn release(self) -> (TxOffset, TxMetrics, Option<ReducerName>) {
        // A read tx doesn't consume `next_tx_offset`, so subtract one to obtain
        // the offset that was visible to the transaction.
        //
        // Note that technically the tx could have run against an empty database,
        // in which case we'd wrongly return zero (a non-existent transaction).
        // This doesn not happen in practice, however, as [RelationalDB::set_initialized]
        // creates a transaction.

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Look the index up by name via the current schema and use the resolved IndexId
  2. Re-compile query plans after any module or schema update
  3. Guard index usage with a startup schema check (iterate st_indexes or get_index_by_name)
  4. Confirm the index-creating transaction actually committed

Example fix

// before: hardcoded IndexId from an earlier schema generation
let iter = tx.index_scan_range(table_id, hardcoded_index_id, &range)?;

// after: resolve the IndexId by name at startup
let index_id = tx.index_id_by_name(table_id, index_name)?.expect("index exists");
let iter = tx.index_scan_range(table_id, index_id, &range)?;
Defensive patterns

Strategy: validation

Validate before calling

// Resolve the index by name at startup instead of trusting a stored IndexId
fn resolve_index_id(tx: &TxId, table_id: TableId, index_name: &str) -> Option<IndexId> {
    tx.committed_state_shared_lock
        .get_table(table_id)?
        .get_index_by_name(index_name)
        .map(|(_, idx)| idx.index_id)
}

Try / catch

Catch the missing-index error, re-resolve the index by name from the current schema, recompile the plan, and retry once; if the index was dropped, fall back to a table scan or re-subscribe after schema refresh.

Prevention

When it happens

Trigger: Index scans using an IndexId captured before the index was dropped or recreated; querying an index that exists only in a newer module version than the database runs; mixing up ids between tables; scanning an index whose creation transaction has not committed.

Common situations: Module updates dropping indexes while old plans cache IndexIds; replicas lagging behind the coordinator's schema; developer tools hardcoding index ids; race between schema change and readers.

Related errors


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