{"record":{"id":"81eedd5c4160c5d3","repo":"chroma-core/chroma","slug":"groupby-input-must-be-a-groupby-instance-or-plain","errorCode":null,"errorMessage":"GroupBy input must be a GroupBy instance or plain object","messagePattern":"GroupBy input must be a GroupBy instance or plain object","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"clients/new-js/packages/chromadb/src/execution/expression/groupBy.ts","lineNumber":140,"sourceCode":"      return undefined;\n    }\n    if (input instanceof GroupBy) {\n      return input;\n    }\n    if (isPlainObject(input)) {\n      const data = input as GroupByJSON;\n      if (!data.keys || !Array.isArray(data.keys)) {\n        throw new TypeError(\"GroupBy requires 'keys' array\");\n      }\n      if (!data.aggregate) {\n        throw new TypeError(\"GroupBy requires 'aggregate'\");\n      }\n      return new GroupBy(\n        data.keys.map((k) => new Key(k)),\n        Aggregate.from(data.aggregate),\n      );\n    }\n    throw new TypeError(\n      \"GroupBy input must be a GroupBy instance or plain object\",\n    );\n  }\n\n  public toJSON(): GroupByJSON {\n    return {\n      keys: this.keys.map((key) => key.name),\n      aggregate: this.aggregate.toJSON(),\n    };\n  }\n}\n","sourceCodeStart":122,"sourceCodeEnd":152,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/clients/new-js/packages/chromadb/src/execution/expression/groupBy.ts#L122-L152","documentation":"GroupBy.from() accepts only a GroupBy instance, null/undefined (returns undefined), or a plain object (GroupByJSON). Any other input type — a string, number, boolean, array, or a class instance of another kind — falls through all branches and raises this TypeError.","triggerScenarios":"GroupBy.from(\"category\"); GroupBy.from([\"category\"]); or passing a JSON string like GroupBy.from(JSON.stringify(gb)) that was never parsed. Also passing a custom class instance that isn't GroupBy.","commonSituations":"Forgetting JSON.parse on a group-by payload read from a queue, cache, or database column. Passing an array of keys directly because the keys field is itself an array. Cross-boundary deserialization where class identity (instanceof GroupBy) is lost after structured clone or IPC.","solutions":["Parse JSON payloads first: GroupBy.from(JSON.parse(raw))","Wrap arrays in the full shape: { keys: [...], aggregate: ... }","After IPC/serialization boundaries, rely on the plain-object JSON shape rather than expecting instanceof GroupBy to hold"],"exampleFix":"// before\nconst gb = GroupBy.from(await cache.get(\"groupBy\")); // stored JSON string -> TypeError\n\n// after\nconst raw = await cache.get(\"groupBy\");\nconst gb = GroupBy.from(typeof raw === \"string\" ? JSON.parse(raw) : raw);","handlingStrategy":"type-guard","validationCode":"const parsed = typeof raw === \"string\" ? JSON.parse(raw) : raw;\nif (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n  throw new Error(\"GroupBy input must be a plain object { keys, aggregate }\");\n}\nconst gb = GroupBy.from(parsed);","typeGuard":"import { isPlainObject } from \"./helpers\";\nconst isGroupByInput = (v: unknown): v is Record<string, unknown> =>\n  isPlainObject(v) && Array.isArray((v as { keys?: unknown }).keys) && \"aggregate\" in v;","tryCatchPattern":"try {\n  const gb = GroupBy.from(cached);\n} catch (e) {\n  if (e instanceof TypeError && /GroupBy input/.test(e.message)) {\n    // cached value is corrupt/strings — rebuild from defaults\n  } else throw e;\n}","preventionTips":["JSON.parse stored payloads before GroupBy.from","After IPC/serialization boundaries, pass the plain-object JSON shape, not class instances","Wrap deserialization in one shared helper that also validates shape"],"tags":["chroma","group-by","typeerror"],"backgroundTag":"schema-validation-failed","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}