clockworklabs/SpacetimeDB · error · TypeError
wrong number of elements
Error message
wrong number of elements
What it means
For a multi-column unique index (including composite unique constraints), find() serializes its argument as a point key: you must pass exactly one value per indexed column, in index order. Passing a scalar, too few, or too many elements throws TypeError('wrong number of elements') before any datastore call is made.
Source
Thrown at crates/bindings-typescript/src/server/runtime.ts:1281
BINARY_WRITER.reset(buf);
serializeRow(BINARY_WRITER, row);
sys.datastore_update_bsatn(
table_id,
index_id,
buf.buffer,
BINARY_WRITER.offset
);
integrateGeneratedColumns?.(row, buf.view);
return row;
};
}
index = base as UniqueIndex<any, any>;
} else if (isUnique) {
// numColumns != 1, unique index
const base = {
find: (colVal: IndexVal<any, any>): RowType<any> | null => {
if (colVal.length !== numColumns) {
throw new TypeError('wrong number of elements');
}
const buf = LEAF_BUF;
const point_len = serializePoint(buf, colVal);
const iter_id = sys.datastore_index_scan_point_bsatn(
index_id,
buf.buffer,
point_len
);
return tableIterateOne(iter_id, deserializeRow);
},
delete: (colVal: IndexVal<any, any>): boolean => {
if (colVal.length !== numColumns)
throw new TypeError('wrong number of elements');
const buf = LEAF_BUF;
const point_len = serializePoint(buf, colVal);
const num = sys.datastore_delete_by_index_scan_point_bsatn(
index_id,View on GitHub (pinned to 524b4487d9)
Solutions
- Pass an array with exactly one value per indexed column, in index order: find([region, id])
- Regenerate/refresh type information after changing index definitions so arity errors surface at compile time
- Centralize each index lookup in one helper so the correct arity is written in a single place
Example fix
// before (unique index on [region, id]) const user = ctx.db.users.byRegionId.find(id); // scalar against 2-column index // after const user = ctx.db.users.byRegionId.find([region, id]);
Defensive patterns
Strategy: type-guard
Validate before calling
// before calling find on a composite unique index covering N columns:
function assertIndexKey(colVal: unknown[], numColumns: number): void {
if (!Array.isArray(colVal) || colVal.length !== numColumns) {
throw new Error(`expected ${numColumns} key values, got ${Array.isArray(colVal) ? colVal.length : typeof colVal}`);
}
} Type guard
const hasIndexArity = (v: unknown, n: number): v is unknown[] => Array.isArray(v) && v.length === n; // usage: if (hasIndexArity(key, 2)) ctx.db.users.byRegionId.find(key as [typeof region, typeof id]);
Prevention
- Regenerate bindings after any index change so the compiler enforces key arity
- Keep one typed helper per composite index that constructs the key array in index order
- When an index gains a column, grep all find/delete call sites for that index
When it happens
Trigger: Calling find(scalarValue) against a 2-column unique index; find([a]) or find([a, b, c]) where the index covers exactly 2 columns; call sites not updated after the index definition changed arity.
Common situations: Index changed from single-column to composite (or vice versa) without updating queries; copy-paste from a table with a single-column index; stale generated bindings after a schema edit.
Related errors
- too many elements
- Subscriptions must have at least one query
- Subscriptions must be SQL strings or typed queries
- Only btree indexes are supported in TableCacheImpl
- transaction retry failed again
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/6dd124c5fbafea93.
Report an issue: GitHub.