fix(rerankers): validate provider result indexes instead of panicking by dudanogueira · Pull Request #13583 · weaviate/weaviate · GitHub
Skip to content

fix(rerankers): validate provider result indexes instead of panicking - #13583

Draft
dudanogueira wants to merge 1 commit into
weaviate:mainfrom
dudanogueira:fix/reranker-result-index-validation
Draft

dudanogueira wants to merge 1 commit into
weaviate:mainfrom
dudanogueira:fix/reranker-result-index-validation

Conversation

@dudanogueira

Copy link
Copy Markdown
Contributor

Motivation

Every API reranker (cohere, voyageai, jinaai, nvidia, contextualai) trusts the result index the provider sends back. toDocumentScores allocated len(results) slots and wrote to documentScores[result.Index] without a bounds check. So whenever a provider returns fewer results than documents, or an unexpected index:

  • Out-of-range index: panics inside the error-group goroutine. The panic is recovered, so the user gets panic occurred: runtime error: index out of range.
  • Fewer results than documents: DocumentScores is shorter than the search results. rank_result.go then indexes result.DocumentScores[i] in the query path, outside any recover.
  • A document with no result while the lengths still match: it silently gets a zero score attached to the wrong object.

Users can trigger this today: reranker-contextualai has a topN class setting, and any topN lower than the number of hits sends back fewer results than documents.

Separately, the NVIDIA 422 error handler repeated Detail[0] for every detail, so only the first validation message was ever shown.

Approach

  • ent.ToDocumentScores (usecases/modulecomponents/ent/rank_result.go): a generic mapper that every API reranker now uses in place of its own copy. Out-of-range and duplicate indexes are errors. Documents without a result are marked with a new DocumentScore.Unscored field. Its zero value means "scored", so producers that always score every document (reranker-transformers, reranker-dummy) need no change.
  • rank_result.go: errors when the number of scores doesn't match the number of results, and drops Unscored objects before sorting. So topN now actually limits the reranked results, instead of crashing. The module pipeline already reassigns the returned slice (toBeExtended = resArray), so a shorter result set is handled downstream.
  • NVIDIA 422: report each detail (Detail[i]).

Key areas for review

  • Behavior change: dropping unscored objects is a product choice. The alternative is to return an error, which would keep contextualai's topN unusable whenever it is below the number of hits.
  • topN with chunking: contextualai still applies topN per chunk of 1000 documents. With more than 1000 hits you can get more than topN results back. That was true before this PR too, and it no longer crashes.

Testing

Each regression test was confirmed to fail on main before the fix:

  • ent.ToDocumentScores table tests: reordering, partial results, no results, zero scores, past-the-end, negative and duplicate indexes.
  • rank provider tests: sorting, dropping unscored objects, all unscored, and too few or too many scores. On main, too few scores panics with index out of range [1] with length 1.
  • Per-module tests for all five rerankers: a top-N style partial response and an out-of-range index, sent through Rank against a mocked server. On main, both return panic occurred: ....
  • NVIDIA: a 422 response with two details reports both. On main, it reported first problem first problem.

go test -race passes for modules/reranker-..., usecases/modulecomponents/additional/..., usecases/modulecomponents/ent and usecases/modules. golangci-lint v2.13.1 is clean.

🤖 Generated with Claude Code

Every API reranker (cohere, voyageai, jinaai, nvidia, contextualai) wrote
scores into a slice sized by the number of results, indexed by the
provider-supplied result index, with no bounds check. When a provider
returned fewer results than documents, e.g. reranker-contextualai with
topN below the number of hits, the rerank either panicked or attached
scores to the wrong objects, and rank_result.go then indexed past the end
of DocumentScores outside any recover.

- Add ent.ToDocumentScores, a shared mapper that rejects out-of-range and
  duplicate indexes and marks documents without a result as Unscored.
- Drop unscored objects from reranked results, so topN limits them.
- Error when a reranker returns a score count that does not match the
  result count, instead of panicking.
- Report every 422 detail from NVIDIA instead of repeating the first.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@orca-security-eu orca-security-eu Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Orca Security Scan Summary

Status Check Issues by priority
Passed Passed Infrastructure as Code high 0   medium 0   low 0   info 0 View in Orca
Passed Passed SAST high 0   medium 0   low 0   info 0 View in Orca
Passed Passed Secrets high 0   medium 0   low 0   info 0 View in Orca
Passed Passed Vulnerabilities high 0   medium 0   low 0   info 0 View in Orca

@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant