matchhighlight PassageSelector sizes its passage queue by maxPassages before it looks at any match, so maxPassages = Integer.MAX_VALUE ('all passages') throws IllegalArgumentException and a large maxPassages allocates maxPassages + 1 queue slots per call, even for a text with two matches

Finding LFV-1005Area: highlighter / matchhighlight passage selection (PassageSelector.pickBest passage-queue sizing; used by MatchHighlighter through FieldValueHighlighters.highlighted, which passes maxPassages through unchecked)Priority: lowImpact: wrong errorNovelty: new

Finding page for LFV-1005

AI-assisted finding, confirmed by automated checks, not yet triaged by a human Lucene committer. This site files nothing upstream.

What it shows

You call PassageSelector.pickBest on a short text with two matches (or MatchHighlighter with FieldValueHighlighters.highlighted) and pass maxPassages = Integer.MAX_VALUE to mean 'all passages', and you expect the same two passages that maxPassages = 10 returns, because maxPassages only caps the result (the method clamps its result to it) and there can never be more passages than matches. Instead pickBest builds its priority queue with Math.max(16, maxPassages) slots before it reads any match, so the call throws IllegalArgumentException 'maxSize must be >= 0 and < 2147483631; got: 2147483647'. A smaller but still large maxPassages succeeds and allocates memory in proportion to maxPassages rather than to the matches: about 64 MiB per call at 2^24.

The test shows that matchhighlight PassageSelector.pickBest sizes its priority queue by maxPassages before reading any match, so maxPassages = Integer.MAX_VALUE ("all passages") fails.

Expected vs actual

Expected: the one passage around the single match in "lucene search"; actual (-ea and -da): IllegalArgumentException: maxSize must be >= 0 and < 2147483631; got: 2147483647 from PriorityQueue.<init> via PassageSelector.pickBest:96.

Files

Run it

# Lucene checkout at the tested commit, built with: ./gradlew --no-daemon assemble   (JDK 25)
LUCENE=/path/to/lucene; V=12.0.0-SNAPSHOT
CP=$LUCENE/lucene/core/build/libs/lucene-core-$V.jar
CP=$CP:$LUCENE/lucene/codecs/build/libs/lucene-codecs-$V.jar
CP=$CP:$LUCENE/lucene/test-framework/build/libs/lucene-test-framework-$V.jar
CP=$CP:$LUCENE/lucene/highlighter/build/libs/lucene-highlighter-$V.jar
CP=$CP:$LUCENE/lucene/memory/build/libs/lucene-memory-$V.jar
CP=$CP:$LUCENE/lucene/queries/build/libs/lucene-queries-$V.jar
CP=$CP:randomizedtesting-runner-2.9.2.jar:junit-4.13.2.jar:hamcrest-3.0.jar   # test-framework dependencies (Maven Central)
CP=$CP:junit-platform-console-standalone-6.1.3.jar   # JUnit Platform console launcher (Maven Central)

javac -d classes -cp "$CP" $(find src -name '*.java')

# run 1: assertions on, seed DEADBEEF
java -ea -esa --add-modules jdk.incubator.vector --enable-native-access=ALL-UNNAMED -Dtests.seed=DEADBEEF \
     -cp "classes:$CP" org.junit.platform.console.ConsoleLauncher \
     execute --select-class org.apache.lucene.search.matchhighlight.TestPassageSelectorMaxValueMaxPassages

Gradle alternative: copy the test into the matching module's src/test/ tree of the checkout and run ./gradlew -p lucene/<module> test --tests <class> -Ptests.seed=<seed> (add -Ptests.asserts=false for a run without assertions).

Feedback

Open an issue in lucene-ai-bug-hunt. Please do not open issues or pull requests in apache/lucene about this finding unless a Lucene committer agrees it should be filed.

Snapshot of 2026-11-04. AI-assisted; not yet triaged by a human Lucene committer. Feedback: open an issue in lucene-ai-bug-hunt.