{"record":{"id":"850a81906f95dc41","repo":"chroma-core/chroma","slug":"invalid-spann-config-provided","errorCode":null,"errorMessage":"Invalid SPANN config provided","messagePattern":"Invalid SPANN config provided","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"clients/js/packages/chromadb-core/src/CollectionConfiguration.ts","lineNumber":208,"sourceCode":"export function collectionConfigurationToJson(\n  config: CollectionConfiguration,\n): Record<string, any> {\n  if (config.hnsw && config.spann) {\n    throw new InvalidConfigurationError(\n      \"Cannot specify both 'hnsw' and 'spann' configurations.\",\n    );\n  }\n  let hnswConfig = config.hnsw;\n  let spannConfig = config.spann;\n  let ef = config.embedding_function;\n  let efConfig = serializeEmbeddingFunction(ef);\n\n  // Basic validation/casting attempt (already done in create/update, but maybe check types?)\n  if (hnswConfig && typeof hnswConfig !== \"object\") {\n    throw new Error(\"Invalid HNSW config provided\");\n  }\n  if (spannConfig && typeof spannConfig !== \"object\") {\n    throw new Error(\"Invalid SPANN config provided\");\n  }\n\n  // Note: Validation (like validateCreateHnswConfig) is tied to creation/update actions\n  // 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);","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/clients/js/packages/chromadb-core/src/CollectionConfiguration.ts#L190-L226","documentation":"GroupBy.from_dict() (operator.py:1523-1525) requires the 'keys' field of a group_by dict to be a list or tuple, and raises TypeError for anything else. The keys name the metadata fields whose values define group membership (e.g. [\"category\"] or [\"author\", \"genre\"]) and are run through _strings_to_keys for iteration (operator.py:1533, operator.py:1334-1336), so a scalar string, dict, or None cannot be interpreted. Note this parser is stricter than Select.from_dict, which also accepts sets (operator.py:1289) — order matters for grouping precedence, so a set is not allowed here.","triggerScenarios":"{\"keys\": \"category\"} — single field not wrapped in a list; {\"keys\": {\"0\": \"category\"}} — object form from JSON; {\"keys\": null} — explicit null survives because the presence check ('keys' not in data) passed; forwarding a Python set from a Select payload as group_by keys.","commonSituations":"Single-field grouping written without brackets (the most common shape, hence the most common mistake); config loaders emitting objects instead of arrays; single-element arrays collapsed to scalars by intermediate serialization; reusing select-style key collections (sets) that this stricter parser refuses.","solutions":["Wrap in a list: {\"keys\": [\"category\"], \"aggregate\": {...}}.","Convert sets before embedding: {\"keys\": sorted(group_fields)} — sorted() also makes multi-field grouping deterministic.","Ensure each element is a string naming a real metadata field on your records.","Avoid explicit null; omit the field only if you also omit aggregate (then use {} for no grouping)."],"exampleFix":"// before\ngroup_by = {\"keys\": \"category\", \"aggregate\": {\"$min_k\": {\"keys\": [\"#score\"], \"k\": 1}}}\n# TypeError: GroupBy keys must be a list, got str\n\n# after\ngroup_by = {\"keys\": [\"category\"], \"aggregate\": {\"$min_k\": {\"keys\": [\"#score\"], \"k\": 1}}}","handlingStrategy":"type-guard","validationCode":"def groupby_keys_is_list(payload: dict) -> bool:\n    ks = payload.get(\"keys\")\n    return ks is None or isinstance(ks, (list, tuple))","typeGuard":"def has_list_keys(v: Any) -> TypeGuard[Dict[str, Any]]:\n    return isinstance(v, dict) and isinstance(v.get(\"keys\"), (list, tuple))","tryCatchPattern":"try:\n    GroupBy.from_dict(payload)\nexcept TypeError as e:\n    if \"keys must be a list\" in str(e):\n        ks = payload[\"keys\"]\n        payload[\"keys\"] = [ks] if isinstance(ks, str) else list(ks)\n    else:\n        raise","preventionTips":["Bracket single group fields: ['category'], not 'category'.","list/tuple only here — a set is accepted by Select.from_dict but not GroupBy.from_dict.","Convert sets explicitly: sorted(field_set) (also fixes nondeterministic multi-field order)."],"tags":["chromadb","groupby","keys","typeerror"],"backgroundTag":"dict-schema-validation-failed","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}