chroma-core/chroma · error · InvalidConfigurationError

Cannot specify both 'hnsw' and 'spann' configurations.

Error message

Cannot specify both 'hnsw' and 'spann' configurations.

What it means

Aggregate.from_dict() (operator.py:1428-1429) raises ValueError when the single operator key in an aggregate dict is neither '$min_k' nor '$max_k'. These two strings are the complete operator vocabulary (dispatch at operator.py:1422-1427), so '$top_k', '$avg', '$sort', 'min_k' (missing the $), or any custom name is rejected. The error echoes the offending operator name, making typo-vs-invented-operator immediately distinguishable.

Source

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

      return efBuilder.build_from_config(efConfig.config);
    } catch (e) {
      console.error("Error building embedding function from config:", e);
      return null; // Fallback if build fails
    }
  } else {
    console.warn(
      `Unknown embedding function type or name: ${efConfig.type}, ${efConfig.name}`,
    );
    return null;
  }
}

// TODO: make warnings prettier and add link to migration docs
export function loadCollectionConfigurationFromJson(
  jsonMap: Record<string, any>,
): CollectionConfiguration {
  if (jsonMap.hnsw && jsonMap.spann) {
    throw new InvalidConfigurationError(
      "Cannot specify both 'hnsw' and 'spann' configurations.",
    );
  }
  let hnswConfig: HNSWConfiguration | null | undefined = jsonMap.hnsw; // Assume structure matches HNSWConfiguration
  let spannConfig: SpannConfiguration | null | undefined = jsonMap.spann; // Assume structure matches SpannConfiguration
  let embeddingFunction: IEmbeddingFunction | null | undefined =
    deserializeEmbeddingFunction(jsonMap.embedding_function);

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

export function loadCollectionConfigurationFromJsonStr(
  jsonStr: string,
): CollectionConfiguration {

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Use exactly '$min_k' or '$max_k': {"$min_k": {"keys": ["#score"], "k": 3}} keeps the 3 best per group (min score = most similar).
  2. Check the '$' prefix — 'min_k' without it is an unknown operator.
  3. Do not expect avg/sum/count/sort operators; if you need them, aggregate client-side after the grouped search.
  4. If a payload previously worked, verify the Chroma version — the supported set is defined solely by the from_dict dispatch.

Example fix

// before
aggregate = {"$top_k": {"keys": ["#score"], "k": 3}}
# ValueError: Unknown aggregate operator: $top_k

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

Strategy: validation

Validate before calling

SUPPORTED = {"$min_k", "$max_k"}
def aggregate_op_supported(payload: dict) -> bool:
    return isinstance(payload, dict) and len(payload) == 1 and next(iter(payload)) in SUPPORTED

Type guard

def is_supported_aggregate(v: Any) -> TypeGuard[Dict[str, Dict[str, Any]]]:
    if not (isinstance(v, dict) and len(v) == 1):
        return False
    op = next(iter(v))
    return op in {"$min_k", "$max_k"} and isinstance(v[op], dict)

Try / catch

try:
    Aggregate.from_dict(agg)
except ValueError as e:
    if "Unknown aggregate operator" in str(e):
        raise ValueError(
            "Only '$min_k' and '$max_k' are supported (note the '$' prefix); "
            f"got operator {next(iter(agg))!r}"
        ) from e
    raise

Prevention

When it happens

Trigger: '$top_k' — inventing a name for the familiar concept ('$min_k' on '#score' is Chroma's top-k by relevance, since lower score = better); '$avg'/'$sum' — expecting SQL-style aggregate functions that do not exist; 'min_k' without the '$' prefix; 'MinK' — using the class name; operators from a different Chroma version's vocabulary or a newer spec.

Common situations: Porting SQL/Mongo-style aggregation syntax to Chroma; paraphrasing operator names from memory instead of docs; version drift where a payload written against a richer (perhaps experimental or future) operator set is run on a build supporting only min/max k; LLM- or template-generated payloads with plausible-but-wrong operator names.

Related errors


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