Skip to content

Fix Range<Score> lower bound handling in vector search queries. - #4310

Open
masiljangajji wants to merge 2 commits into
spring-projects:mainfrom
masiljangajji:fix/vector-range-bound-check
Open

masiljangajji wants to merge 2 commits into
spring-projects:mainfrom
masiljangajji:fix/vector-range-bound-check

Conversation

@masiljangajji

@masiljangajji masiljangajji commented Aug 7, 2026

Copy link
Copy Markdown
  • You have read the Spring Data contribution guidelines.
  • You use the code formatters provided here and have them applied to your changes. Don’t submit any formatting related changes.
  • You submit test cases (unit or integration tests) that back your changes.
  • You added yourself as author in the headers of the classes you touched. Amend the date range in the Apache license header if needed. For new types, add the license header (copy from another file and set the current year only).

What

JpaQueryCreator's WITHIN/NEAR vector-search predicate builder and JpaParametersParameterAccessor.doWithScore() both mishandle a Range<Score> that only has a lower bound set (e.g. Range.rightUnbounded(...), a natural way to express "similarity >= X"). This affects the currently released 4.0.x and 4.1.0 lines, not just main.

Why

Both are the same class of mistake, introduced in the same commit (17a59905a7, "Explore returning Search Results."): getUpperBound() is called where getLowerBound() was clearly intended.

In JpaQueryCreator, the guard range.getUpperBound().isBounded() || range.getUpperBound().isBounded() checks the same (upper) bound twice, so a lower-bound-only range never enters the predicate-building branch and falls through to InvalidDataAccessApiUsageException("Near/Within keywords must be used with a Score or Range<Score> type") — even though a valid Range<Score> was supplied.

In JpaParametersParameterAccessor.doWithScore(), the branch that matches on the lower bound reads the value back via getUpperBound().getValue().get() instead of getLowerBound().getValue().get(), throwing NoSuchElementException for the same input before JpaQueryCreator even gets a chance to build a predicate.

Ranges with only an upper bound set happen to work today, since that is the bound both call sites actually inspect.

Fix

  • JpaQueryCreator.java: check getLowerBound().isBounded() instead of checking getUpperBound().isBounded() twice.
  • JpaParametersParameterAccessor.java: read the lower-bound branch's value from getLowerBound() instead of getUpperBound().
  • Added two tests to JpaQueryCreatorTests exercising a lower-bound-only and an upper-bound-only Range<Score> query end to end (JPQL rendering); this scenario had no test coverage anywhere in the module before this change.

mp911de and others added 2 commits August 5, 2026 16:11
JpaQueryCreator's WITHIN/NEAR keyword handling checked range.getUpperBound().isBounded() twice instead of checking both the lower and the upper bound, so a Range<Score> with only a lower bound set (e.g. Range.rightUnbounded(...)) skipped predicate generation entirely and fell through to "Near/Within keywords must be used with a Score or Range<Score> type", even though a valid Range<Score> had in fact been supplied. Ranges with only an upper bound set happened to work by accident, since that is the bound the condition was actually checking.

JpaParametersParameterAccessor.doWithScore() had the same lower/upper mix-up: the branch that matches on the lower bound read the value back from getUpperBound() instead of getLowerBound(), throwing NoSuchElementException for any lower-bound-only range before JpaQueryCreator even gets to build a predicate. Both defects were introduced in the same commit, 17a5990 ("Explore returning Search Results.").

Added two characterization tests to JpaQueryCreatorTests covering lower-bound-only and upper-bound-only Range<Score> queries; neither had any test coverage anywhere in the module before this change.

Signed-off-by: masiljangajji <xmfpdlsj0508@gmail.com>
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Aug 7, 2026
@masiljangajji masiljangajji changed the title Fix inverted lower/upper bound checks in vector Range<Score> queries. Hotfix: Fix bug where Range<Score> lower bound is ignored in vector search queries. Aug 7, 2026
@masiljangajji masiljangajji changed the title Hotfix: Fix bug where Range<Score> lower bound is ignored in vector search queries. Fix Range<Score> lower bound handling in vector search queries. Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: waiting-for-triage An issue we've not yet triaged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants