{"record":{"id":"bc5416a2b15d2a08","repo":"chroma-core/chroma","slug":"bad-request-to-input-with-status-resp-status","errorCode":null,"errorMessage":"Bad request to ${input} with status: ${resp.statusText}","messagePattern":"Bad request to (.+?) with status: (.+?)","errorType":"http","errorClass":"ChromaClientError","httpStatus":400,"severity":"error","filePath":"clients/js/packages/chromadb-core/src/ChromaFetch.ts","lineNumber":63,"sourceCode":" *  It is intended to be passed to the ApiApi constructor.\n */\nexport const chromaFetch: FetchAPI = async (\n  input: RequestInfo | URL,\n  init?: RequestInit,\n): Promise<Response> => {\n  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\") ||","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/clients/js/packages/chromadb-core/src/ChromaFetch.ts#L45-L81","documentation":"Select.from_dict() (operator.py:1315-1319) allows exactly one top-level key, 'keys', in a Select dict; any extra field raises ValueError with the offending key names. The dict form is intentionally minimal ({\"keys\": [...]}) because it mirrors what Select.to_dict() emits (operator.py:1275), so extra entries indicate the caller mixed fields from another part of the Search payload (filter, rank, limit, group_by) into the select object. This strictness catches payload-shape confusion early rather than silently ignoring typos.","triggerScenarios":"Search(select={\"keys\": [\"#document\"], \"limit\": 10}) — a Search-level field nested inside select; {\"keys\": [...], \"k\": 3} — an Aggregate-style field leaking into Select; {\"keys\": [...], \"document\": True} from attempting per-key flags; copy-pasting a GroupBy dict ({\"keys\": ..., \"aggregate\": ...}) as the select argument, which also trips this after the keys pass.","commonSituations":"Flattening a Search.to_dict() blob and feeding a sub-object that still carries sibling fields; hand-authoring request payloads where nested-field boundaries are guessed; merging config snippets that each add a field to the same dict; wrappers that inject metadata (e.g. a version or comment key) into every payload sub-object.","solutions":["Strip the select object down to {\"keys\": [...]} — that is the only accepted shape.","Move misplaced fields to the right level: limit belongs on Search(limit=10) or the limit dict, aggregate belongs inside group_by, not select.","If a wrapper decorates payloads with bookkeeping keys, strip them before decode: payload = {k: v for k, v in payload.items() if k == 'keys'} — but prefer fixing the wrapper so only schema fields travel.","Validate payloads against Select.to_dict()'s output shape before sending: the key set must equal {'keys'}."],"exampleFix":"// before\nselect = {\"keys\": [\"#document\"], \"limit\": 10, \"offset\": 0}\n# ValueError: Unexpected keys in Select dict: {'limit', 'offset'}\n\n# after\nsearch = Search(select={\"keys\": [\"#document\"]}, limit=10)","handlingStrategy":"validation","validationCode":"def select_payload_shape_ok(payload: dict) -> bool:\n    return set(payload.keys()) <= {\"keys\"}","typeGuard":"def is_select_shaped(v: Any) -> TypeGuard[Dict[str, Any]]:\n    return isinstance(v, dict) and set(v.keys()) <= {\"keys\"}","tryCatchPattern":"try:\n    Select.from_dict(payload)\nexcept ValueError as e:\n    if \"Unexpected keys\" in str(e):\n        payload = {k: v for k, v in payload.items() if k == \"keys\"}\n        Select.from_dict(payload)\n    else:\n        raise","preventionTips":["Keep Search-level fields (limit, where, rank) at the Search level, never inside select.","Validate generated payloads against set(payload) == {'keys'} before send.","Do not let wrappers inject version/comment keys into payload sub-objects."],"tags":["chromadb","select","schema","valueerror","payload-shape"],"backgroundTag":"dict-schema-validation-failed","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}