{"record":{"id":"87b3008372aad34e","repo":"weaviate/weaviate","slug":"sparse-search-w","errorCode":null,"errorMessage":"sparse search: %w","messagePattern":"sparse search: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"usecases/traverser/hybrid/searcher.go","lineNumber":211,"sourceCode":"\t\t\treturn nil, fmt.Errorf(\"hybrid search selection: %w\", err)\n\t\t}\n\t}\n\tif postProc != nil {\n\t\tsr, err := postProc(fused)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"hybrid search post-processing: %w\", err)\n\t\t}\n\t\tfused = sr\n\t}\n\tif params.SelectionFn == nil && params.Autocut > 0 {\n\t\tfused = performAutocut(fused, params.Autocut)\n\t}\n\treturn fused, nil\n}\n\nfunc processSparseSearch(results []*storobj.Object, scores []float32, err error) ([]*search.Result, error) {\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"sparse search: %w\", err)\n\t}\n\n\tout := make([]*search.Result, len(results))\n\tfor i, obj := range results {\n\t\tsr := obj.SearchResultWithScore(additional.Properties{}, scores[i])\n\t\tsr.SecondarySortValue = sr.Score\n\t\tout[i] = &sr\n\t}\n\treturn out, nil\n}\n\nfunc processDenseSearch(ctx context.Context,\n\tdenseSearch denseSearchFunc, params *Params, modules modulesProvider,\n\tschemaGetter uc.SchemaGetter, targetVectorParamHelper targetVectorParamHelper,\n) ([]*search.Result, error) {\n\tquery := params.Query\n\tvector := params.Vector\n\tif params.HybridSearch.NearTextParams != nil {","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/weaviate/weaviate/blob/75aa4b6d11f8818305aafd4440b4e32794f7ca04/usecases/traverser/hybrid/searcher.go#L193-L229","documentation":"Wraps any error returned by the sparse (BM25 keyword) leg of hybrid search. processSparseSearch receives results, scores, and an error from the inverted-index search; if err is non-nil it is wrapped here and the whole hybrid query aborts. The sparse leg never ran to completion, so no fusion happens.","triggerScenarios":"BM25/inverted index lookup failure during hybrid search: corrupted or missing inverted index, shard unavailable/read-only, stopword/lexicon processing errors, or a timeout in the underlying keyword search.","commonSituations":"Shard replication issues after node failure; disk problems corrupting LSM inverted-index buckets; querying a collection while a rebalance/restore is in progress.","solutions":["Read the wrapped root cause in server logs — it identifies the actual sparse-search failure.","Check shard health (`/v1/nodes`) and confirm all shards of the collection are reachable and not read-only.","If an index looks corrupted, restore from backup or reindex the collection.","Retry the query; transient replication or timeout errors may self-heal."],"exampleFix":"// check cluster shard status before retrying\ncurl http://localhost:8080/v1/nodes | jq '.[] | .shards[] | select(.status != \"READY\")'\n// after: repair or reassign unhealthy shards, then re-run the hybrid query","handlingStrategy":"retry","validationCode":"// health check before query\nconst nodes = await fetch(\"http://localhost:8080/v1/nodes\").then(r => r.json());\nconst unhealthy = nodes.flatMap(n => n.shards).filter(s => s.status !== \"READY\");\nif (unhealthy.length) throw new Error(\"shards not ready: \" + unhealthy.map(s => s.name));","typeGuard":null,"tryCatchPattern":"try {\n  return await hybridQuery();\n} catch (e) {\n  if (String(e).includes(\"sparse search\")) {\n    await sleep(backoff); // transient shard/replication errors may self-heal\n    return await hybridQuery();\n  }\n  throw e;\n}","preventionTips":["Monitor shard health via /v1/nodes.","Maintain backups; reindex or restore on inverted-index corruption.","Avoid querying during restores/rebalances."],"tags":["hybrid-search","bm25","sparse-search","storage"],"backgroundTag":"sparse-search-failed","analyzedSha":"75aa4b6d11f8818305aafd4440b4e32794f7ca04","analyzedAt":"2026-09-04T14:58:20.392Z","contentChangedAt":"2026-09-04T14:58:20.392Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}