chroma-core/chroma · error · ChromaForbiddenError
You do not have permission to access the requested resource.
Error message
You do not have permission to access the requested resource.
What it means
_parse_k_aggregate() (operator.py:1358-1359) raises ValueError when the inner dict of a '$min_k'/'$max_k' aggregation has no 'keys' field. 'keys' tells the aggregation which record fields to rank within each group — typically ["#score"] or a metadata field like ["priority", "#score"] for tiebreaking — so an aggregation without it is unexecutable and is rejected before MinK/MaxK are constructed (operator.py:1422-1427). The required inner shape is exactly {"keys": [...], "k": n}.
Source
Thrown at clients/js/packages/chromadb-core/src/ChromaFetch.ts:69
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);
}
break;
case 500:View on GitHub (pinned to aecdd12c8a)
Solutions
- Add the required field: {"$min_k": {"keys": ["#score"], "k": 3}} — most often keys is ["#score"].
- Spell the field exactly 'keys'; synonyms like 'key', 'fields', 'on' are not accepted.
- For multi-criteria ranking pass multiple entries in order: {"keys": ["priority", "#score"], "k": 5}.
- If generating payloads from code, build them from a typed MinK(...).to_dict() so field names can never drift.
Example fix
// before
aggregate = {"$min_k": {"k": 3}} # ValueError: $min_k requires 'keys' field
# after
aggregate = {"$min_k": {"keys": ["#score"], "k": 3}} Defensive patterns
Strategy: validation
Validate before calling
def agg_has_keys_field(payload: dict) -> bool:
op = next(iter(payload))
body = payload.get(op, {})
return isinstance(body, dict) and "keys" in body Type guard
def is_complete_k_aggregate(v: Any) -> TypeGuard[Dict[str, Dict[str, Any]]]:
if not (isinstance(v, dict) and len(v) == 1):
return False
op, body = next(iter(v.items()))
return (
op in {"$min_k", "$max_k"}
and isinstance(body, dict)
and "keys" in body
and "k" in body
) Try / catch
try:
Aggregate.from_dict(agg)
except ValueError as e:
if "requires 'keys' field" in str(e):
op = next(iter(agg))
agg[op]["keys"] = ["#score"] # or fail loudly with a config error
else:
raise Prevention
- Both 'keys' and 'k' are mandatory in every $min_k/$max_k body — no defaults exist.
- Copy the canonical body {'keys': ['#score'], 'k': n} and edit values only.
- Generate payloads from MinK(...).to_dict() so field names cannot drift.
When it happens
Trigger: {"$min_k": {"k": 3}} — only k supplied; field renamed in config ('key', 'fields', 'by') instead of the required 'keys'); JSON payload built programmatically that skips keys when a default was intended; partial merge of config templates that dropped the keys entry.
Common situations: Config authors assuming keys defaults to '#score'; renaming payload fields for house style without updating the consumer; YAML stripped of the keys line by a bad edit or templating conditional; versions of a wrapper that emit only k and rely on server defaults that Chroma does not have.
Related errors
- The requested resource could not be found: ${input}
- ${respBody?.message}
- Failed to fetch ${input} with status ${resp.status}: ${resp.
- You must provide either queryEmbeddings or queryTexts
- Cannot specify both 'hnsw' and 'spann' configurations.
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/ad654db40e920521.
Report an issue: GitHub.