chroma-core/chroma · error · Error

Invalid JSON string for collection configuration

Error message

Invalid JSON string for collection configuration

What it means

GroupBy.from_dict() (operator.py:1514-1515) raises TypeError when the group_by payload is not a dict. GroupBy's dict form is either {} (no grouping) or {"keys": [...], "aggregate": {...}} — the shape emitted by GroupBy.to_dict() (operator.py:1508-1510). A list of field names, a string, or None cannot be decoded, so construction aborts. In the Search constructor (plan.py:123-124) a dict group_by is routed here while a GroupBy instance passes through and anything else fails earlier — so this error typically comes from calling GroupBy.from_dict directly.

Source

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

    deserializeEmbeddingFunction(jsonMap.embedding_function);

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

export function loadCollectionConfigurationFromJsonStr(
  jsonStr: string,
): CollectionConfiguration {
  try {
    const jsonMap = JSON.parse(jsonStr);
    return loadCollectionConfigurationFromJson(jsonMap);
  } catch (e: any) {
    if (e instanceof InvalidConfigurationError) throw e;
    console.error("Error parsing JSON string for collection configuration:", e);
    throw new Error("Invalid JSON string for collection configuration");
  }
}

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") {

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Wrap the fields in the mapping form: {"keys": ["category"], "aggregate": {"$min_k": {"keys": ["#score"], "k": 3}}}.
  2. Use {} (or omit group_by) when no grouping is wanted.
  3. Prefer the typed API for readability: GroupBy(keys=["category"], aggregate=MinK(keys=K.SCORE, k=3)).
  4. json.loads any JSON text before passing it as group_by.

Example fix

// before
search = Search(group_by=["category"])   # rejected earlier by plan.py; direct form:
gb = GroupBy.from_dict(["category"])      # TypeError: Expected dict for GroupBy, got list

# after
gb = GroupBy.from_dict({"keys": ["category"], "aggregate": {"$min_k": {"keys": ["#score"], "k": 3}}})
Defensive patterns

Strategy: type-guard

Validate before calling

def is_groupby_payload(v: Any) -> bool:
    return isinstance(v, dict)

Type guard

def is_groupby_dict(v: Any) -> TypeGuard[Dict[str, Any]]:
    return isinstance(v, dict)

Try / catch

try:
    GroupBy.from_dict(payload)
except TypeError as e:
    raise ValueError(
        f"group_by must be {{}}, or {{'keys': [...], 'aggregate': {{...}}}} — got {payload!r}"
    ) from e

Prevention

When it happens

Trigger: GroupBy.from_dict("category") or GroupBy.from_dict(["category"]) — a bare field or list instead of the wrapped mapping; Search(group_by=["category"]) is caught by plan.py:125-128 with its own message, but Search(group_by={...}-shaped JSON string) reaches json boundary issues; YAML config where the group_by section lost its mapping structure; forwarding a string field name from an API query parameter.

Common situations: Users assuming group_by takes a field name or list like SQL GROUP BY; config files where indentation collapse turned the mapping into a scalar; REST handlers forwarding raw query-param strings into the search payload; replaying Search.to_dict() output in which group_by was stringified.

Understand the failure class

Related errors


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