chroma-core/chroma · error · TypeError

Aggregate input must be an Aggregate instance or object with

Error message

Aggregate input must be an Aggregate instance or object with $min_k or $max_k

What it means

Aggregate.from() converts user input into a GroupBy aggregate (MinK or MaxK). It only accepts an Aggregate instance or a plain object in the serialized JSON shape { $min_k: { keys, k } } or { $max_k: { keys, k } }. Any other value — a bare object without the $min_k/$max_k envelope, a string, number, or array — raises this TypeError before the query is built.

Source

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

      return input;
    }
    if (isPlainObject(input)) {
      if ("$min_k" in input) {
        const data = input.$min_k as MinKJSON;
        return new MinK(
          data.keys.map((k) => new Key(k)),
          data.k,
        );
      }
      if ("$max_k" in input) {
        const data = input.$max_k as MaxKJSON;
        return new MaxK(
          data.keys.map((k) => new Key(k)),
          data.k,
        );
      }
    }
    throw new TypeError(
      "Aggregate input must be an Aggregate instance or object with $min_k or $max_k",
    );
  }

  public static minK(keys: (Key | string)[], k: number): MinK {
    return new MinK(
      keys.map((key) => (key instanceof Key ? key : new Key(key))),
      k,
    );
  }

  public static maxK(keys: (Key | string)[], k: number): MaxK {
    return new MaxK(
      keys.map((key) => (key instanceof Key ? key : new Key(key))),
      k,
    );
  }
}

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Build aggregates with the static helpers Aggregate.minK(keys, k) or Aggregate.maxK(keys, k) instead of raw objects
  2. If you must write raw JSON, wrap it correctly: { $min_k: { keys: ["score"], k: 5 } }
  3. When deserializing persisted queries, validate that aggregate has a $min_k or $max_k key before calling GroupBy.from

Example fix

// before
GroupBy.from({
  keys: ["category"],
  aggregate: { keys: ["score"], k: 5 }, // missing $min_k wrapper -> TypeError
});

// after
GroupBy.from({
  keys: ["category"],
  aggregate: Aggregate.minK(["score"], 5), // or { $min_k: { keys: ["score"], k: 5 } }
});
Defensive patterns

Strategy: type-guard

Validate before calling

const isAggregateShape = (v: unknown): boolean =>
  v instanceof Aggregate ||
  (typeof v === "object" &&
    v !== null &&
    ("$min_k" in v || "$max_k" in v));

if (!isAggregateShape(input.aggregate)) {
  throw new Error("aggregate must be Aggregate.minK/maxK(...) or { $min_k | $max_k: { keys, k } }");
}
const gb = GroupBy.from(input as GroupByJSON);

Type guard

function isAggregateJSON(v: unknown): v is { $min_k: { keys: string[]; k: number } } | { $max_k: { keys: string[]; k: number } } {
  if (typeof v !== "object" || v === null) return false;
  const o = v as Record<string, unknown>;
  const inner = (o.$min_k ?? o.$max_k) as { keys?: unknown; k?: unknown } | undefined;
  return !!inner && Array.isArray(inner.keys) && typeof inner.k === "number";
}

Try / catch

try {
  const gb = GroupBy.from(queryJson);
} catch (e) {
  if (e instanceof TypeError && /Aggregate input/.test(e.message)) {
    // rebuild aggregate with Aggregate.minK/maxK helpers instead of raw JSON
  } else throw e;
}

Prevention

When it happens

Trigger: GroupBy.from({ keys: ["category"], aggregate: { keys: ["score"], k: 5 } }) — aggregate object missing the $min_k/$max_k wrapper. Passing a non-Aggregate class instance or a JSON blob whose aggregate shape drifted (e.g. restored from persistence or received from another service).

Common situations: Hand-writing the aggregate JSON and forgetting the $min_k/$max_k envelope; round-tripping serialized GroupBy JSON after a schema change; copying the GroupByJSON type's outer shape but nesting the keys/k directly under aggregate.

Related errors


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