clockworklabs/SpacetimeDB · error · TypeError

too many elements

Error message

too many elements

What it means

For a multi-column ranged index, filter()/delete() accept a prefix/range array of at most numColumns elements: all but the last are equality values and the last may be a Range bound. serializeRange throws TypeError('too many elements') when the array is longer than the index's column count: you cannot constrain more columns than the index covers.

Source

Thrown at crates/bindings-typescript/src/server/runtime.ts:1425

        },
      } as PointIndex<any, any>;
    } else {
      // numColumns != 1
      const isCompleteScalarKey = (range: any[]): boolean => {
        // Preserve the point-scan path only for complete scalar keys.
        // A complete key with a Range in the final position is still a range
        // scan over that column with equality over the preceding prefix.
        return (
          range.length === numColumns &&
          !(range[range.length - 1] instanceof Range)
        );
      };

      const serializeRange = (
        buffer: ResizableBuffer,
        range: any[]
      ): IndexScanArgs => {
        if (range.length > numColumns) throw new TypeError('too many elements');

        BINARY_WRITER.reset(buffer);
        const writer = BINARY_WRITER;
        const prefix_elems = range.length - 1;
        for (let i = 0; i < prefix_elems; i++) {
          indexSerializers[i](writer, range[i]);
        }
        const rstartOffset = writer.offset;
        const term = range[range.length - 1];
        const serializeTerm = indexSerializers[range.length - 1];
        if (term instanceof Range) {
          const writeBound = (bound: Bound<any>) => {
            const tags = { included: 0, excluded: 1, unbounded: 2 };
            writer.writeU8(tags[bound.tag]);
            if (bound.tag !== 'unbounded') serializeTerm(writer, bound.value);
          };
          writeBound(term.from);
          const rstartLen = writer.offset - rstartOffset;

View on GitHub (pinned to 524b4487d9)

Solutions

  1. Limit the argument to at most the index's column count: filter([a, b]) or filter([a, range]) for a 2-column index
  2. Update every filter/delete call site for an index whenever its column list changes
  3. When building arrays dynamically, assert length <= index column count before calling

Example fix

// before (ranged index on [a, b])
const rows = ctx.db.t.idx.filter([a, b, someRange]); // 3 elements > 2 columns

// after: equality on `a`, range over `b`
const rows = ctx.db.t.idx.filter([a, someRange]);
Defensive patterns

Strategy: validation

Validate before calling

// ranged index covering N columns: at most N elements (all but last are equalities)
function assertRangeArity(range: unknown[], numColumns: number): void {
  if (range.length > numColumns) {
    throw new Error(`range has ${range.length} elements but index covers only ${numColumns} columns`);
  }
}

Prevention

When it happens

Trigger: Calling filter([a, b, c]) on a two-column index; passing a full key plus a Range (numColumns + 1 elements); stale queries after a column was dropped from the index definition.

Common situations: Index narrowed from three columns to two without updating range queries; building the filter array dynamically with an off-by-one; assuming extra elements are silently ignored.

Related errors


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