chroma-core/chroma · error · TypeError

GroupBy input must be a GroupBy instance or plain object

Error message

GroupBy input must be a GroupBy instance or plain object

What it means

GroupBy.from() accepts only a GroupBy instance, null/undefined (returns undefined), or a plain object (GroupByJSON). Any other input type — a string, number, boolean, array, or a class instance of another kind — falls through all branches and raises this TypeError.

Source

Thrown at clients/new-js/packages/chromadb/src/execution/expression/groupBy.ts:140

      return undefined;
    }
    if (input instanceof GroupBy) {
      return input;
    }
    if (isPlainObject(input)) {
      const data = input as GroupByJSON;
      if (!data.keys || !Array.isArray(data.keys)) {
        throw new TypeError("GroupBy requires 'keys' array");
      }
      if (!data.aggregate) {
        throw new TypeError("GroupBy requires 'aggregate'");
      }
      return new GroupBy(
        data.keys.map((k) => new Key(k)),
        Aggregate.from(data.aggregate),
      );
    }
    throw new TypeError(
      "GroupBy input must be a GroupBy instance or plain object",
    );
  }

  public toJSON(): GroupByJSON {
    return {
      keys: this.keys.map((key) => key.name),
      aggregate: this.aggregate.toJSON(),
    };
  }
}

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Parse JSON payloads first: GroupBy.from(JSON.parse(raw))
  2. Wrap arrays in the full shape: { keys: [...], aggregate: ... }
  3. After IPC/serialization boundaries, rely on the plain-object JSON shape rather than expecting instanceof GroupBy to hold

Example fix

// before
const gb = GroupBy.from(await cache.get("groupBy")); // stored JSON string -> TypeError

// after
const raw = await cache.get("groupBy");
const gb = GroupBy.from(typeof raw === "string" ? JSON.parse(raw) : raw);
Defensive patterns

Strategy: type-guard

Validate before calling

const parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
  throw new Error("GroupBy input must be a plain object { keys, aggregate }");
}
const gb = GroupBy.from(parsed);

Type guard

import { isPlainObject } from "./helpers";
const isGroupByInput = (v: unknown): v is Record<string, unknown> =>
  isPlainObject(v) && Array.isArray((v as { keys?: unknown }).keys) && "aggregate" in v;

Try / catch

try {
  const gb = GroupBy.from(cached);
} catch (e) {
  if (e instanceof TypeError && /GroupBy input/.test(e.message)) {
    // cached value is corrupt/strings — rebuild from defaults
  } else throw e;
}

Prevention

When it happens

Trigger: GroupBy.from("category"); GroupBy.from(["category"]); or passing a JSON string like GroupBy.from(JSON.stringify(gb)) that was never parsed. Also passing a custom class instance that isn't GroupBy.

Common situations: Forgetting JSON.parse on a group-by payload read from a queue, cache, or database column. Passing an array of keys directly because the keys field is itself an array. Cross-boundary deserialization where class identity (instanceof GroupBy) is lost after structured clone or IPC.

Related errors


AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16). Data as JSON: /api/errors/81eedd5c4160c5d3. Report an issue: GitHub.