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
- Change the module schema to use a btree index for columns you read through the client cache
- For point lookups on hash-indexed columns, query with a WHERE clause server-side instead of the cache index API
- 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
- Stick to btree indexes in module schemas you plan to read via the client cache
- Keep point lookups on hash indexes server-side (subscription WHERE clauses)
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
- cannot serialize refs without a typespace
- cannot deserialize refs without a typespace
- Index '${idx.sourceName ?? '<unknown>'}' on table '${tableDe
- Missing type name for ${typeBuilder.constructor.name ?? 'Typ
- Index '${indexLabel}' on table '${tableLabel}' must define a
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/79b0222801608abe.
Report an issue: GitHub.