chroma-core/chroma · error · ChromaUnauthorizedError

Unauthorized

Error message

Unauthorized

What it means

_parse_k_aggregate() (operator.py:1355-1357) requires the value under the '$min_k' or '$max_k' operator key to be a dict describing the aggregation, e.g. {"$min_k": {"keys": ["#score"], "k": 3}}. If that value is a list, number, string, or None, the aggregation parameters cannot be extracted and a TypeError naming the operator is raised. This fires inside Aggregate.from_dict after it has already verified the outer dict holds exactly one recognized operator key (operator.py:1415-1427).

Source

Thrown at clients/js/packages/chromadb-core/src/ChromaFetch.ts:67

  init?: RequestInit,
): Promise<Response> => {
  try {
    const resp = await fetch(input, init);

    const clonedResp = resp.clone();
    const respBody = await clonedResp.json();
    if (!clonedResp.ok) {
      const error = createErrorByType(respBody?.error, respBody?.message);
      if (error) {
        throw error;
      }
      switch (resp.status) {
        case 400:
          throw new ChromaClientError(
            `Bad request to ${input} with status: ${resp.statusText}`,
          );
        case 401:
          throw new ChromaUnauthorizedError(`Unauthorized`);
        case 403:
          throw new ChromaForbiddenError(
            `You do not have permission to access the requested resource.`,
          );
        case 404:
          throw new ChromaNotFoundError(
            `The requested resource could not be found: ${input}`,
          );
        case 409:
          throw new ChromaUniqueError("The resource already exists");
        case 422:
          if (
            respBody?.message &&
            (respBody?.message.startsWith("Quota exceeded") ||
              respBody?.message.startsWith("Billing limit exceeded"))
          ) {
            throw new ChromaQuotaExceededError(respBody?.message);
          }

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Wrap the operator's arguments in an inner dict with named fields: {"$min_k": {"keys": ["#score"], "k": 3}}.
  2. Keep 'keys' a list even for one key: {"keys": ["#score"]}, and 'k' an int.
  3. Prefer constructing typed objects when in doubt: GroupBy(keys=["category"], aggregate=MinK(keys=K.SCORE, k=3)) — dicts are only the serialized form.
  4. Lint nested YAML/JSON aggregations: the operator key's value must be an object, never a scalar/array.

Example fix

// before
aggregate = {"$min_k": ["#score", 3]}   # TypeError: $min_k requires a dict, got list

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

Strategy: type-guard

Validate before calling

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

Type guard

def is_k_aggregate_payload(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 TypeError as e:
    if "requires a dict" in str(e):
        op = next(iter(agg))
        agg = {op: agg[op] if isinstance(agg[op], dict) else {"keys": ["#score"], "k": 3}}
    else:
        raise

Prevention

When it happens

Trigger: GroupBy aggregate written as {"$min_k": ["#score", 3]} — a positional list instead of a field dict; {"$min_k": 3} — only the k value supplied; {"$max_k": null} in JSON/YAML config; {"$min_k": "#score"} — collapsing keys into a scalar because there is a single key.

Common situations: Authors abbreviating single-key aggregations and dropping the inner braces; YAML configs losing the nested mapping when re-indented; JSON built with jq/pydantic where the aggregation body was flattened; migrating from a shorthand API (MinK(keys=K.SCORE, k=3)) to dict payloads and assuming arguments map positionally.

Understand the failure class

Related errors


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