{"record":{"id":"0a7819110b704d4a","repo":"chroma-core/chroma","slug":"could-not-serialize-collection-configuration","errorCode":null,"errorMessage":"Could not serialize collection configuration","messagePattern":"Could not serialize collection configuration","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"clients/js/packages/chromadb-core/src/CollectionConfiguration.ts","lineNumber":230,"sourceCode":"  // not necessarily to retrieving/displaying the existing config.\n\n  return {\n    hnsw: hnswConfig,\n    spann: spannConfig,\n    embedding_function: efConfig,\n  };\n}\n\nexport function collectionConfigurationToJsonStr(\n  config: CollectionConfiguration,\n): string {\n  try {\n    const jsonObj = collectionConfigurationToJson(config);\n    return JSON.stringify(jsonObj);\n  } catch (e: any) {\n    if (e instanceof InvalidConfigurationError) throw e;\n    console.error(\"Error serializing collection configuration to JSON:\", e);\n    throw new Error(\"Could not serialize collection configuration\");\n  }\n}\n\n// --- Create Configuration Helpers ---\n\nexport function loadApiCollectionConfigurationFromCreateCollectionConfiguration(\n  config: CreateCollectionConfiguration,\n): Api.CollectionConfiguration {\n  // Cast needed because the generated Api type might not be perfectly aligned\n  // with our internal Create* types, but the structure should match after JSON conversion.\n  return createCollectionConfigurationToJson(\n    config,\n  ) as Api.CollectionConfiguration;\n}\n\n// TODO: make warnings prettier and add link to migration docs\nexport function createCollectionConfigurationToJson(\n  config: CreateCollectionConfiguration,","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/clients/js/packages/chromadb-core/src/CollectionConfiguration.ts#L212-L248","documentation":"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.","triggerScenarios":"{\"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.","commonSituations":"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.","solutions":["If no grouping is wanted, omit group_by or pass {} — never {\"keys\": [], ...}.","Gate payload construction: build group_by only when the field list is non-empty: group_by = {\"keys\": fields, \"aggregate\": agg} if fields else None.","Validate at your API boundary: reject empty group-field lists or convert them to 'no grouping'.","Ensure YAML/JSON templates never materialize keys: [] alongside an aggregate."],"exampleFix":"// before\ngroup_by = {\"keys\": [], \"aggregate\": {\"$min_k\": {\"keys\": [\"#score\"], \"k\": 3}}}\n# ValueError: GroupBy keys cannot be empty\n\n# after\ngroup_by = None   # or {} — both mean no grouping\nsearch = Search(group_by=group_by, ...)","handlingStrategy":"validation","validationCode":"def groupby_keys_nonempty_or_absent(payload: dict) -> bool:\n    return \"keys\" not in payload or (isinstance(payload[\"keys\"], (list, tuple)) and len(payload[\"keys\"]) > 0)","typeGuard":"def is_valid_groupby(v: Any) -> TypeGuard[Dict[str, Any]]:\n    if not isinstance(v, dict):\n        return False\n    if not v:\n        return True\n    ks = v.get(\"keys\")\n    return (\n        isinstance(ks, (list, tuple))\n        and len(ks) > 0\n        and all(isinstance(k, str) for k in ks)\n        and isinstance(v.get(\"aggregate\"), dict)\n        and len(v[\"aggregate\"]) == 1\n    )","tryCatchPattern":"try:\n    GroupBy.from_dict(payload)\nexcept ValueError as e:\n    if \"keys cannot be empty\" in str(e):\n        return None  # reinterpret as no grouping\n    raise","preventionTips":["No grouping = omit group_by or {}; never {'keys': [], ...}.","Builders: emit group_by only when the field list is non-empty (group_by = {...} if fields else None).","Treat empty group-field selections from UIs as 'no grouping', not empty arrays forwarded downstream."],"tags":["chromadb","groupby","empty-list","valueerror"],"backgroundTag":"empty-required-field","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}