clockworklabs/SpacetimeDB · error · Error

Only btree indexes are supported in TableCacheImpl

Error message

Only btree indexes are supported in TableCacheImpl

What it means

TableCacheImpl's index read path mirrors the server's btree ranged-scan semantics (prefix columns fixed to equality, range bound on the last term). Only idx.algorithm === 'btree' can be served this way, so requesting a cached index view for any other algorithm (e.g. hash) throws with an explicit 'not yet supported' comment in the source.

Source

Thrown at crates/bindings-typescript/src/sdk/table_cache.ts:120

    }
  }

  // TODO: this just scans the whole table; we should build proper index structures
  #makeReadonlyIndex<
    I extends TableDefForTableName<
      RemoteModule,
      TableName
    >['resolvedIndexes'][number],
  >(
    tableDef: TableDefForTableName<RemoteModule, TableName>,
    idx: I
  ): ReadonlyIndex<TableDefForTableName<RemoteModule, TableName>, I> {
    type TableDef = TableDefForTableName<RemoteModule, TableName>;
    type Row = Prettify<RowType<TableDef>>;

    // We do not yet support non-btree indexes
    if (idx.algorithm !== 'btree') {
      throw new Error('Only btree indexes are supported in TableCacheImpl');
    }

    const columns = idx.columns;

    // Extract the tuple key for this btree index (column order preserved)
    const getKey = (row: Row): readonly unknown[] =>
      columns.map(c => (row as Record<string, unknown>)[c]);

    // The server’s ranged scan fixes all prefix cols to equality and applies
    // the bound only to the *last* term. We mirror that.
    //
    // rangeArg for multi-col index is:
    //   [...prefixEqualValues, (lastTerm | Range<lastTerm>)]
    //
    // If only one element is provided, it’s the last term (scalar or Range).
    const matchRange = (row: Row, rangeArg: any): boolean => {
      const key = getKey(row);

View on GitHub (pinned to 524b4487d9)

Solutions

  1. Change the module schema to use a btree index for columns you read through the client cache
  2. For point lookups on hash-indexed columns, query with a WHERE clause server-side instead of the cache index API
  3. Check for SDK updates - non-btree index support in TableCacheImpl is on the roadmap per the source comment

Example fix

// module (Rust) - before
#[spacetimedb::table(name = user)]
pub struct User {
  #[primary_key]
  #[spacetimedb(index = hash)] // client cache throws on this
  pub email: String,
}

// after
#[spacetimedb::table(name = user)]
pub struct User {
  #[primary_key]
  #[spacetimedb(index = btree)]
  pub email: String,
}
Defensive patterns

Strategy: validation

Validate before calling

const idx = tableDef.resolvedIndexes.find(i => i.accessorName === wanted);
if (idx && idx.algorithm !== 'btree') {
  // skip the cache index API; use a SQL WHERE query or full row iteration
}

Type guard

function isBtreeIndex(idx: { algorithm: string }): boolean {
  return idx.algorithm === 'btree';
}

Prevention

When it happens

Trigger: A module schema declares a non-btree index (e.g. #[index(hash)] on a column) and client code accesses that index through the TableCache index API.

Common situations: Porting a module that used hash indexes for point lookups; a module upgrade adds a hash index and the generated bindings now expose it to the cache; following older examples/docs that assumed index-agnostic access.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16). Data as JSON: /api/errors/79b0222801608abe. Report an issue: GitHub.