chroma-core/chroma · error · Error

Invalid HNSW config provided

Error message

Invalid HNSW config provided

What it means

GroupBy.from_dict() (operator.py:1520-1521) raises ValueError when a non-empty group_by dict lacks the 'aggregate' field. Chroma's grouping is always grouping-plus-aggregation: 'keys' partitions rows and 'aggregate' (a '$min_k'/'$max_k' expression) decides which k rows each group contributes — there is no 'just group everything' mode, so a keys-only dict is incomplete and rejected. The check order is keys first (operator.py:1518), so this error means 'keys' was present but 'aggregate' was not; chromadb/test/test_api.py:3219 pins this behavior.

Source

Thrown at clients/js/packages/chromadb-core/src/CollectionConfiguration.ts:205

  }
}

export function collectionConfigurationToJson(
  config: CollectionConfiguration,
): Record<string, any> {
  if (config.hnsw && config.spann) {
    throw new InvalidConfigurationError(
      "Cannot specify both 'hnsw' and 'spann' configurations.",
    );
  }
  let hnswConfig = config.hnsw;
  let spannConfig = config.spann;
  let ef = config.embedding_function;
  let efConfig = serializeEmbeddingFunction(ef);

  // Basic validation/casting attempt (already done in create/update, but maybe check types?)
  if (hnswConfig && typeof hnswConfig !== "object") {
    throw new Error("Invalid HNSW config provided");
  }
  if (spannConfig && typeof spannConfig !== "object") {
    throw new Error("Invalid SPANN config provided");
  }

  // Note: Validation (like validateCreateHnswConfig) is tied to creation/update actions
  // not necessarily to retrieving/displaying the existing config.

  return {
    hnsw: hnswConfig,
    spann: spannConfig,
    embedding_function: efConfig,
  };
}

export function collectionConfigurationToJsonStr(
  config: CollectionConfiguration,
): string {

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Add the aggregate, most commonly top-1 per group: {"keys": ["category"], "aggregate": {"$min_k": {"keys": ["#score"], "k": 1}}}.
  2. Use the exact field name 'aggregate' holding a single-operator dict ($min_k/$max_k).
  3. For 'best n per group' semantics use $min_k on ["#score"] with k=n (lower Chroma score = more similar).
  4. If you actually want all rows ungrouped, omit group_by entirely — there is no group-without-aggregate mode.

Example fix

// before
group_by = {"keys": ["category"]}
# ValueError: GroupBy requires 'aggregate' field

# after
group_by = {"keys": ["category"], "aggregate": {"$min_k": {"keys": ["#score"], "k": 1}}}
Defensive patterns

Strategy: validation

Validate before calling

def groupby_has_aggregate(payload: dict) -> bool:
    return len(payload) == 0 or ("keys" in payload and "aggregate" in payload)

Type guard

def is_complete_groupby(v: Any) -> TypeGuard[Dict[str, Any]]:
    if not isinstance(v, dict) or not v:
        return isinstance(v, dict)
    return (
        set(v.keys()) == {"keys", "aggregate"}
        and isinstance(v["keys"], (list, tuple))
        and len(v["keys"]) > 0
        and isinstance(v["aggregate"], dict)
    )

Try / catch

try:
    GroupBy.from_dict(payload)
except ValueError as e:
    if "requires 'aggregate' field" in str(e):
        raise ValueError("Grouping always pairs with an aggregation; add e.g. "
                         "'aggregate': {'$min_k': {'keys': ['#score'], 'k': 1}}") from e
    raise

Prevention

When it happens

Trigger: GroupBy.from_dict({"keys": ["category"]}) — SQL-style GROUP BY with no reduction; authors who want one representative row per group but omit the top-1 spec; 'aggregate' spelled differently ('agg', 'aggregation') in config; builders that omit aggregate when a default was assumed.

Common situations: Porting SQL GROUP BY mental models where aggregates are optional; assuming a default of '$min_k on #score, k=1'; config systems abbreviating field names; payloads assembled from partial templates.

Related errors


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