{"record":{"id":"3f38342249e37f8c","repo":"chroma-core/chroma","slug":"found-non-string-ids-at-nonstrings-join","errorCode":null,"errorMessage":"Found non-string IDs at ${nonStrings.join(\", \")}","messagePattern":"Found non-string IDs at (.+?)","errorType":"validation","errorClass":"ChromaValueError","httpStatus":null,"severity":"error","filePath":"clients/new-js/packages/chromadb/src/utils.ts","lineNumber":205,"sourceCode":" */\nexport const validateIDs = (ids: string[]) => {\n  if (!Array.isArray(ids)) {\n    throw new ChromaValueError(\n      `Expected 'ids' to be an array, but got ${typeof ids}`,\n    );\n  }\n\n  if (ids.length === 0) {\n    throw new ChromaValueError(\"Expected 'ids' to be a non-empty list\");\n  }\n\n  const nonStrings = ids\n    .map((id, i) => [id, i] as [any, number])\n    .filter(([id, _]) => typeof id !== \"string\")\n    .map(([_, i]) => i);\n\n  if (nonStrings.length > 0) {\n    throw new ChromaValueError(\n      `Found non-string IDs at ${nonStrings.join(\", \")}`,\n    );\n  }\n\n  const seen = new Set();\n  const duplicates = ids.filter((id) => {\n    if (seen.has(id)) {\n      return id;\n    }\n    seen.add(id);\n  });\n  let message = \"Expected IDs to be unique, but found duplicates of\";\n  if (duplicates.length > 0 && duplicates.length <= 5) {\n    throw new ChromaValueError(`${message} ${duplicates.join(\", \")}`);\n  }\n  if (duplicates.length > 0) {\n    throw new ChromaValueError(\n      `${message} ${duplicates.slice(0, 5).join(\", \")}, ..., ${duplicates","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/clients/new-js/packages/chromadb/src/utils.ts#L187-L223","documentation":"ChromaValueError thrown by validateIDs (utils.ts:203) when some elements of the ids array are not strings. The message lists the indexes of every offending element (not the values), so you can locate them in the original array.","triggerScenarios":"collection.add({ ids: [1, 2, 3], documents }); collection.get({ ids: ['a', 42] }); ids mapped from database numeric primary keys without String() conversion.","commonSituations":"Numeric auto-increment IDs from SQL sources; Object.entries keys (strings) mixed with values; ids parsed from JSON where the field is sometimes a number.","solutions":["Convert all ids to strings at the source: rows.map(r => String(r.id))","Use the reported indices to inspect the exact bad entries before retrying","Enforce id: string in the types of your ingestion pipeline"],"exampleFix":"// before\nawait collection.add({ ids: [1, 2, 3], documents });\n// after\nawait collection.add({ ids: [1, 2, 3].map(String), documents });","handlingStrategy":"type-guard","validationCode":"const nonStringIdx = ids.map((id, i) => [id, i]).filter(([id]) => typeof id !== 'string').map(([, i]) => i);\nif (nonStringIdx.length) throw new TypeError(`Non-string ids at ${nonStringIdx}`);","typeGuard":"function isStringIdArray(v): v is string[] { return Array.isArray(v) && v.every(id => typeof id === 'string'); }","tryCatchPattern":"try { await collection.add({ ids, documents }); } catch (e) { if (e instanceof ChromaValueError && /non-string IDs at/.test(e.message)) ids = ids.map(String); else throw e; }","preventionTips":["Map numeric primary keys through String() at ingestion","Use the indices in the message to inspect the exact bad rows","Type ids as string[] end-to-end"],"tags":["chromadb","validation","ids","type-mismatch"],"backgroundTag":"non-string-ids","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}