{"record":{"id":"8532d1b0cb14a796","repo":"chroma-core/chroma","slug":"cannot-specify-both-hnsw-and-spann-configurati-8532d1","errorCode":null,"errorMessage":"Cannot specify both 'hnsw' and 'spann' configurations during creation.","messagePattern":"Cannot specify both 'hnsw' and 'spann' configurations during creation\\.","errorType":"validation","errorClass":"InvalidConfigurationError","httpStatus":null,"severity":"error","filePath":"clients/js/packages/chromadb-core/src/CollectionConfiguration.ts","lineNumber":251,"sourceCode":"\n// --- Create Configuration Helpers ---\n\nexport function loadApiCollectionConfigurationFromCreateCollectionConfiguration(\n  config: CreateCollectionConfiguration,\n): Api.CollectionConfiguration {\n  // Cast needed because the generated Api type might not be perfectly aligned\n  // with our internal Create* types, but the structure should match after JSON conversion.\n  return createCollectionConfigurationToJson(\n    config,\n  ) as Api.CollectionConfiguration;\n}\n\n// TODO: make warnings prettier and add link to migration docs\nexport function createCollectionConfigurationToJson(\n  config: CreateCollectionConfiguration,\n): Record<string, any> {\n  if (config.hnsw && config.spann) {\n    throw new InvalidConfigurationError(\n      \"Cannot specify both 'hnsw' and 'spann' configurations during creation.\",\n    );\n  }\n  let hnswConfig = config.hnsw;\n  let spannConfig = config.spann;\n  let ef = config.embedding_function;\n  let efConfig = serializeEmbeddingFunction(ef);\n\n  // Basic validation/casting attempt\n  if (hnswConfig && typeof hnswConfig !== \"object\") {\n    throw new Error(\n      \"Invalid HNSW config provided in CreateCollectionConfiguration\",\n    );\n  }\n  if (spannConfig && typeof spannConfig !== \"object\") {\n    throw new Error(\n      \"Invalid SPANN config provided in CreateCollectionConfiguration\",\n    );","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/clients/js/packages/chromadb-core/src/CollectionConfiguration.ts#L233-L269","documentation":"Thrown by createCollectionConfigurationToJson (CollectionConfiguration.ts) when a CreateCollectionConfiguration passed to client.createCollection / getOrCreateCollection contains BOTH a truthy hnsw block and a truthy spann block. Chroma builds exactly one ANN index per collection at creation time, so specifying both HNSW and SPANN parameters is contradictory and is rejected client-side before any request is sent. It throws InvalidConfigurationError, a plain Error subclass exported from the same module.","triggerScenarios":"client.createCollection({ name: 'x', configuration: { hnsw: { space: 'cosine' }, spann: { search_nprobe: 10 } } }); the same applies to getOrCreateCollection and any other path that serializes a CreateCollectionConfiguration via createCollectionConfigurationToJson.","commonSituations":"Copy-pasting SPANN examples on top of an existing HNSW config while migrating; building the configuration object dynamically (Object.assign / spread of two partial configs) so both keys end up defined; toggling an experimental SPANN flag without removing the old hnsw block.","solutions":["Delete either the hnsw or the spann key so the configuration contains only one index block.","If migrating HNSW to SPANN, create a fresh collection with only the spann block and re-add data - index type is chosen at creation and cannot be switched by passing both.","When building configuration dynamically, assert !cfg.hnsw || !cfg.spann before calling createCollection so you fail fast with your own error message."],"exampleFix":"// before\nawait client.createCollection({\n  name: 'docs',\n  configuration: { hnsw: { space: 'cosine' }, spann: { search_nprobe: 10 } },\n});\n\n// after\nawait client.createCollection({\n  name: 'docs',\n  configuration: { spann: { search_nprobe: 10 } },\n});","handlingStrategy":"validation","validationCode":"function assertSingleIndexConfig(cfg: CreateCollectionConfiguration) {\n  if (cfg.hnsw && cfg.spann) {\n    throw new Error(\n      `Pick one index type: hnsw=${JSON.stringify(cfg.hnsw)} spann=${JSON.stringify(cfg.spann)}`,\n    );\n  }\n}\n// before client.createCollection / getOrCreateCollection:\nassertSingleIndexConfig(configuration);","typeGuard":"function hasSingleIndexConfig(\n  cfg: CreateCollectionConfiguration,\n): cfg is CreateCollectionConfiguration & { hnsw?: CreateHNSWConfiguration } {\n  return !(cfg.hnsw && cfg.spann);\n}","tryCatchPattern":"try {\n  await client.createCollection({ name, configuration });\n} catch (e) {\n  if (e instanceof InvalidConfigurationError && /hnsw.*spann|spann.*hnsw/.test(e.message)) {\n    // fix the config, exactly one index block allowed at creation\n  }\n  throw e;\n}","preventionTips":["Type configuration payloads as CreateCollectionConfiguration so extra keys stand out in review.","Build index config in one factory function that returns either { hnsw } or { spann }, never both.","Write a unit test asserting your config builder never emits both blocks."],"tags":["configuration","validation","hnsw","spann","index","collection-creation"],"backgroundTag":"conflicting-config-options","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}