{"record":{"id":"ad654db40e920521","repo":"chroma-core/chroma","slug":"you-do-not-have-permission-to-access-the-requested","errorCode":null,"errorMessage":"You do not have permission to access the requested resource.","messagePattern":"You do not have permission to access the requested resource\\.","errorType":"http","errorClass":"ChromaForbiddenError","httpStatus":403,"severity":"error","filePath":"clients/js/packages/chromadb-core/src/ChromaFetch.ts","lineNumber":69,"sourceCode":"  try {\n    const resp = await fetch(input, init);\n\n    const clonedResp = resp.clone();\n    const respBody = await clonedResp.json();\n    if (!clonedResp.ok) {\n      const error = createErrorByType(respBody?.error, respBody?.message);\n      if (error) {\n        throw error;\n      }\n      switch (resp.status) {\n        case 400:\n          throw new ChromaClientError(\n            `Bad request to ${input} with status: ${resp.statusText}`,\n          );\n        case 401:\n          throw new ChromaUnauthorizedError(`Unauthorized`);\n        case 403:\n          throw new ChromaForbiddenError(\n            `You do not have permission to access the requested resource.`,\n          );\n        case 404:\n          throw new ChromaNotFoundError(\n            `The requested resource could not be found: ${input}`,\n          );\n        case 409:\n          throw new ChromaUniqueError(\"The resource already exists\");\n        case 422:\n          if (\n            respBody?.message &&\n            (respBody?.message.startsWith(\"Quota exceeded\") ||\n              respBody?.message.startsWith(\"Billing limit exceeded\"))\n          ) {\n            throw new ChromaQuotaExceededError(respBody?.message);\n          }\n          break;\n        case 500:","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/clients/js/packages/chromadb-core/src/ChromaFetch.ts#L51-L87","documentation":"_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}.","triggerScenarios":"{\"$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.","commonSituations":"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.","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."],"exampleFix":"// before\naggregate = {\"$min_k\": {\"k\": 3}}        # ValueError: $min_k requires 'keys' field\n\n# after\naggregate = {\"$min_k\": {\"keys\": [\"#score\"], \"k\": 3}}","handlingStrategy":"validation","validationCode":"def agg_has_keys_field(payload: dict) -> bool:\n    op = next(iter(payload))\n    body = payload.get(op, {})\n    return isinstance(body, dict) and \"keys\" in body","typeGuard":"def is_complete_k_aggregate(v: Any) -> TypeGuard[Dict[str, Dict[str, Any]]]:\n    if not (isinstance(v, dict) and len(v) == 1):\n        return False\n    op, body = next(iter(v.items()))\n    return (\n        op in {\"$min_k\", \"$max_k\"}\n        and isinstance(body, dict)\n        and \"keys\" in body\n        and \"k\" in body\n    )","tryCatchPattern":"try:\n    Aggregate.from_dict(agg)\nexcept ValueError as e:\n    if \"requires 'keys' field\" in str(e):\n        op = next(iter(agg))\n        agg[op][\"keys\"] = [\"#score\"]  # or fail loudly with a config error\n    else:\n        raise","preventionTips":["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."],"tags":["chromadb","aggregate","missing-field","valueerror","min-k","max-k"],"backgroundTag":"missing-required-field","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}