chroma-core/chroma · error · Error

Could not serialize collection configuration

Error message

Could not serialize collection configuration

What it means

GroupBy.from_dict() (operator.py:1526-1527) raises ValueError when the 'keys' list of a group_by dict is empty. Grouping requires at least one metadata field to partition results on — an empty keys list defines zero grouping dimensions, which is indistinguishable from 'no grouping', and Chroma requires you to say that differently: pass {} (which returns the default GroupBy, operator.py:1514-1515) or omit group_by entirely. The empty-list case is treated as a malformed non-empty payload, not as the no-grouping request.

Source

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

  // not necessarily to retrieving/displaying the existing config.

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

export function collectionConfigurationToJsonStr(
  config: CollectionConfiguration,
): string {
  try {
    const jsonObj = collectionConfigurationToJson(config);
    return JSON.stringify(jsonObj);
  } catch (e: any) {
    if (e instanceof InvalidConfigurationError) throw e;
    console.error("Error serializing collection configuration to JSON:", e);
    throw new Error("Could not serialize collection configuration");
  }
}

// --- Create Configuration Helpers ---

export function loadApiCollectionConfigurationFromCreateCollectionConfiguration(
  config: CreateCollectionConfiguration,
): Api.CollectionConfiguration {
  // Cast needed because the generated Api type might not be perfectly aligned
  // with our internal Create* types, but the structure should match after JSON conversion.
  return createCollectionConfigurationToJson(
    config,
  ) as Api.CollectionConfiguration;
}

// TODO: make warnings prettier and add link to migration docs
export function createCollectionConfigurationToJson(
  config: CreateCollectionConfiguration,

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. If no grouping is wanted, omit group_by or pass {} — never {"keys": [], ...}.
  2. Gate payload construction: build group_by only when the field list is non-empty: group_by = {"keys": fields, "aggregate": agg} if fields else None.
  3. Validate at your API boundary: reject empty group-field lists or convert them to 'no grouping'.
  4. Ensure YAML/JSON templates never materialize keys: [] alongside an aggregate.

Example fix

// before
group_by = {"keys": [], "aggregate": {"$min_k": {"keys": ["#score"], "k": 3}}}
# ValueError: GroupBy keys cannot be empty

# after
group_by = None   # or {} — both mean no grouping
search = Search(group_by=group_by, ...)
Defensive patterns

Strategy: validation

Validate before calling

def groupby_keys_nonempty_or_absent(payload: dict) -> bool:
    return "keys" not in payload or (isinstance(payload["keys"], (list, tuple)) and len(payload["keys"]) > 0)

Type guard

def is_valid_groupby(v: Any) -> TypeGuard[Dict[str, Any]]:
    if not isinstance(v, dict):
        return False
    if not v:
        return True
    ks = v.get("keys")
    return (
        isinstance(ks, (list, tuple))
        and len(ks) > 0
        and all(isinstance(k, str) for k in ks)
        and isinstance(v.get("aggregate"), dict)
        and len(v["aggregate"]) == 1
    )

Try / catch

try:
    GroupBy.from_dict(payload)
except ValueError as e:
    if "keys cannot be empty" in str(e):
        return None  # reinterpret as no grouping
    raise

Prevention

When it happens

Trigger: {"keys": [], "aggregate": {...}} — explicit empty list; a computed field list that evaluated to [] (user supplied no group fields, but the builder still emitted the dict); YAML where all keys entries were commented out; template merging that stripped every grouping field yet kept aggregate.

Common situations: APIs that accept a list of group fields and build group_by unconditionally — emitting {"keys": [], "aggregate": ...} for empty input instead of {}; optional config sections that default to empty lists; frontends sending empty arrays for unset multi-select controls.

Related errors


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