Repro tests
One directory per public finding: the minimal repro sources, what they show, and how to run them against a Lucene checkout. Rows withheld pending security review have no repro here. See also the formal models and scripts and the table as data (CSV, JSON).
| Finding | Area | Priority | Title | Files |
|---|---|---|---|---|
| LFV-001 | index / IndexWriter NRT | high | openIfChanged returns null and isCurrent() stays true after a flush when the only changes are doc-values updates | 1 |
| LFV-016 | index / doc-values updates | high | deleteDocuments(Query) on a doc-values field is evaluated against stale values when doc-values updates are pending | 1 |
| LFV-044 | codecs / doc values | high | Doc-values range queries with a skip index return wrong hits when a segment's values span more than Long.MAX_VALUE | 2 |
| LFV-222 | join / block join (ToParentBlockJoinQuery.BlockJoinBulkScorer) x search / BooleanQuery MUST_NOT bulk scoring (ReqExclBulkScorer, #16669) | high | A MUST_NOT clause next to a scoring ToParentBlockJoinQuery is checked against child documents instead of parents, so excluded parents are returned, and the search throws when a parent/child block straddles a 4096-doc window | 1 |
| LFV-106 | search / vector similarity queries and the query cache | high | Vector similarity queries report isCacheable() == true although their per-segment result depends on live docs, the search timeout and the filter, so a shared query cache serves one reader's or one search's result to another | 1 |
| LFV-038 | search / multi-term queries | high | Doc-values-rewritten multi-term queries are invisible to QueryVisitor, so they escape the nested clause limit and the query-cache RAM budget | 1 |
| LFV-011 | index / IndexWriter merge | high | With index sorting and a parent field, deleting only a block's parent makes every later merge fail | 1 |
| LFV-005 | search / HNSW | high | HNSW merge-time graph reuse can leave the entry node with no neighbours, dropping kNN recall to zero | 1 |
| LFV-811 | codecs / HNSW vectors on the 10.x line (merge-time graph reuse: InitializedHnswGraphBuilder, MergingHnswGraphBuilder, ConcurrentHnswMerger; Lucene99HnswVectorsWriter .vem metadata) | high | On 10.5.1, 10.5.2 and branch_10_6 (the 10.6.0 RC1 revision), an HNSW merge that reuses a graph written with a different maxConn either fails and closes the IndexWriter (maxConn raised) or commits a segment that no kNN query can search (maxConn lowered) | 1 |
| LFV-158 | analysis / StandardTokenizer and the other JFlex-generated scanners (zzRefill in both Lucene JFlex skeletons) | medium | StandardAnalyzer and the other JFlex-generated scanners (StandardTokenizer, UAX29URLEmailTokenizer, ClassicTokenizer, WikipediaTokenizer, HTMLStripCharFilter) silently index no tokens for a text value that ends in an unpaired high surrogate, such as a string cut inside an emoji; values longer than the scan buffer lose or split their last buffer window | 1 |
| LFV-146 | index / FieldInfos and segment metadata strings (DataOutput#writeString in .fnm, segments_N and .si) | medium | Two field names that differ only in an unpaired surrogate are written to disk as the same U+FFFD name, so IndexWriter commits an index that DirectoryReader and a new IndexWriter refuse to open (on main also colliding field attribute keys and commit user-data keys) | 2 |
| LFV-904 | core / index write path (delete-by-query: FrozenBufferedUpdates.applyQueryDeletes) x core / search and queries (reader-dependent rewrites) | medium | IndexWriter.deleteDocuments(Query) and updateDocuments(Query, ...) rewrite the query separately on each segment, so reader-dependent queries (kNN, the default FuzzyQuery and other top-N term rewrites, CommonTermsQuery, MoreLikeThisQuery, score ranges) delete a set that depends on the segment layout and differs from what IndexSearcher.search returns | 1 |
| LFV-1045 | index / IndexWriter full flush (DocumentsWriterFlushControl.nextPendingFlush) | medium | updateDocument racing commit() can leave two live documents for one key (a lost delete) and operations above the sequence number commit() returned in the commit point, because DocumentsWriterFlushControl.nextPendingFlush flushes a DWPT of the new delete queue during the running full flush | 1 |
| LFV-118 | index / IndexingChain per-field schema validation (frozen-FieldType cache) | medium | The frozen-FieldType validation cache (#15886) keys a field on its first value's type, so for a field built from several field types a later document skips the per-field schema check (or is checked against stale state after a rejected addBatch), depending on value order, flushes and earlier operations | 1 |
| LFV-009 | index / doc-values updates | medium | tryUpdateDocValue is overwritten by an earlier, still-buffered doc-values update | 1 |
| LFV-901 | core / index write path (delete-by-query: FrozenBufferedUpdates.applyQueryDeletes over the ReadersAndUpdates pooled reader) x core / search kNN queries | medium | IndexWriter.deleteDocuments with a kNN query runs on the writer's pooled segment reader, whose live docs miss the writer's own earlier deletes, and on the whole flushed segment including documents added later, so the query picks its k nearest among documents already deleted or added after the call and the acknowledged delete removes fewer documents than it should, often none (since 9.0.0) | 1 |
| LFV-643 | index / IndexWriter doc-values updates (BinaryDocValuesUpdate, DocumentsWriterDeleteQueue slices, FieldUpdatesBuffer) | medium | IndexWriter.updateBinaryDocValue and updateDocValues(Term, BinaryDocValuesField) keep the caller's BytesRef without copying it, so documents still buffered in RAM get the bytes that BytesRef holds at the writer's next document or flush instead of the value passed to the call (every release since 4.8.0) | 1 |
| LFV-1046 | index / IndexWriter buffered delete terms (DocumentsWriterDeleteQueue.DeleteSlice.apply, BufferedUpdates.DeletedTerms) | medium | A deleteDocuments or updateDocument(s) call with a term over 32,766 bytes is rejected but stays in IndexWriter's shared delete queue, so every later add and delete and the next commit, NRT reopen or close() fail until rollback() (regression in 9.9.0; up to 9.8.0 such a delete was a no-op) | 1 |
| LFV-045 | search / concurrency | medium | IndexSearcher#count hangs forever when Weight#count throws, for example on a query timeout, on a segment split into intra-segment partitions | 1 |
| LFV-596 | index / IndexWriter frozen update packets vs. merge carry-over (forceApply, commitMergedDeletesAndUpdates, BufferedUpdatesStream) | medium | IndexWriter.forceApply marks a re-resolving update packet finished outside the IndexWriter lock when its re-iteration matches no segment, so a merge that commits in that gap skips the packet's already-resolved doc-values updates and nobody applies them again: an acknowledged updateNumericDocValue/updateDocValues is lost and softUpdateDocument leaves two live versions of the document, also after commit (since 7.0.0) | 2 |
| LFV-002 | index / IndexWriter merge | medium | Merge doc-values carry-over (#16570) can lose an acknowledged update or close the writer on a duplicate delGen | 1 |
| LFV-451 | index / soft deletes (tryUpdateDocValue un-delete vs. a running merge's carry-over) | medium | An un-delete through IndexWriter#tryUpdateDocValue during a merge of the document's segment returns success and is visible to NRT readers, but the merge commit silently drops the document | 1 |
| LFV-110 | index / IndexWriter doc-values update write path (ReadersAndUpdates.writeFieldUpdates, the checkpoint after writeReaderPool, IndexFileDeleter reference counts) | medium | An IOException late in a doc-values update write leaves IndexWriter open but inconsistent: published update files are never checkpointed and get deleted while still referenced, and a failed pooled-reader re-open silently drops the update | 2 |
| LFV-473 | index / DocumentsWriter full flush (DocumentsWriterFlushControl.abortFullFlushes, blockedFlushes) and the error paths of IndexWriter.getReader and prepareCommit | medium | A non-tragic exception during an NRT reopen or commit full flush aborts the DWPTs other threads filled during that flush, silently losing acknowledged documents and updates while the writer stays open | 1 |
| LFV-1078 | index / DocumentsWriter flush failure handling (DocumentsWriter.doFlush, DocumentsWriterPerThread.prepareFlush, DocumentsWriterDeleteQueue.freezeGlobalBuffer) | medium | An exception inside DocumentsWriterPerThread.prepareFlush is not tragic: IndexWriter stays open but drops the in-memory segment and the deletes and doc-values updates it had just frozen, so the next successful commit lacks acknowledged operations its sequence number covers | 1 |
| LFV-843 | index / IndexWriter full flush (DocumentsWriter.flushAllThreads naked-delete freeze, DocumentsWriterDeleteQueue.close) | medium | An Error (in practice an OutOfMemoryError) while an NRT reopen or commit that has no buffered documents freezes the buffered deletes and doc-values updates is replaced by IllegalStateException("Can't close queue unless all changes are applied") from the finally of DocumentsWriter.flushAllThreads, so IndexWriter stays open instead of closing itself and its next commit silently drops those acknowledged deletes and updates (with -ea an AssertionError replaces the Error; every release since 8.2.0) | 3 |
| LFV-195 | search / phrase queries (ExactPhraseMatcher maxFreq and merged impacts, PhraseScorer TOP_SCORES pruning) | medium | Exact PhraseQuery/MultiPhraseQuery: when the first query term occurs twice at one document position, the phrase freq exceeds the maxFreq()/impacts bound, so Scorer#getMaxScore is below score() and TOP_SCORES search drops the best hit | 1 |
| LFV-319 | queryparser / classic MultiFieldQueryParser (getFieldQuery(String,String,boolean) per-field clause grouping and getMultiTermPositionQuery; core util/QueryBuilder graph phrases) | medium | MultiFieldQueryParser under AND treats clause i of every field's analyzed BooleanQuery as term position i and requires each group, so fields whose analyzers tokenize the same text differently lose (and sometimes gain wrong) matches (released since 6.2.0, default settings since 7.0.0), and since #16446 (10.6.0) graph-phrase alternatives such as a multi-word synonym are required together | 1 |
| LFV-1136 | core document / LatLon distance sort (LatLonPointDistanceComparator.setBottom: sampled competitive bounding box) | medium | LatLon distance sort used as a later Sort key drops closer tied hits after 1024 bottom updates, because LatLonPointDistanceComparator keeps a stale bounding box when the bottom grows (every release since 6.1.0) | 1 |
| LFV-242 | suggest / document (NRT) suggester (NRTSuggester.getMaxTopNSearcherQueueSize via SuggestIndexSearcher and CompletionQuery; Util.TopNSearcher queue depth) | medium | NRTSuggester returns too few or wrongly ranked suggestions in a segment with only a few deleted documents, because its deleted-document queue slack (long)(topN / liveDocsRatio) rounds back down to topN | 1 |
| LFV-225 | analysis / Thai (ThaiTokenizer#incrementWord skip loop; ThaiAnalyzer and the 'thai' tokenizer SPI) | medium | ThaiTokenizer and ThaiAnalyzer silently drop a number written directly after a period, '#' or currency sign (2567 in 'พ.ศ.2567', 1,500 in 'ราคา ฿1,500', 42 in 'page.42'), because a word segment is skipped whole when its first character is not a letter or digit | 1 |
| LFV-305 | queryparser / classic QueryParser and MultiFieldQueryParser phrase slop (QueryParserBase.getFieldQuery(String,String,int), MultiFieldQueryParser.getFieldQuery and applySlop; core util/QueryBuilder graph and boosted phrases) | medium | Classic QueryParser and MultiFieldQueryParser ignore an explicit phrase slop ("..."~N) when the phrase analyzes to a token graph (multi-word synonyms, WordDelimiterGraphFilter) or, for QueryParser, carries token boosts, and search with the default phraseSlop instead: fewer hits with the default slop 0, extra hits for an explicit ~0 when a larger default slop is set | 2 |
| LFV-1099 | analysis / synonyms (SynonymGraphFilter position increments) | medium | SynonymGraphFilter drops the position hole (for example a stop word removed before it) in front of a token that starts a synonym match, so the replacement moves one position back (known: #10028 / LUCENE-8985) (released) | 1 |
| LFV-358 | facet / DrillSideways (sequential DrillSidewaysScorer, drill-down-advance strategy, two-phase drill-down dimensions) | medium | Sequential DrillSideways skips the two-phase matches() check of the second-cheapest drill-down dimension on segments without deletions, so documents that fail that dimension but are in its approximation are returned as drill-down hits and counted in the facets (released since 5.3.0) | 1 |
| LFV-789 | facet / DrillSideways (sequential query-first scoring: score mode of the base weight and the scorable handed to the hit collector) | medium | Sequential DrillSideways lets a TOP_SCORES hit collector prune the shared base query, so drill-sideways facet counts silently miss matching documents | 2 |
| LFV-019 | util / automaton | medium | RegExp no longer parses an escaped range start such as [\.-z] as a range | 1 |
| LFV-204 | document / geo shape fields (ShapeField triangle encoding; LatLonShape and XYShape CONTAINS queries) | medium | ShapeField.encodeTriangle puts the wrong edge flag on the first edge when it flips a clockwise triangle, so LatLonShape and XYShape CONTAINS queries return wrong hits | 1 |
| LFV-698 | geo / shape queries (Polygon2D intersectsLine/intersectsTriangle; LatLonShape and XYShape INTERSECTS and DISJOINT with a query polygon that has holes) | medium | Polygon2D.intersectsLine/intersectsTriangle never test the query polygon's hole edges, so LatLonShape/XYShape INTERSECTS misses, and DISJOINT matches, a line or polygon whose vertices all lie in holes but which crosses the polygon between them | 1 |
| LFV-1128 | core / geo (Circle2D haversine segment test behind LatLonShape.newDistanceQuery) | medium | LatLonShape circle (distance) queries miss lines and polygons whose edge crosses the circle with no vertex inside, because Circle2D tests only the edge point closest to the centre in raw lon/lat degrees, not the point closest by haversine distance (DISJOINT matches them instead) | 1 |
| LFV-291 | queries / intervals (Intervals.notContainedBy: NotContainedByIntervalsSource disjunction rewrite, LUCENE-8477) | medium | Intervals.notContainedBy(small, or(B1, B2)) returns small intervals that lie inside B1 or B2, because the default disjunction rewrite turns it into an OR of per-clause filters | 1 |
| LFV-287 | queries / intervals (NotContainingIntervalsSource, Intervals.notContaining) | medium | Intervals.notContaining drops minuend intervals that a subtrahend interval overlaps on the right edge or encloses, though they contain no subtrahend interval | 1 |
| LFV-457 | queries / intervals (Intervals.analyzedText: IntervalBuilder.analyzeGraph; flexible StandardQueryParser fn: interval functions) | medium | Intervals.analyzedText keeps only the first of the tokens stacked at a position whenever the analyzed text is a token graph (a multi-word synonym or a WordDelimiterGraphFilter catenation elsewhere in the text), so interval queries silently miss documents, even documents with exactly the query words (AssertionError under -ea) | 1 |
| LFV-286 | queries / intervals (Intervals.atLeast: MinimumShouldMatchIntervalsSource) | medium | Intervals.atLeast stops early when the sub-iterator it just used runs out, so it loses minimal intervals and misses documents when nested; the same hand-over also lets a stale sub-iterator re-enter and return a non-minimal interval out of order | 1 |
| LFV-627 | core / search (NGramPhraseQuery rewrite), on n-gram fields built with analysis-common (NGramTokenizer, CJKAnalyzer / CJKBigramFilter) | medium | NGramPhraseQuery matches documents its own PhraseQuery does not whenever adjacent gram positions do not come from adjacent text: multi-valued n-gram fields with a position increment gap below n (Lucene's default gap is 0), CJKAnalyzer text with a break between CJK runs (punctuation, a digit, a Latin word or a stop word), and NGramTokenizer pre-tokenizing through isTokenChar | 1 |
| LFV-220 | join / ToParentBlockJoinSortField nested sort (ToParentDocValues missing-child count, #15727) | medium | ToParentBlockJoinSortField treats a parent as having a missing child value whenever its block holds any document outside childFilter, even if every document has the sort field (regression in 10.5.0) | 1 |
| LFV-232 | grouping / two-pass grouping (TopGroupsCollector second pass, TopGroups.merge, TopGroupsCollectorManager, GroupingSearch) | medium | Grouping with a within-group sort that equals Sort.RELEVANCE but is a different object (new Sort(), new Sort(SortField.FIELD_SCORE)) returns the wrong documents per group when results from slices or shards are merged, and since 10.5.0 a NaN GroupDocs.maxScore | 1 |
| LFV-660 | suggest / document suggester (NRTSuggester skipDuplicates, queue sizing) and util / FST (Util.TopNSearcher) | medium | Document suggester with skipDuplicates=true and an index-time synonym returns fewer than n distinct suggestions (n=2 drops one that n=3 returns), because Util.TopNSearcher drops its queue before the last result although acceptPartialPath can still reject that path, and NRTSuggester sizes the queue from entries per analyzed form, which ignores synonym graph paths | 3 |
| LFV-691 | suggest / document (NRT) suggester (RegexCompletionQuery automaton intersected with the NRTSuggester FST, including the internal END and dedup bytes; also inside ContextQuery) | medium | RegexCompletionQuery lets '.' and negated character classes match the document suggester's internal end byte (0x00), so a suggestion one character shorter than the pattern is returned ('foo.' returns foo as well as food, 'foo..' returns food) | 1 |
| LFV-700 | suggest / analyzing: BlendedInfixSuggester result collection | medium | BlendedInfixSuggester loses a distinct suggestion when a duplicate entry arrives while its result set is full: boundedTreeAdd evicts the lowest result before TreeSet.add rejects the duplicate, so lookup returns num-1 suggestions, or a lower-ranked fetched suggestion in place of a higher-ranked one | 1 |
| LFV-254 | suggest / document (NRT) suggester (ContextQuery: ContextCompletionWeight.setNextMatch boost lookup over ContextSuggestField contexts) | medium | ContextQuery gives an exact context's boost to any longer indexed context that starts with it (exact 'red' boosts a suggestion indexed under 'redwood') when that longer context is matched through a shorter prefix context or addAllContexts(), so document-suggester hits get wrong scores and a wrong order | 1 |
| LFV-087 | search / rescoring | medium | RescoreTopNQuery lets deleted documents take top-n slots, and IndexSearcher#count counts them | 1 |
| LFV-315 | search / rescoring | medium | RescoreTopNQuery builds its inner Weight with ScoreMode.COMPLETE_NO_SCORES, so a values source that needs scores (DoubleValuesSource.SCORES, an expression using _score) reads 0 instead of the inner query's score | 1 |
| LFV-1015 | search / rescoring (RescoreTopNQuery scores, consumed by MaxScoreBulkScorer dynamic pruning) | medium | RescoreTopNQuery passes negative DoubleValuesSource values through as negative scores, so a top-k BooleanQuery that ORs it with another clause silently returns no hits | 1 |
| LFV-1016 | search / top-k dynamic pruning (ScorerUtil.minRequiredScore, called by MaxScoreBulkScorer) | medium | ScorerUtil.minRequiredScore (new in 10.3.0, #14827) never terminates when the remaining clauses' max score is negative at a minimum competitive score of 0, so with assertions disabled a top-k BooleanQuery with a negative-scoring SHOULD clause spins forever in MaxScoreBulkScorer, the infinite loop that LUCENE-10428 had turned into an exception | 1 |
| LFV-1048 | join / block join iterator (ParentsChildrenBlockJoinQuery advance() and Weight#explain; reached through ConjunctionDISI, sorted-search competitive iterators and IndexSearcher.explain) | medium | ParentsChildrenBlockJoinQuery: advance() does not count the matching children it skips, so conjunctions, sorted searches and explain return children beyond childLimitPerParent | 1 |
| LFV-424 | search / rescoring (SortRescorer; expressions ExpressionRescorer inherits rescore()) | medium | SortRescorer and ExpressionRescorer give returned hits another hit's first-pass score when topN is smaller than the number of first-pass hits (AssertionError with -ea) | 1 |
| LFV-582 | search / IndexSearcher#termStats distributed-statistics hook (SynonymQuery, MultiPhraseQuery, CombinedFieldQuery, SpanWeight) | medium | SynonymQuery, MultiPhraseQuery, CombinedFieldQuery and SpanOrQuery ask IndexSearcher#termStats only about terms that occur in the local reader, so an override that supplies distributed (whole-collection) statistics is never asked about a query term that occurs only on other shards, and documents on those shards score differently than in the whole collection (since 8.3.0, LUCENE-8921) | 1 |
| LFV-190 | search / similarities and top-k bulk scoring (IndriDirichletSimilarity, TermQuery bulk scorer, BatchScoreBulkScorer) | medium | IndriDirichletSimilarity produces negative scores, and since 10.3.0 a top-k TermQuery search under it silently returns no hits, because BatchScoreBulkScorer passes a hit to the collector only if its score is at least the initial minimum competitive score of 0 | 1 |
| LFV-484 | search / BlendedTermQuery cross-field statistics blending | medium | Cross-field BlendedTermQuery gives a sparse field's term a docFreq above that field's docCount, so matches score negative (and since 10.3 are dropped from top-k), and a field with no indexed terms makes search throw NullPointerException | 1 |
| LFV-413 | misc / similarities (SweetSpotSimilarity) with core impacts-based TOP_SCORES pruning | medium | SweetSpotSimilarity with a length plateau (setLengthNormFactors with min >= 2) breaks Similarity's norm-monotonicity contract, so default top-k search silently misses the best hits | 1 |
| LFV-253 | search / CombinedFieldQuery (BM25F) max-score bound under dynamic pruning (CombinedFieldScorer.getMaxScore as used by MaxScoreBulkScorer) | medium | CombinedFieldQuery computes its max score as score(+Infinity, 1), which is NaN under AxiomaticF2LOG/F2EXP, so top-k pruning silently drops the best hits | 1 |
| LFV-874 | search / IndriAndQuery (IndriDisjunctionScorer iteration over two-phase clauses) | medium | IndriAndQuery returns documents that match none of its clauses when a clause uses two-phase iteration (PhraseQuery, doc-values range queries), because IndriDisjunctionScorer iterates the clauses' approximations and never calls TwoPhaseIterator.matches() | 1 |
| LFV-173 | search / score fusion (LogOddsFusionQuery: LogOddsFusionWeight#scorerSupplier) | medium | LogOddsFusionQuery returns the raw clause score in segments where only one clause has a scorer, so identical documents score differently depending on their segment and explain() disagrees with the score | 1 |
| LFV-443 | search / score fusion (LogOddsFusionQuery: LogOddsFusionScorer#score with per-signal logit bounds and null weights) | medium | LogOddsFusionQuery with logit bounds but no weights normalizes every clause's logit with the first clause's bounds, so scores disagree with explain() and can exceed getMaxScore() | 1 |
| LFV-322 | monitor / presearcher (RegexpQueryHandler custom query handler) | medium | Monitor with RegexpQueryHandler silently misses matching RegexpQuery queries, because the handler indexes each one under a fragment of its pattern text (for example 'cat|dog', 'colou' or '?mail') that matching terms do not contain | 1 |
| LFV-347 | monitor / presearcher (RegexpQueryHandler document-side ngram filter SuffixingNGramTokenFilter) | medium | Monitor with RegexpQueryHandler silently misses regexp matches on any short token that contains a supplementary character (an emoji, a CJK Extension B ideograph, a Gothic or Adlam letter), because SuffixingNGramTokenFilter emits no ngrams for that token | 1 |
| LFV-1115 | monitor / persistent query index (WritableQueryIndex, ReadonlyQueryIndex, QueryDecomposer) | medium | A persistent Monitor query index written before 10.3.0 keeps missing matches after an upgrade to 10.3.0 or later, until every query is registered again (the #14886 fix covers only indexes written from 10.3.0 on) | 1 |
| LFV-772 | monitor / query index updates versus matching (WritableQueryIndex.commitWithoutNotify versus search, reached through Monitor.register and Monitor.match) | medium | Monitor.match running while Monitor.register re-registers the same query id can silently miss that query, because register puts the new version's cache entries into the live cache map before the new index documents are committed and the query index searcher is refreshed | 1 |
| LFV-817 | search / intra-segment concurrency (index / TermStates lazy per-leaf lookup) | medium | TermStates#get hands a lazily looked-up TermState to the other partitions of the same segment without safe publication, so under intra-segment concurrency a partition can read docFreq or file pointers still at 0 and a non-scoring term or phrase query silently misses matches (executed on aarch64) | 2 |
| LFV-556 | queries / mlt (MoreLikeThisQuery.rewrite over MoreLikeThis.like(String, Reader...)) x queryparser / xml (LikeThisQueryBuilder) | medium | MoreLikeThisQuery ignores its moreLikeFields and searches only fieldName, so the XML parser's <LikeThisQuery fieldNames="a,b"> searches only the first field (documents similar through the other fields are silently missed, every release since 6.1.0) | 1 |
| LFV-241 | replicator / NRT segment replication (CopyJob.transferAndCancel, ReplicaNode.newNRTPoint) | medium | After a primary change, an NRT replica keeps a file it already copied from the old primary when the new primary's file has the same name, matching by name only, so the replica serves and commits the wrong documents with CheckIndex clean | 1 |
| LFV-145 | index / index sorting at merge time (IndexSorter.FloatSorter/DoubleSorter merge keys, MultiSorter) -> search / TopFieldCollector index-sort early termination | medium | Merging segments of an index sorted by a FLOAT or DOUBLE field misplaces a NaN whose sign bit is set, so the merged segment violates its declared index sort (CheckIndex at level 2 or higher reports it) and sorted searches that terminate early on the index sort return wrong top hits | 1 |
| LFV-086 | search / FieldExistsQuery count | medium | FieldExistsQuery#count undercounts documents whose norms-free text field analyzes to no tokens but still has a doc value, so IndexSearcher#count is too low | 1 |
| LFV-008 | index / soft deletes | medium | Removing a document's soft-delete value brings a hard-deleted document back | 1 |
| LFV-593 | index / IndexWriter construction from a near-real-time reader (ReaderPool pre-enrollment, PendingSoftDeletes reader constructor, soft-deletes accounting) | medium | With a soft-deletes field configured, an IndexWriter opened from a near-real-time reader's IndexCommit (IndexWriterConfig#setIndexCommit) counts the reader's deletions again, so its next commit can drop a segment that still has live documents, write a commit that cannot be opened, or turn a soft delete into a hard delete (since 7.4.0) | 1 |
| LFV-1062 | index / IndexWriter opened from a reader's IndexCommit (ReaderPool pre-enrollment) with a leaf-sorted reader (DirectoryReader leaf sorter, IndexWriterConfig#setLeafSorter) | medium | An IndexWriter opened from a leaf-sorted reader's IndexCommit pairs each segment with the segment reader at the same leaf position, so deleteDocuments(term) deletes another segment's documents and the commit persists that silently | 1 |
| LFV-006 | util / BKD points | medium | PointInSetQuery silently misses most matches on selectively indexed points (fewer index dimensions than data dimensions) | 1 |
| LFV-475 | search / points queries (PointInSetQuery segment early exit) | medium | Multi-dimensional PointInSetQuery skips segments that contain matching points, because its segment early exit uses the lexicographically first and last set points as per-dimension bounds | 1 |
| LFV-144 | search / sorting (NumericComparator doc-values-skipper pruning for FLOAT/DOUBLE) | medium | A FLOAT or DOUBLE sort on a NUMERIC doc-values field with a skip index and no points silently returns wrong or missing top hits when values have the sign bit set (negative values, or -0.0 with a tie-break sort): skipper pruning compares sortable-encoded bounds with the raw IEEE-bit block min/max | 1 |
| LFV-1047 | search / doc-values range queries, index-sort shortcut (SortedNumericDocValuesRangeQuery.canUsePrimarySortShortcut, SortedSkipperScorerSupplier) | medium | Doc-values exact and range queries silently miss or add documents on a skip-indexed field that holds raw float/double bits and that the index is sorted by as FLOAT or DOUBLE: SortedNumericDocValuesRangeQuery's index-sort shortcut checks the sort field's name but not its type | 1 |
| LFV-1049 | search / IndexSortSortedNumericDocValuesRangeQuery (index-sort range shortcut: INT sort comparator path and 4-byte points path) | medium | IndexSortSortedNumericDocValuesRangeQuery casts its long bounds to int on an INT index sort, so Long.MIN_VALUE / Long.MAX_VALUE open ends (or any bound outside the int range) silently return wrong hits and counts | 1 |
| LFV-751 | document / point query factories (BinaryPoint, PointRangeQuery) | medium | BinaryPoint.newExactQuery and the one-dimensional newRangeQuery keep the caller's byte[] as the query bounds (BinaryPoint.pack returns the caller's array for one dimension), while the same factory packs a private copy for two or more dimensions, so a caller that refills its buffer silently changes queries it already built | 1 |
| LFV-115 | search / IndexSearcher timeout reporting for vector queries (AbstractKnnVectorQuery rewrite, AbstractVectorSimilarityQuery scorerSupplier) | medium | kNN and vector-similarity searches that hit the IndexSearcher timeout before collecting any hit return 0 hits with IndexSearcher.timedOut() == false, so the timed-out search looks like a search without matches | 2 |
| LFV-235 | index / FilterCodecReader reader lifecycle (IndexReader reference counting) | medium | Closing a FilterCodecReader runs the wrapped reader's close hook directly (in.doClose() instead of in.close()), so a DirectoryReader that still uses that segment silently finds 0 hits, and its own close later releases the segment a second time and throws | 1 |
| LFV-490 | search / FieldExistsQuery and index / FieldInfos field-schema consistency on Lucene-8-created indexes (SegmentInfos per-segment open gate, #14607) | medium | Since 10.4.0 Lucene opens indexes created by Lucene 8 once Lucene 9 has rewritten every segment, but without Lucene 9's field-consistency leniency for them (LUCENE-10518), so FieldExistsQuery returns documents that lack the doc value (or throws) and IndexWriter refuses the index | 1 |
| LFV-1109 | core / search: PointRangeQuery.rewrite (GITHUB#14609 full-coverage rewrite to FieldExistsQuery, new in 10.3.0) on composite readers | medium | PointRangeQuery rewrites a range that covers every indexed point to FieldExistsQuery without checking that each leaf has points, so on a MultiReader whose other index stores the field without points it also matches (or, under MUST_NOT, drops) documents that have no point | 1 |
| LFV-278 | index / addIndexes reorder path: SlowCompositeCodecReaderWrapper merged vector values (MergedDocIterator) over SortingCodecReader inputs | medium | SlowCompositeCodecReaderWrapper's merged vector iterator numbers ordinals by position and ignores each input's own index(), so addIndexes of two or more SortingCodecReader inputs through a reordering merge policy writes vectors onto the wrong documents | 1 |
| LFV-420 | codecs / quantized vector formats merge (Lucene104 scalar-quantized, Lucene102 binary-quantized) with index / addIndexes through SlowCodecReaderWrapper and memory / MemoryIndex | medium | Merging into a Lucene104 scalar-quantized FLOAT32 vector field that does not use COSINE centers the merge source's own vector arrays in place, so IndexWriter.addIndexes changes a source that keeps its arrays (MemoryIndex, FloatVectorValues.fromFloats) and can store wrong full-precision vectors or wrong quantized codes | 3 |
| LFV-491 | facet / taxonomy (TaxonomyMergeUtils.merge, OrdinalMappingLeafReader) | medium | TaxonomyMergeUtils.merge / OrdinalMappingLeafReader do not re-map the taxonomy ordinals stored in association facet fields, so merged IntAssociationFacetField / FloatAssociationFacetField values are credited to unrelated categories (10.x, main) or lost (9.x) | 1 |
| LFV-722 | facet / taxonomy (TaxonomyMergeUtils.merge, OrdinalMappingLeafReader; FacetsConfig default DimConfig) | medium | TaxonomyMergeUtils.merge (OrdinalMappingLeafReader) does not re-map the facet ordinals stored in the index field chosen by an overridden FacetsConfig#getDefaultDimConfig, so merged documents silently point at other categories | 1 |
| LFV-284 | queryparser / classic QueryParser and MultiFieldQueryParser (QueryParser.jj MultiTerm run grouping, QueryParserBase.addClause conjunction step) | medium | Classic QueryParser with the default splitOnWhitespace=false: since #16446 an AND/OR that directly follows a token the analyzer drops (such as a stopword) binds to the whole preceding run of plain terms instead of the last term, so typing the stopword changes which documents match (regression new in 10.6.0, also on main and branch_10_6) | 1 |
| LFV-860 | search / index-sort range-query shortcuts (Sort.getPrimarySortField; SortedNumericDocValuesRangeQuery, SortedSetDocValuesRangeQuery, IndexSortSortedNumericDocValuesRangeQuery) | medium | Sort.getPrimarySortField (new in 10.6.0, #16424) skips an index-sort field that the reader's FieldInfos do not list, or whose skip index holds a single value, even when that field still orders the documents (a FilterLeafReader hides it but keeps the index sort, or a BinarySortField derives its key from other fields), so doc-values range queries on the next sort field, LongField.newRangeQuery included, return wrong hits or throw | 2 |
| LFV-1051 | index / doc-values overlays (OverlaySortedNumericDocValues over DocValuesOverlayMerger), seen through search / field sorting (SortedNumericSelector, LongComparator, TopFieldCollector) | medium | With doc-values overlays (on by default on main), a second advanceExact on the same document does not restart a multi-valued SORTED_NUMERIC column's values, so SortedNumericSortField sorts return the wrong top hits (or throw) | 1 |
| LFV-229 | analysis / Thai (ThaiTokenizer#incrementWord user-dictionary loop and re-anchor, GITHUB#16722; ThaiTokenizerFactory 'dictionary') | medium | ThaiTokenizer with a user dictionary silently drops the vowel or tone marks that follow a dictionary word ending inside a character cluster (with {แม่น}, 'แม่น้ำ' (river) is tokenized as just [แม่น] (accurate)), because the match is accepted at a non-boundary and the remainder, which now starts with a mark, is skipped | 1 |
| LFV-261 | search / similarities: StableTflSimilarity with SynonymQuery and CombinedFieldQuery | medium | StableTflSimilarity scores SynonymQuery and CombinedFieldQuery with the length of a placeholder term string ('synonym pseudo-term', 19 code points, or 'pseudo_term', 11), not the length of the query terms | 1 |
| LFV-628 | search / SynonymQuery pseudo-term statistics (SynonymWeight; reached through QueryBuilder with stock synonym parsers) | medium | SynonymQuery with a repeated term adds that term's totalTermFreq once per copy, so the pseudo-term statistics it gives the Similarity can exceed the field's sumTotalTermFreq (AssertionError in SimilarityBase with -ea, scores from impossible statistics with -da) | 1 |
| LFV-1103 | search / BlendedTermQuery with IndexSearcher statistics overrides | medium | BlendedTermQuery blends shard-local statistics in rewrite() and passes the blended values to IndexSearcher#termStats, so an override that returns per-term distributed statistics undoes the blend and the blended terms no longer score alike (known: elastic/elasticsearch#42957 and #9884, partial overlap) (released) | 1 |
| LFV-093 | misc / BP merge-time reordering | medium | Merges through BPReorderingMergePolicy with BpVectorReorderer break document blocks even when a parent field is configured | 1 |
| LFV-1022 | misc / index: BpVectorReorderer command line (main -> reorderIndexDirectory, an in-place rewrite through an OpenMode.CREATE IndexWriter and addIndexes) | medium | BpVectorReorderer's in-place command-line reorder commits an empty or partial index over the original when reordering fails | 1 |
| LFV-211 | queries / FunctionScoreQuery block-max pruning (#16431) | medium | FunctionScoreQuery's block-max bound multiplies by the wrapped query's no-score max score (0 for a TermQuery), so a BooleanQuery that contains it can drop the true top hits | 1 |
| LFV-435 | search / TermQuery equality and BooleanQuery clause de-duplication (blended and fuzzy TermStates) | medium | TermStates#equals compares only docFreq, so BooleanQuery still merges blended or fuzzy TermQuery clauses whose totalTermFreq differs, and similarities that read totalTermFreq then score them wrongly (the part of the #10309 fix, #12354, that was left out; main only) | 1 |
| LFV-109 | index / DirectoryReader reopen with doc-values updates (generation numbers reused across writer sessions) | medium | A reopened reader returns the doc values of a discarded writer session or commit when a later writer session reuses the same doc-values generation number | 1 |
| LFV-430 | index / IndexWriter tryDeleteDocument (dropDeletedSegment, change accounting) | medium | If tryDeleteDocument removes a segment's last live document and closing that segment's pooled reader throws, IndexWriter stays open but never counts the change, so NRT readers hide the document while commit() and close() keep it | 1 |
| LFV-452 | index / IndexWriter deleteAll (change accounting on the exception path, ReaderPool.dropAll) | medium | If closing a pooled segment reader throws inside IndexWriter.deleteAll, the segments are already cleared but the change is never counted: the writer stays open and its NRT readers show an empty index, yet hasUncommittedChanges() is false and commit() and close() keep every document, until a later unrelated commit silently applies the failed deleteAll | 1 |
| LFV-474 | index / IndexWriter deleteAll versus a concurrent segment flush (DocumentsWriter.lockAndAbortAll, flush-ticket queue) | medium | IndexWriter.deleteAll misses a segment flush that another thread is already running, so documents added before deleteAll survive it and are committed | 1 |
| LFV-1074 | index / IndexWriter addIndexes vs deleteAll (writer-wide field schema, FieldInfos.FieldNumbers) | medium | A deleteAll() that overlaps addIndexes clears the incoming fields from the writer's field schema, but addIndexes still publishes its segment, so a later document can give such a field another doc-values type and the committed index can no longer be opened by an IndexWriter | 1 |
| LFV-1137 | index / IndexWriter deleteAll (IndexWriter-DocumentsWriter lock order) | medium | IndexWriter.deleteAll can deadlock with a concurrent flush publish and a concurrent tryDeleteDocument or addIndexes, because DocumentsWriter.lockAndAbortAll waits for the flush-ticket purge lock while holding the DocumentsWriter monitor | 1 |
| LFV-635 | index / IndexWriter doc-values updates vs deleteAll (writer-wide field schema, FieldInfos.FieldNumbers) | medium | A doc-values update racing IndexWriter.deleteAll() can be queued after deleteAll has cleared its field from the writer's field schema; applying it then makes every commit, NRT reopen and close() fail (a tragic close with assertions on), or, if a document added in between gives the field another doc-values type, commits a segment whose field cannot be read | 1 |
| LFV-1090 | index / IndexWriter delete queue (DocumentsWriterPerThread.finishDocuments, DeleteSlice failure handling) | medium | After addDocument fails with a non-tragic exception while an in-memory segment copies its backlog of buffered deletes and doc-values updates, the segment's next document resets its delete slice past the operations that were never applied, so IndexWriter stays open and the next successful commit silently lacks an acknowledged delete of a buffered document | 1 |
| LFV-842 | index / IndexWriter merge registration (registerMerge, pendingMerges, mergingSegments) | medium | If the IndexWriter InfoStream throws inside registerMerge, the merge stays queued but its segments are not marked as merging, so the next merge selection picks the same segments again and, with assertions disabled, forceMerge commits duplicated documents (every release since 3.2.0) | 2 |
| LFV-1082 | index / IndexWriter flush publishing (IndexWriter.publishFlushedSegments, IndexWriter.publishFlushedSegment, DocumentsWriterFlushQueue.innerPurge) | medium | If the IndexWriter InfoStream throws a RuntimeException while a flushed segment is being published, IndexWriter drops that already written segment (and, for some log lines, the deletes and doc-values updates on its flush ticket) but stays open, so the next successful commit silently lacks acknowledged documents its sequence number covers (every release since 4.0.0) | 1 |
| LFV-1083 | index / IndexWriter commit failure handling (IndexWriter.startCommit, prepareCommitInternal and rollback; IndexFileDeleter reference counts) | medium | If commit() fails with an InfoStream exception after the pending segments file is synced, the commit's file references are released twice, so a later rollback() (or close() with commitOnClose=false) deletes files of the last commit and the index can no longer be opened | 1 |
| LFV-013 | index / doc-values updates | medium | Concurrent doc-values updates can make a merge throw NullPointerException and close the writer | 1 |
| LFV-652 | core / index (ParallelLeafReader stored fields x StoredFieldsWriter.MergeVisitor, on addIndexes and wrapForMerge copies) | medium | Copying a ParallelLeafReader into an index (IndexWriter.addIndexes over SlowCodecReaderWrapper, or a merge whose OneMerge.wrapForMerge returns one) silently stores a later sub-reader's stored fields under another field's name: ParallelLeafReader.storedFields() lets each sub-reader visit with its own FieldInfo numbers while getFieldInfos() renumbers the fields, and StoredFieldsWriter.MergeVisitor skips its remap-by-name step when the numbers look aligned | 1 |
| LFV-018 | index / readers | medium | ParallelLeafReader.termVectors() no longer honours 'the first reader having the field wins' | 1 |
| LFV-233 | analysis / SegmentingTokenizerBase buffer refill (smartcn HMMChineseTokenizer and SmartChineseAnalyzer; ThaiTokenizer and ThaiAnalyzer) | medium | SmartChineseAnalyzer and ThaiTokenizer lose a supplementary character (an emoji, a CJK Extension B ideograph) that straddles their 1024-char buffer in text with no line break, because SegmentingTokenizerBase.refill cuts the surrogate pair in half: smartcn indexes two U+FFFD halves and ThaiTokenizer drops the character | 1 |
| LFV-707 | analysis-smartcn / HHMM segmenter character classes (Utility.getCharType -> HHMMSegmenter DELIMITER token -> SegTokenFilter ',' -> default stop list; SmartChineseAnalyzer and HMMChineseTokenizer) | medium | SmartChineseAnalyzer silently drops letters and letter-numbers as if they were punctuation, among them the Chinese zero U+3007 (二〇〇八年 -> 二, 八, 年) and the Roman numerals Ⅰ-Ⅻ (第Ⅲ章 and 第Ⅳ章 analyze identically), because Utility.getCharType classifies four whole Unicode blocks as DELIMITER | 1 |
| LFV-557 | analysis-morfologik / language analyzers (UkrainianMorfologikAnalyzer normalization: Analyzer#normalize and initReaderForNormalization, used by the query parsers for multi-term queries) | medium | UkrainianMorfologikAnalyzer overrides neither normalize() nor initReaderForNormalization, so prefix, wildcard, regexp, range and fuzzy terms from the query parsers skip its lower-casing and its apostrophe, stress-mark, soft-hyphen and ґ mapping and miss words spelled exactly as in the document | 1 |
| LFV-534 | analysis-common / language analyzers (SerbianAnalyzer.normalize, used by the query parsers for multi-term queries) | medium | SerbianAnalyzer.normalize only lower-cases and skips SerbianNormalizationFilter (Cyrillic to Latin, diacritics removed), so prefix, wildcard, fuzzy, regexp and range queries typed in Cyrillic or with č ć š ž đ miss the indexed terms | 1 |
| LFV-1063 | analysis-common / CustomAnalyzer conditional blocks (ConditionalTokenFilterFactory, ProtectedTermFilterFactory) and Analyzer.normalize, which the query parsers use for multi-term queries | medium | CustomAnalyzer.normalize skips the token filters inside a when()/whenTerm() block or a ProtectedTermFilterFactory (ConditionalTokenFilterFactory has no normalize()), so query-parser range, fuzzy, prefix, wildcard and regexp terms are not lower-cased or folded like the indexed term and silently miss documents | 1 |
| LFV-1053 | analysis-icu / collation (ICUCollationKeyAnalyzer vs Analyzer#normalize; classic QueryParser range bounds) | medium | ICUCollationKeyAnalyzer does not override attributeFactory(String), so Analyzer.normalize returns the plain UTF-8 bytes instead of the ICU collation key, and classic QueryParser range queries on an ICU collation-key field match the wrong documents | 1 |
| LFV-1064 | analysis-kuromoji / sutegana (small kana) token filter factories (JapaneseKatakanaUppercaseFilterFactory, JapaneseHiraganaUppercaseFilterFactory) and Analyzer.normalize via CustomAnalyzer, which the query parsers use for multi-term queries | medium | JapaneseKatakanaUppercaseFilterFactory and JapaneseHiraganaUppercaseFilterFactory do not override normalize(), so CustomAnalyzer.normalize leaves small kana unmapped and query-parser prefix, wildcard, regexp, fuzzy and range terms that contain them silently miss the indexed documents | 1 |
| LFV-663 | analysis-common / Brazilian Portuguese stemmer (BrazilianStemmer.step1; BrazilianStemFilter, BrazilianAnalyzer and the 'brazilianStem' factory) | medium | BrazilianStemmer throws away the result of its "logias" -> "log" rule, so plural -logias nouns stay unstemmed and stop matching their singular | 1 |
| LFV-594 | analysis / QueryAutoStopWordAnalyzer (analysis-common query package; AnalyzerWrapper reuse strategy, Analyzer.ReuseStrategy) | medium | QueryAutoStopWordAnalyzer inherits its delegate's reuse strategy although its analysis chain differs per field, so with a stock delegate (GLOBAL_REUSE_STRATEGY) the chain built for the first field a thread analyses is reused for every other field: one field's stop words drop another field's query terms and a field's own stop words are kept (since 4.5.0) | 3 |
| LFV-311 | analysis / HTMLStripCharFilter (JFlex grammar: SCRIPT_COMMENT, STYLE_COMMENT, SINGLE_/DOUBLE_QUOTED_STRING and the %eof exclude list; also the 'htmlStrip' char filter SPI) | medium | HTMLStripCharFilter silently drops all text after a <!-- -->-wrapped <script> or <style> block whose content has an unbalanced quote (for example the apostrophe in a JS comment '// Don't remove' or a CSS comment '/* client's fix */'): the quote opens a quoted-string state that ignores '-->' and the end tag, and at end of input everything after the quote is removed, including the text after the closed </script> or </style> | 1 |
| LFV-780 | analysis / HTMLStripCharFilter (JFlex grammar: the BR, SCRIPT and STYLE start-tag rules of the LEFT_ANGLE_BRACKET state; also the 'htmlStrip' char filter SPI) | medium | HTMLStripCharFilter (since 10.5.0) treats a start tag whose name only begins with script, style or br (<scripts>, <style-guide>, <stylesheet>, <brand>) as a script, style or br tag, so it silently drops all text after it up to the next </script> or </style> (often to the end of the value) and misapplies escapedTags to such names | 1 |
| LFV-290 | analysis / HTMLStripCharFilter (JFlex grammar: OpenTagAttribute, EventAttribute, OpenTagContent) | medium | HTMLStripCharFilter drops the visible text after a tag when a quoted attribute value ends with whitespace, a name and '=' (title="a b=", alt="x y ="): the scanner re-reads the value's closing quote as the opening quote of a new attribute value, so the tag runs on to the next quote of the same kind; the GITHUB#15754 fix (#15756) covers only the shape without whitespace | 1 |
| LFV-878 | analysis / HTMLStripCharFilter (JFlex grammar: the %eof end-of-input switch for the start- and end-tag tail states; also the 'htmlStrip' char filter SPI) | medium | HTMLStripCharFilter drops an unclosed '<name' or '</name' when the input ends right after the name, but outputs the same text when any character follows it, so 'a < b' indexes only 'a' | 1 |
| LFV-721 | analysis-common / wikipedia: WikipediaTokenizer (JFlex grammar character classes, WikipediaTokenizerImpl.jflex LETTER/DIGIT macros) | medium | WikipediaTokenizer silently drops letters and digits from plain text that Unicode 3.0 already had (µ in '5 µm', ª/º in '1ª'/'2º', fullwidth digits and letters, ligatures such as fi, Yi syllables, Arabic presentation forms; 2,083 BMP code points that ClassicTokenizer keeps) because its LETTER and DIGIT macros are hard-coded 2008 range lists | 1 |
| LFV-353 | analysis / WordDelimiterGraphFilter position increments (IGNORE_KEYWORDS keyword bypass; factory ignoreKeywords option) | medium | WordDelimiterGraphFilter with IGNORE_KEYWORDS moves the position hole of a swallowed delimiter-only token (a standalone '/', '-' or '&') to after the next keyword token, so exact phrases across the keyword miss or over-match (released since 7.4.0) | 1 |
| LFV-528 | analysis-common / shingle (ShingleFilter, ShingleFilterFactory, ShingleAnalyzerWrapper) | medium | ShingleFilter with minShingleSize >= 3 ends the token stream early when a hole (for example a removed stop word) is near the end, so the last word(s) are never output as unigrams and are missing from the index ('a cup of tea' loses 'tea'; 'the cat' yields no token at all) | 1 |
| LFV-781 | analysis-common / shingle (FixedShingleFilter, FixedShingleFilterFactory) over core analysis GraphTokenFilter (route walk) | medium | FixedShingleFilter takes the gap before each token of a graph route from that token's stream position increment, so tokens stacked right after a hole (a removed stop word followed by a preserved original, a stemmed variant or a synonym) get shingles that skip the filler ('at café' for 'at the café') while the correct ones ('at _ café') are missing, and a token after a multi-position token gets a filler it should not have ('login _' instead of 'login page'); released since 8.0.0 | 1 |
| LFV-1094 | analysis / kuromoji (JapaneseTokenizer discardPunctuation) | medium | JapaneseTokenizer with the default discardPunctuation=true drops the dictionary nouns (株) (有) (社) (財) whole, Han letter included, because it tests only the token's first character for punctuation (known: #10430 / LUCENE-9390) (released) | 1 |
| LFV-1058 | analysis / kuromoji and nori number filters (JapaneseNumberFilter, KoreanNumberFilter: attribute state of the composed number token) | medium | JapaneseNumberFilter and KoreanNumberFilter emit a composed number on the attribute state of the token after it, so the number takes that token's part of speech, reading, position increment and position length (車は三台 with は removed by a StopFilter gives 3 +1 名詞-接尾-助数詞 instead of 3 +2 名詞-数) (known: #10130, Japanese part of speech) (released since 6.0.0 / 8.2.0) | 1 |
| LFV-658 | analysis / nori KoreanTokenizer user dictionary (UserDictionary right ids, UserMorphData left id vs the bundled mecab-ko-dic-2.1.1 connection costs) | medium | Nori: user-dictionary nouns still use the context ids of mecab-ko-dic 2.0.3 after Lucene 10.0 moved to mecab-ko-dic 2.1.1, so the particle after a user noun gets the wrong part of speech (학교가: 가 becomes the verb 'go'; 학생이: 이 becomes the copula) and KoreanAnalyzer indexes spurious terms such as 가 and 이 | 1 |
| LFV-620 | analysis-opennlp / OpenNLPLemmatizerFilter (sentence buffering, KeywordAttribute handling) | medium | OpenNLPLemmatizerFilter silently drops keyword-marked tokens that end a sentence (and every token but the first of a sentence made only of keyword tokens), because since 9.5.0 it ends a sentence once it has used all lemmas, and keyword tokens get no lemma | 1 |
| LFV-444 | analysis / nori KoreanTokenizer (Viterbi.backtrace unigram branch; KoreanTokenizerFactory, KoreanAnalyzer) | medium | KoreanTokenizer with outputUnknownUnigrams=true emits every punctuation, symbol and whitespace character inside an unknown word as its own token ('$', '@', '.', ' ', '\t', '\n') although discardPunctuation=true (the default): LUCENE-8784 (8.2.0) dropped the punctuation check from the unigram branch | 1 |
| LFV-656 | analysis / kuromoji user dictionary (ja.dict.UserDictionary entry validation; USER-token expansion in ViterbiNBest and JapaneseTokenizer.incrementToken) | medium | Kuromoji UserDictionary loads entries whose whitespace makes the stored segment lengths disagree with the surface form (a half-width space inside the surface, a tab between segments, a space after a comma), so JapaneseTokenizer later emits a term that starts with a space and drops the entry's last character, throws ArrayIndexOutOfBoundsException, or emits an empty token | 1 |
| LFV-540 | analysis-common / compound (HyphenationTree, HyphenationCompoundWordTokenFilter) | medium | HyphenationTree.hyphenate does not shift its added start and end points past leading characters that are in none of the grammar's character classes, so HyphenationCompoundWordTokenFilter misses the subwords of tokens such as 3zimmerwohnung or "zimmerwohnung (the same word with a trailing quote decomposes) | 1 |
| LFV-897 | analysis-common / compound hyphenation (TernaryTree insert and compact via HyphenationTree.loadPatterns and HyphenationCompoundWordTokenFilter) | medium | Hyphenation grammars whose TernaryTree key array grows past 65,535 chars load without error but silently lose or corrupt patterns, because TernaryTree stores key-array offsets in 16-bit chars (the Norwegian OFFO grammars the Lucene docs point to: nb/nn 1,158 of 27,448 patterns wrong, 1.2 no.xml 309 of 26,017) | 1 |
| LFV-739 | analysis / UAX29URLEmailTokenizer JFlex URL rules (path segments of http(s), scheme-less, ftp and file URLs; analysis-common) | medium | UAX29URLEmailTokenizer ends a URL token at the first $ + ! * ' ( ) or , in the URL path, although both RFCs its grammar cites allow these characters there, so URLs such as https://en.wikipedia.org/wiki/Python_(programming_language) or http://example.com/a+b/c are split | 1 |
| LFV-525 | analysis / pattern tokenizers (analysis-common: SimplePatternTokenizer, SimplePatternSplitTokenizer and their simplePattern / simplePatternSplit factories) | medium | SimplePatternTokenizer and SimplePatternSplitTokenizer stop scanning when a non-matching lookahead reaches the end of the input, so later tokens are dropped (or later separators ignored) | 1 |
| LFV-657 | analysis-icu / segmentation (ICUTokenizer with DefaultICUTokenizerConfig; break rules Default.rbbi -> Default.brk) | medium | ICUTokenizer silently drops Korean words when a Hangul syllable is followed by a combining mark, soft hyphen, ZWNJ, ZWJ or U+FEFF: the Hangul rules of Default.rbbi do not attach the trailing Extend/Format character, so the segment gets rule status 0 and is skipped as a non-word (U+D55C U+AD6D U+00AD U+C5B4 keeps only U+C5B4; since 4.7.0, LUCENE-4381) | 2 |
| LFV-728 | analysis-smartcn / HHMM segmenter character classes (Utility.getCharType SPACE_LIKE test -> HHMMSegmenter OTHER branch -> one-character STRING term; SmartChineseAnalyzer and HMMChineseTokenizer) | medium | SmartChineseAnalyzer indexes whitespace characters as terms: VERTICAL TAB, FORM FEED, OGHAM SPACE MARK and the eleven spaces U+2000-U+200A (EN QUAD to HAIR SPACE, among them EN, EM and THIN SPACE) each become a one-character term, because Utility.getCharType classifies them OTHER instead of SPACE_LIKE | 1 |
| LFV-849 | analysis / kuromoji completion romanization (romaji_map.txt read by KatakanaRomanizer; JapaneseCompletionFilter, JapaneseCompletionAnalyzer) | medium | Japanese completion suggester (JapaneseCompletionAnalyzer / JapaneseCompletionFilter): words with a small tsu before shi, chi or tsu (雑誌, 決して, マッチ, 三つ) are never suggested for their Hepburn or input-method spellings zasshi, kesshite, macchi/matchi, mittsu, because romaji_map.txt maps ッシ only to 'ssi', ッチ only to 'tti' and ッツ only to 'ttu', while the base rows シ/チ/ツ list shi/chi/tsu and the neighbouring rows ッシャ and ッチャ do double the consonant ('ssha', 'ccha') | 1 |
| LFV-047 | codecs / vectors | medium | Two antipodal COSINE vectors make the OSQ centroid zero, so flush or merge fails and the writer closes | 1 |
| LFV-183 | codecs / postings writer and reader (Lucene104 level-1 skip data, ImpactLength; the same field in the Lucene912, Lucene101 and Lucene103 formats) | medium | Since 9.12.0 the default postings writer stores the byte length of a level-1 block's competitive impacts in a signed short, so with a custom Similarity whose norms do not fit in a byte, a term with 8,192 or more postings in one segment (4,096 before 10.4) can need more than 32,767 bytes: flush fails an assertion with -ea, and with -da the segment is written but that term's postings then throw on every read or are read back wrong | 1 |
| LFV-097 | index / columnar addBatch doc values (dense NUMERIC and SORTED_NUMERIC writers) | medium | When a dense LongColumn's values cursor throws during addBatch, the NUMERIC/SORTED_NUMERIC doc values it already delivered stay buffered with no document, so later documents of that field in the same segment are stored with another document's value | 1 |
| LFV-101 | index / columnar addBatch (dense points, PointValuesWriter) | medium | When IndexWriter#addBatch fails part-way through a dense points column, the point bytes it already copied stay in the points buffer, so documents added later to the same in-memory segment are silently indexed with the rejected batch's point values | 1 |
| LFV-096 | index / columnar addBatch (term vectors) | medium | An addBatch that registers a new term-vector field but frames no rows leaves a segment whose FieldInfos declare term vectors with no term-vector files, so the committed index cannot be opened | 1 |
| LFV-094 | index / columnar addBatch (DictionaryColumn SORTED_SET doc values, SortedSetDocValuesWriter) | medium | A SORTED_SET DictionaryColumn tuple that addBatch rejects (out-of-range ordinal, or ordValue() throws) leaves an empty document in the doc-values buffer, so the next flush fails and closes the IndexWriter, or with -da commits a segment whose field cannot be read | 1 |
| LFV-199 | index / deletion policies (PersistentSnapshotDeletionPolicy save-file loading, crash recovery) | medium | PersistentSnapshotDeletionPolicy adopts a broken newest save file on load and deletes the good older one, so an OS crash, power loss or process kill while snapshot() or release() writes its save file silently drops every earlier persisted snapshot, and IndexWriter then deletes the snapshotted commits | 1 |
| LFV-408 | misc / index tools (IndexSplitter.split) over core / index: SegmentCommitInfo per-commit doc-values update state | medium | IndexSplitter.split writes each copied segment into the destination commit without its doc-values update metadata, so on main the copy silently reads wrong doc values, and in every release since 4.6.0 the first IndexWriter opened on the copy deletes the copied update files and the copy can no longer be opened | 1 |
| LFV-481 | facet / taxonomy (ReindexingEnrichedDirectoryTaxonomyWriter.reindexWithNewOrdinalData) | medium | ReindexingEnrichedDirectoryTaxonomyWriter.reindexWithNewOrdinalData rebuilds only the last committed taxonomy, so categories added since that commit are dropped and their ordinals are later reused for other categories | 1 |
| LFV-280 | codecs / per-field postings format merge (PerFieldPostingsFormat attribute bookkeeping) | medium | PerFieldPostingsFormat merge leaves stale inherited format attributes on a field that has no postings left after a segment written by a non-per-field postings codec (for example SimpleTextCodec), so the merged segment cannot be opened | 1 |
| LFV-249 | codecs / SharedTermsUniformSplit postings format (STUniformSplitTermsWriter.merge under PerFieldPostingsFormat and PerFieldMergeState) | medium | SharedTermsUniformSplit merges silently drop the postings of fields that a source segment stored under another postings format or another shared-terms group (after a per-field postings mapping change, or addIndexes from an index with another mapping), because STUniformSplitTermsWriter.merge reads only the shared-terms block of the first field with terms in each source segment | 1 |
| LFV-417 | misc / BP merge-time reordering (BPIndexReorderer with document blocks) | medium | BPIndexReorderer assumes every segment ends with a parent document: once a segment ends with child documents that have no parent after them, each BP reordering merge in which that segment comes last throws and closes the IndexWriter | 1 |
| LFV-563 | index / IndexWriter document blocks (parent field) and merges | medium | A document block rejected at a child can be flushed as a fully deleted segment without the parent field; if the merge policy keeps it (SoftDeletesRetentionMergePolicy can), merges that combine it only with segments without multi-document blocks throw 'expected parent doc field ... across all segments' and close IndexWriter, again after every reopen | 1 |
| LFV-1050 | index / index sorting with document blocks (IndexingChain flush-time sort, DocumentsWriterPerThread non-aborting rejection) | medium | With an index sort and a parent field, a document that IndexWriter rejects (a documented, non-aborting IllegalArgumentException) as the last document of an in-memory segment that holds a document block makes the next flush throw ArrayIndexOutOfBoundsException 'Index 2147483647' and close IndexWriter, losing every uncommitted document (since 9.10.0) | 1 |
| LFV-256 | codecs / per-field doc values and vectors formats (PerFieldDocValuesFormat, PerFieldKnnVectorsFormat attribute bookkeeping) | medium | PerFieldDocValuesFormat and PerFieldKnnVectorsFormat accept a per-field hook that returns another per-field format (for example the default codec's docValuesFormat() or knnVectorsFormat()); the nested writer overwrites the outer per-field attributes, so the committed segment cannot be opened, while PerFieldPostingsFormat rejects the same configuration | 2 |
| LFV-615 | core index / IndexUpgrader (command line and default-config upgrade path); IndexWriter index-sort validation | medium | IndexUpgrader's command line and default constructors use a bare IndexWriterConfig, so upgrading a sorted index silently and permanently removes its index sort (the application's sorted IndexWriter then refuses to open the index), and an index with a parent field or a soft-deletes field cannot be upgraded at all | 1 |
| LFV-580 | index / IndexWriterConfig and IndexWriter configuration (creation-only settings re-read from the caller's config object) | medium | IndexWriterConfig setters called after the IndexWriter was created still change that writer (index sort, parent field, soft-deletes field, codec, similarity, ...), although the class javadoc says such changes have no effect; a late index sort or parent field makes merges fail and closes the writer, and a late soft-deletes field can drop a live document | 1 |
| LFV-1042 | luke / IndexTools write operations (IndexToolsImpl.optimize and addDocument through IndexUtils.createWriter) behind Tools > Optimize and Documents > Add document; IndexWriter index-sort validation | medium | Luke: Optimize and Add document open an IndexWriter without the index's sort, so on a sorted index they silently write unsorted segments and the application's IndexWriter configured with that sort then refuses to open the index | 1 |
| LFV-730 | index / IndexWriter merge soft-delete accounting (mergeMiddle carry-over of soft deletes x OneMerge#wrapForMerge, OneMergeWrappingMergePolicy, SoftDeletesRetentionMergePolicy) | medium | With a soft-deletes field configured, IndexWriter's merge assumes OneMerge#wrapForMerge only revives documents: for each merged segment without hard deletes, every live document that a merge wrapper hides (which the javadoc allows) lowers the new segment's soft-delete count by one, so the merge throws 'invalid softDelCount=-1' when nothing is revived, and under SoftDeletesRetentionMergePolicy commits a too-low count (numDocs and IndexSearcher#count over-count, CheckIndex rejects it, later merges of it throw); regression since 7.7.0 (LUCENE-8569) | 1 |
| LFV-161 | search / CachingCollector first-pass caching (CachingCollector, CachingCollectorManager) | medium | CachingCollector and CachingCollectorManager report isCached() true (no overflow) but hold only the hits their wrapped first-pass collector let through (TOP_SCORES pruning, early leaf termination, skipped leaves), so replay() silently feeds the second pass fewer matches than re-running the query | 2 |
| LFV-765 | facet / sampling (RandomSamplingFacetsCollector.createManager reduce, FacetsCollectorManager.reduceMatchingDocs) | medium | RandomSamplingFacetsCollector.createManager samples the hits twice when a search has more than one slice: the reduce reads each slice's already-sampled getMatchingDocs() as its original hits, so the sample is far too small and every amortized facet count is biased low (regression from #13542, 10.0.0 onward) | 1 |
| LFV-303 | facet / range facet counts (LongRangeCounter multi-valued path, exclusive and overlapping counters) | medium | Multi-valued range facet counts drop matches when a document's values do not arrive in ascending order (custom MultiLongValuesSource/MultiDoubleValuesSource, or raw-bit doubles with two or more negative values): LongRangeCounter.addMultiValued assumes sorted values | 1 |
| LFV-433 | facet / LongValueFacetCounts (count-all constructors with a LongValuesSource or MultiLongValuesSource) | medium | LongValueFacetCounts count-all constructors that take a LongValuesSource or MultiLongValuesSource count deleted documents, although they promise the result of a MatchAllDocsQuery (LUCENE-10070 fixed only the field-based constructor) | 2 |
| LFV-437 | facet / sampling (RandomSamplingFacetsCollector: sampling rate vs bin size in amortizeFacetCounts and getSamplingRate) | medium | RandomSamplingFacetsCollector samples one hit per (int) (1 / samplingRate) hits but amortizes by the untruncated samplingRate, so amortized facet counts are up to 2x too high (1999 hits with sampleSize 1000: every hit is sampled, yet every count is doubled) | 2 |
| LFV-539 | facet / taxonomy association facets (TaxonomyFacetFloatAssociations value-source path, FloatTaxonomyFacets#updateValueFromRollup count roll-up) | medium | TaxonomyFacetFloatAssociations with a DoubleValuesSource reports a too-high LabelAndValue.count for every label that has matching documents below it in a hierarchical dimension, because FloatTaxonomyFacets rolls the counts up again at every ancestor level (values are right; every release since 9.11.0) | 1 |
| LFV-234 | grouping / GroupingSearch (all-groups and all-group-heads passes) | medium | GroupingSearch.setIgnoreDocsWithoutGroupField(true) is applied only to the first pass, so totalGroupCount, getAllMatchingGroups() and getAllGroupHeads() still include the null group | 1 |
| LFV-414 | grouping / range group selectors (LongRangeGroupSelector, DoubleRangeGroupSelector) on scorer-less collection paths: the GroupingSearch score-less cache replay and the DistinctValuesCollector value selector | medium | LongRangeGroupSelector and DoubleRangeGroupSelector load their per-segment values only in setScorer, so grouping with score-less caching returns wrong groups (8.6.0-10.5.2) or throws NullPointerException (10.6.0 by reading, and main), and DistinctValuesCollector with a range value selector always throws NullPointerException | 4 |
| LFV-368 | facet / getTopDims of taxonomy and SortedSetDocValues facets (TaxonomyFacets#getTopDims and AbstractSortedSetDocValueFacetCounts#getTopDims, shared by FastTaxonomyFacetCounts, the taxonomy int and float association facets, SortedSetDocValuesFacetCounts and ConcurrentSortedSetDocValuesFacetCounts) | medium | Facets#getTopDims on taxonomy and SortedSetDocValues facets admits a multi-valued dimension without requireDimCount even when the query has no hits in it, so the result list contains null (AssertionError with -ea) and a dimension that has hits can be pushed out (released since 9.2.0) | 1 |
| LFV-363 | facet / taxonomy facets (TaxonomyFacets#getTopDims, shared by FastTaxonomyFacetCounts and the int and float association facets) | medium | Taxonomy Facets#getTopDims returns another dimension's children, childCount and value under a multi-valued dimension's name, because replacing the bottom of the top-dims queue updates dim and value but not dimOrd (released since 9.2.0) | 1 |
| LFV-524 | facet / MultiFacets and DrillSideways results (MultiFacets#getAllDims, the default DrillSideways#buildFacetsResult, the inherited Facets#getTopDims) | medium | MultiFacets.getAllDims, the Facets of every DrillSideways result with a drill-down dim, lists the mapped (sideways) dims first in HashMap order instead of sorted by value and returns null for a mapped dim without hits, so the inherited getTopDims returns the wrong dims | 1 |
| LFV-723 | facet / taxonomy facets (TaxonomyFacets#rollup dimension enumeration vs the overridable FacetsConfig default dimension config; FastTaxonomyFacetCounts, TaxonomyFacetFloatAssociations) | medium | Taxonomy facets never roll up a single-valued hierarchical dimension whose config comes from an overridden FacetsConfig#getDefaultDimConfig, so its dimension and non-leaf counts are 0 and getTopChildren returns null or partial results | 1 |
| LFV-690 | misc / search: DiversifiedTopDocsCollector and DiversifiedTopDocsCollectorManager (per-key diversity cap) | medium | DiversifiedTopDocsCollector and its manager put every document without a key into key 0's group, so a keyless document uses up key 0's maxHitsPerKey quota and real key-0 hits are silently dropped from the top hits | 1 |
| LFV-155 | misc / DocValuesStats double statistics (DocValuesStatsCollector, DocValuesStatsCollectorManager) | medium | DoubleDocValuesStats and SortedDoubleDocValuesStats (lucene/misc) start max at Double.MIN_VALUE, the smallest positive double, so max() returns 4.9E-324 instead of the real maximum whenever every collected value is <= 0 (and min() returns Double.MAX_VALUE when every value is +Infinity) | 1 |
| LFV-1129 | misc / DocValuesStats: SortedDoubleDocValuesStats decode of sorted-numeric double doc values (core DoubleField) | medium | SortedDoubleDocValuesStats (lucene/misc) reads core DoubleField values as raw IEEE bits, so negative values give a silently wrong min, sum and mean (DoubleField -5.0 and 3.0 give min -0.8749999999999999) | 1 |
| LFV-547 | facet / taxonomy association facets (TaxonomyFacetIntAssociations, TaxonomyFacetFloatAssociations incl. the DoubleValuesSource path; MAX start value in the per-ordinal, roll-up and dimension aggregates) | medium | Association facets with AssociationAggregationFunction.MAX report 0 instead of the maximum when every value of a label, of a single-valued dimension or of a rolled-up hierarchy node is negative, because the maximum starts from 0 (int, float and DoubleValuesSource paths; every release since 9.2.0) | 1 |
| LFV-1116 | facet / taxonomy association facets (TaxonomyFacetIntAssociations, IntTaxonomyFacets, AssociationAggregationFunction.SUM) | medium | Int association facets with AssociationAggregationFunction.SUM add values in int, so a label total above Integer.MAX_VALUE silently wraps to a wrong, often negative, value (known: #6596 / LUCENE-5533) (released since 4.x) | 1 |
| LFV-382 | classification / document classifiers (SimpleNaiveBayesDocumentClassifier field boosts) | medium | SimpleNaiveBayesDocumentClassifier applies a documented 'field^boost' (e.g. 'title^10') only on its first call: it writes the stripped field name back into the caller's textFieldNames array, so every later classification silently returns the unboosted result (released since 6.0.0) | 1 |
| LFV-680 | classification / BooleanPerceptronClassifier (batched training) | medium | BooleanPerceptronClassifier with batchSize > 1 can silently lose the weight updates of misclassified training documents: the weight FST is rebuilt only when a misclassified document sits at a multiple of batchSize and never after the last batch, and updates inside a batch are computed from the last FST build and overwrite each other, so the trained model is wrong (released since 5.0.0) | 1 |
| LFV-391 | classification / SimpleNaiveBayesClassifier (training query; copies in SimpleNaiveBayesDocumentClassifier and CachingNaiveBayesClassifier) | medium | SimpleNaiveBayesClassifier applies its documented training query only to the per-word counts: the class prior and the likelihood denominators are computed over the whole index, so labelled documents outside the training set can decide the class (released since 4.6.0; same pattern in SimpleNaiveBayesDocumentClassifier and CachingNaiveBayesClassifier) | 1 |
| LFV-380 | classification / document classifiers (SimpleNaiveBayesDocumentClassifier.assignClass and getClasses) | medium | SimpleNaiveBayesDocumentClassifier returns NaN for every class and null from assignClass when the document has a field value with no tokens (empty, stop words only or punctuation only), because each value's log-likelihood is divided by its token count (released since 6.0.0) | 1 |
| LFV-395 | classification / BooleanPerceptronClassifier (weights FST) | medium | BooleanPerceptronClassifier adds its term weights to its FST in Java String (UTF-16) order instead of the UTF-8 byte order the FST requires, so a text field with a term starting with a supplementary character (such as an emoji) and a term starting with a character in U+E000..U+FFFF (such as a fullwidth letter) makes training throw AssertionError with -ea and, with -da, silently loses term weights (in some term layouts all of them) or throws ArrayIndexOutOfBoundsException (released since 5.0.0) | 1 |
| LFV-209 | spatial3d / Geo3DPoint shape queries (PointInShapeIntersectVisitor per-document test against GeoStandardCircle and other cap-shaped boundaries) | medium | Geo3DPoint distance queries with a radius below about 1 km silently return wrong results in both directions: each document's decoded point lies a few millimetres off the planet surface and is tested against a circle plane nearly tangent to the surface, so a 10 m query misses documents at its own centre and matches documents about 100 m away | 1 |
| LFV-736 | spatial3d / geom path membership (GeoStandardPath end caps; Geo3DPoint.newPathQuery, Geo3DDocValuesField.newPathSort) | medium | On WGS84, geo3d path end caps are shifted toward the equator, so Geo3DPoint.newPathQuery and Geo3DDocValuesField.newPathSort miss documents just beyond a poleward path end (sort value +Infinity) and match documents tens of km beyond an equatorward end | 1 |
| LFV-551 | spatial3d / Geo3DDocValuesField sort comparators (Geo3DPointDistanceComparator, Geo3DPointOutsideDistanceComparator; all seven Geo3D sort factories) | medium | Geo3D distance sorts read a document's doc values twice in any segment where some document has two or more points, so top-N and searchAfter results come back in the wrong order with another document's distance as the sort value (even a filtered-out or deleted document's), or the search throws EOFException (every release since 7.0.0) | 1 |
| LFV-544 | spatial3d / Geo3DDocValuesField sort comparators (Geo3DPointDistanceComparator, Geo3DPointOutsideDistanceComparator: compareTop under searchAfter paging) | medium | Geo3D distance, path and outside-distance sorts (Geo3DDocValuesField) drop hits under IndexSearcher.searchAfter: compareTop compares the cursor, which is in meters, with the document's distance in planet units, so on WGS84 every page after the first loses all finite-distance hits (released since 6.1.0) | 1 |
| LFV-807 | queries / intervals (Intervals.ordered and unorderedNoOverlaps with equal consecutive sub-sources: OrderedIntervalsSource.deduplicate, RepeatingIntervalsSource) | medium | Intervals.ordered(X, X) with two equal sub-sources that span several positions lets the two copies of X overlap, so ordered(phrase(a, a), phrase(a, a)) matches 'a a a' and ordered(unordered(a, b), unordered(a, b)) matches 'a b a' (one b), while the same query with an equivalent but unequal second source finds nothing | 1 |
| LFV-306 | queries / intervals (Intervals.ordered/unordered with equal sub-sources: RepeatingIntervalsSource, maxgaps) | medium | RepeatingIntervalsSource's iterator computes width() with the sign inverted (start - end + 1 per repeated sub-interval), so when Intervals.ordered/unordered repeat a sub-source wider than one position (for example the same phrase twice) gaps() is over-reported, maxgaps drops real matches and Weight#matches disagrees with the scorer | 1 |
| LFV-809 | queries / intervals (gap-sensitive disjunction rewrite of LUCENE-8477 vs repeated equal sub-sources: RepeatingIntervalsSource.pullUpDisjunctions, Ordered/UnorderedIntervalsSource.deduplicate) | medium | Intervals.unordered/ordered given the same disjunction twice merge it into one repeated source that the gap-sensitive disjunction rewrite does not look into (RepeatingIntervalsSource.pullUpDisjunctions returns itself), so maxgaps(0, unordered(X, X)) with X = or(b, phrase(c, b)) misses 'c b c b', and maxgaps or phrase over ordered(X, X) miss the same way | 1 |
| LFV-810 | queries / intervals (a whole ordered/unordered of equal sub-sources nested in another operator: RepeatingIntervalsSource width(), Ordered/UnorderedIntervalsSource.deduplicate) | medium | A nested Intervals.ordered(a, a) or unordered(a, a) passes its inner gap up to its parent, so maxgaps(0, ordered(ordered(a, a), a)) misses 'a x a a' while maxgaps(0, ordered(ordered(a, b), a)) matches 'a x b a' | 1 |
| LFV-247 | spatial3d / Geo3DDocValuesField distance sorts (Geo3DPointDistanceComparator, Geo3DPointOutsideDistanceComparator; GeoStandardCircle membership test on the decoded doc value) | medium | Geo3DDocValuesField.newDistanceSort and newOutsideDistanceSort with a maximum radius below about 10 km test each document's 21-bit decoded point, which lies metres off the planet surface, against the circle's nearly tangent plane: about half the documents inside the circle, even at its centre, get distance +Infinity and sort last, documents up to about 8 km away get finite distances, and inside documents get outside distances of up to the radius instead of 0.0 | 1 |
| LFV-701 | core / document: LatLon point geometry queries (LatLonDocValuesQuery CONTAINS on the doc-values path vs LatLonPoint.newGeometryQuery, and their IndexOrDocValuesQuery pairing) | medium | LatLonDocValuesField.newSlowGeometryQuery with CONTAINS and two or more Point geometries matches documents that hold only some of the query points, while its documented IndexOrDocValuesQuery partner LatLonPoint.newGeometryQuery requires all of them | 1 |
| LFV-1132 | core / document: XY distance sort (XYDocValuesField.newDistanceSort, XYPointDistanceComparator) | medium | XY distance sort used as a later Sort key drops closer tied hits, because XYPointDistanceComparator.setBottom keeps an old, too-small bounding box when the bottom grows (a missing-value bottom of +Infinity, or growth after 1024 bottom updates) | 1 |
| LFV-612 | spatial-extras / prefix-tree strategies (NumberRangePrefixTreeStrategy over DateRangePrefixTree or a custom NumberRangePrefixTree; the pointsOnly TermQuery shortcut in RecursivePrefixTreeStrategy.makeGridShapeIntersectsQuery) | medium | NumberRangePrefixTreeStrategy with setPointsOnly(true): an Intersects query for a date or number unit coarser than full precision (a year, month, day, ...) matches no documents | 1 |
| LFV-671 | spatial-extras / spatial4j bridge to spatial3d (Geo3dRectangleShape.getCrossesDateLine), read by PointVectorStrategy and BBoxStrategy | medium | Geo3dRectangleShape.getCrossesDateLine() tests whether a box spans longitude 0 instead of whether it crosses the dateline, so PointVectorStrategy and BBoxStrategy return wrong hits for Geo3d boxes and circles at the dateline or the prime meridian | 1 |
| LFV-673 | spatial-extras / spatial4j bridge to spatial3d (Geo3dShape.relate(Rectangle) and its shared GeoArea-to-SpatialRelation mapping), reached through SpatialOperation IsWithin/Contains on SerializedDVStrategy and CompositeSpatialStrategy, RecursivePrefixTreeStrategy cell traversal over PackedQuadPrefixTree, and any spatial4j relate() against ctx.getWorldBounds() | medium | Geo3dShape.relate(Rectangle) swaps WITHIN and CONTAINS when the rectangle is not a Geo3d shape (such as ctx.getWorldBounds() or a PackedQuadPrefixTree cell), so IsWithin/Contains on stored shapes give the opposite answer and RecursivePrefixTreeStrategy over PackedQuadPrefixTree returns documents far outside the query shape (regression in 7.1.0) | 1 |
| LFV-679 | spatial-extras / spatial4j bridge to spatial3d (Geo3dShapeFactory.pointXYZ and Geo3dPointBuilder.pointXYZ, which the line, polygon, hole and multi-point builders share), reached through the public spatial4j ShapeFactory / PointsBuilder API and spatial4j's GeoJSON reader in the Geo3d spatial context | medium | Geo3dShapeFactory.pointXYZ(x, y, z) and the Geo3d builders' pointXYZ read longitude, latitude and a third value as geocentric Cartesian x, y, z, so 3-coordinate points, lines and multi-points land somewhere else (pointXYZ(30, 10, 0) becomes lon 18.43, lat 0) and polygons with z = 0 are rejected as 'all points are coplanar' (since 7.1.0) | 2 |
| LFV-308 | core / document: shape doc-values queries (BaseShapeDocValuesQuery via SpatialQuery) and the query cache | medium | LatLonShape/XYShape newSlowDocValuesBoxQuery reports Weight#isCacheable() == true although it reads the shape from binary doc values, so after an in-place doc-values update the query cache keeps returning the old matches | 1 |
| LFV-200 | search / phrase queries (SloppyPhraseMatcher Matches support: endPosition/endOffset read after advanceRpts) | medium | For a sloppy PhraseQuery with a repeated term (for example "very very"~1), Weight#matches reports an end position and end offset past the match, at a later occurrence of the repeated term that repeat-collision resolution has already advanced to, so Matches-based highlighting (the default UnifiedHighlighter) marks too much text | 1 |
| LFV-236 | join / block-join and global-ordinals join Weight#matches (ToChildBlockJoinQuery, GlobalOrdinalsWithScoreQuery) | medium | ToChildBlockJoinQuery and JoinUtil's scoring global-ordinals join inherit FilterWeight#matches, so Weight#matches reports the wrapped query's documents instead of the join's hits (child hits lose their highlights, Lucene Monitor's HighlightsMatch matcher reports the wrong documents) | 3 |
| LFV-515 | highlighter / UnifiedHighlighter WEIGHT_MATCHES path (FieldOffsetStrategy field-matcher remap) | medium | UnifiedHighlighter with WEIGHT_MATCHES (the default) and a field matcher that accepts other fields (requireFieldMatch=false) highlights nothing in a hit whose query has a required clause on another field, because the matcher's remap evaluates that clause against the highlighted field's terms | 1 |
| LFV-505 | highlighter / UnifiedHighlighter WEIGHT_MATCHES path (FieldOffsetStrategy, OverlaySingleDocTermsLeafReader) with block-join queries | medium | Default UnifiedHighlighter (WEIGHT_MATCHES) returns no highlights for a block-join hit when the join's inner query uses the highlighted field, because Weight#matches runs on an overlay reader whose highlighted field holds only the hit document | 2 |
| LFV-243 | core / search: MultiTermQuery rewrite methods (DocValuesRewriteMethod, DOC_VALUES_REWRITE) and the Matches API (Weight#matches) | medium | DocValuesRewriteMethod's Weight#matches looks the matched terms up in the postings, so on a doc-values-only field it returns null for every hit of newSlowSetQuery or any DOC_VALUES_REWRITE query (highlights are silently lost, and a MUST_NOT clause of this kind fails open in Weight#matches) | 1 |
| LFV-832 | highlighter / vectorhighlight FieldPhraseList and FieldTermStack (FastVectorHighlighter phrase search over stacked tokens) | medium | FastVectorHighlighter drops a match at a position that holds stacked tokens (index-time synonyms, stems) when the token that sorts first there starts a query phrase that does not continue: FieldPhraseList tries only the first stacked token with any query-map entry, so dogs OR "dog house" on 'my dogs' (synonym dog stacked on dogs) highlights nothing (a LUCENE-5538 regression, 4.7.1 on) | 1 |
| LFV-827 | highlighter / original Highlighter, QueryScorer and WeightedSpanTermExtractor (phrase-to-span conversion) | medium | Classic Highlighter turns the position holes of an exact PhraseQuery or MultiPhraseQuery (for example from removed stop words) into SpanNearQuery slop, so it highlights nearby pairs that do not match and can miss the occurrence that does | 1 |
| LFV-516 | highlighter / UnifiedHighlighter WEIGHT_MATCHES path (FieldOffsetStrategy) with statistics-dependent query rewrites (CommonTermsQuery, MoreLikeThisQuery) | medium | Default UnifiedHighlighter (WEIGHT_MATCHES) rewrites the query again on its own per-leaf or one-document reader, so statistics-dependent queries such as CommonTermsQuery lose their highlights | 2 |
| LFV-150 | search / sorting (TopFieldCollector competitive iterator x DenseConjunctionBulkScorer collectRange shortcut) | medium | Since 10.3.0, a field-sorted top-n search whose query fully matches a segment without deletions (MatchAllDocsQuery, a range covering the segment) no longer skips non-competitive documents: the comparator's initial all-docs competitive iterator reports a run to maxDoc through UpdateableDocIdSetIterator.docIDRunEnd, so DenseConjunctionBulkScorer hands the whole segment to the collector in one collectRange call (performance regression; results correct) | 1 |
| LFV-709 | analysis-smartcn / HHMM segmenter bigram dictionary (BigramDictionary.getBigramItemIndex, AbstractDictionary.hash2; reached through SmartChineseAnalyzer and HMMChineseTokenizer) | medium | smartcn: the double-hashing step of BigramDictionary (AbstractDictionary.hash2, an operator-precedence slip) is 0 for some Chinese word + ASCII or Latin-1 punctuation pairs, so each such bigram lookup re-reads one slot 402,136 times (about 0.7 ms instead of about 0.1 us) and SmartChineseAnalyzer analyzes ordinary prose 2-7x slower and text dense in such pairs 67x-174x slower, with unchanged tokens | 1 |
| LFV-297 | search / rescoring | medium | RescoreTopNQuery throws (AssertionError with -ea, ArrayIndexOutOfBoundsException with -da) instead of matching nothing when its inner query matches no document: rewrite passes an empty top-n list to DocAndScoreQuery.createDocAndScoreQuery, which requires a non-empty one | 1 |
| LFV-815 | search / rescoring (SortRescorer; expressions ExpressionRescorer inherits it) | medium | SortRescorer (and Expression#getRescorer) never rewrites its Sort against the searcher, unlike IndexSearcher#search(Query, int, Sort): sorts that need a rewrite throw, and a legacy query() function sort silently uses the default Similarity | 1 |
| LFV-814 | facet / sorted-search helpers (FacetsCollectorManager static search/searchAfter, DrillSideways sorted search) | medium | FacetsCollectorManager#search/searchAfter with a Sort and DrillSideways#search(..., Sort, ...) never call Sort#rewrite(searcher), so a query-dependent sort returns a different hit order than IndexSearcher#search(query, n, sort) or throws | 1 |
| LFV-816 | grouping / GroupingSearch (convenience API) | medium | GroupingSearch#search never rewrites its group sort or within-group sort against the searcher, unlike IndexSearcher#search(Query, int, Sort): sorts that need a rewrite throw, and a legacy query() function sort silently orders groups, group documents and group heads with the default Similarity | 2 |
| LFV-114 | search / kNN query layer (KnnSearchStrategy.Seeded, optimistic re-entry pass, SeededKnnVectorQuery) | medium | A kNN query built with a null KnnSearchStrategy, documented as 'the default strategy will be used', throws NullPointerException when a seeded HNSW search runs (SeededKnnVectorQuery, or the optimistic re-entry pass when a segment is re-entered) | 3 |
| LFV-041 | queryparser / classic and flexible | medium | An invalid regular expression lets IllegalArgumentException escape QueryParser.parse() and StandardQueryParser.parse() | 1 |
| LFV-217 | join / JoinUtil numeric (point-based) query-time join | medium | JoinUtil's numeric join on Float or Double throws 'values are out of order' when the from side has two or more distinct negative values | 1 |
| LFV-804 | highlighter / UnifiedHighlighter passage scoring (PassageScorer match labels) | medium | UnifiedHighlighter throws MaxBytesLengthExceededException when a TermInSetQuery's toString() is longer than 32766 bytes (for example 886 UUID-like ids), because PassageScorer groups match labels in a BytesRefHash | 1 |
| LFV-806 | queries / intervals (Intervals.atLeast Matches path: MinimumShouldMatchIntervalsSource, CachingMatchesIterator) | medium | Weight#matches of Intervals.atLeast, or iterating the Matches it returns, throws IllegalStateException (AssertionError with -ea) for a matching document once an Intervals.or(...) source has run out of intervals, so default UnifiedHighlighter highlighting of such a query fails | 2 |
| LFV-1097 | core/search / multi-term rewrites (ScoringRewrite with FuzzyQuery boosts) | medium | ScoringRewrite (SCORING_BOOLEAN_REWRITE, CONSTANT_SCORE_BOOLEAN_REWRITE) passes FuzzyQuery's negative per-term boosts to BoostQuery, so a fuzzy query that matches a term shorter than its edit distance throws 'boost must be a positive float'; the classic Highlighter hits it with default settings (cat~ over text containing 'a') (known: #10608 / LUCENE-9568) (released since 8.0) | 1 |
| LFV-824 | highlighter / classic Highlighter (QueryScorer, WeightedSpanTermExtractor term-vector path) | medium | Classic Highlighter throws IllegalStateException for any query that contains a FieldExistsQuery (or a query that rewrites to one, such as an open-ended LongField range) when the token stream comes from term vectors with positions and offsets (regression in 10.5.0 from GITHUB#15678) | 1 |
| LFV-803 | highlighter / UnifiedHighlighter re-analysis offset strategies (MemoryIndexOffsetStrategy, TokenStreamOffsetStrategy) | medium | UnifiedHighlighter's re-analysis offset strategies decode every extracted query term as UTF-8, so a binary term (for example a binary StringField id reached with requireFieldMatch=false) makes highlighting throw | 1 |
| LFV-503 | highlighter / UnifiedHighlighter WEIGHT_MATCHES path (FieldOffsetStrategy) with reader-bound join queries | medium | Default UnifiedHighlighter (WEIGHT_MATCHES) rebuilds the query's Weight on its own single-leaf searcher, so JoinUtil global-ordinals joins throw IllegalStateException and ParentChildrenBlockJoinQuery reads its top-level parent id as a segment-local id | 1 |
| LFV-602 | highlighter / uhighlight + matchhighlight: default offset-source choice on composite readers (core index FieldInfos.getMergedFieldInfos) | medium | UnifiedHighlighter and MatchRegionRetriever throw IllegalArgumentException on a MultiReader whose indexes differ in any field's schema, even only in norms or in an unrelated field, because FieldInfos.getMergedFieldInfos applies the single-index consistency check across the indexes | 2 |
| LFV-349 | monitor / presearcher query analysis (QueryAnalyzer, QueryTree; default TermFilteredPresearcher) | medium | Monitor.register throws IllegalArgumentException 'Cannot build a conjunction (or disjunction) with no children' for a legal query, or a part of one, that reports no terms to the query visitor (an empty TermInSetQuery, an inverted TermRangeQuery, RegexpQuery '#', a term-less PhraseQuery or SynonymQuery), and the other queries of that commit chunk are not registered either | 1 |
| LFV-483 | analysis / analysis-common miscellaneous filters (DateRecognizerFilterFactory, DateRecognizerFilter) | medium | DateRecognizerFilterFactory gives every filter it creates the same java.text.DateFormat, so an analyzer built from it throws NumberFormatException or ArrayIndexOutOfBoundsException when several threads analyse text at the same time | 1 |
| LFV-526 | analysis-common / pattern tokenizers (SimplePatternTokenizer String constructors) | medium | SimplePatternTokenizer's String constructors do not determinize the regexp (and ignore determinizeWorkLimit), so valid patterns such as ab|ac or http|https throw 'please determinize the incoming automaton first' | 1 |
| LFV-527 | facet / SortedSetDocValues faceting (AbstractSortedSetDocValueFacetCounts#prepareChildIteration, shared by SortedSetDocValuesFacetCounts and ConcurrentSortedSetDocValuesFacetCounts) | medium | SortedSetDocValues faceting throws NullPointerException from getTopChildren/getAllChildren for a dimension that is configured hierarchical but has no document in the reader, instead of returning null as the Facets javadoc says (regression since 9.3.0) | 1 |
| LFV-725 | facet / DrillSideways (default buildFacetsResult for the mixed TaxonomyReader + SortedSetDocValuesReaderState constructors) | medium | DrillSideways built with both a TaxonomyReader and a SortedSetDocValuesReaderState (the constructors documented for indexes that mix FacetField and SortedSetDocValuesFacetField dimensions) never counts the SortedSetDocValues dimensions, because the default buildFacetsResult ignores the state whenever taxoReader != null (every release since 4.7.0) | 1 |
| LFV-662 | suggest / FreeTextSuggester (n-gram model built with ShingleFilter; lookup context counts after analysis holes) | medium | FreeTextSuggester.lookup throws AssertionError (-ea) or NullPointerException (-da) when a word the analyzer removed (a stop word) comes right before the key's last word, because it reads the count of the filler-only context '_', which the n-gram model never stores (lookup('the w') with the default constructor and EnglishAnalyzer) | 1 |
| LFV-704 | queryparser / complexPhrase: ComplexPhraseQueryParser (ComplexPhraseQuery.rewrite building a SpanNearQuery) | medium | ComplexPhraseQueryParser: a phrase whose contents reduce to one clause that is not a bare term or multi-term query ("the beat*" with a stop-word analyzer, "+john", "john^2") parses, but searching it throws IllegalArgumentException instead of returning hits | 1 |
| LFV-758 | search / vector queries (KnnFloat/Byte/Float16VectorQuery, Float/Byte/Float16VectorSimilarityQuery; join DiversifyingChildren*KnnVectorQuery) | medium | kNN and vector-similarity query constructors keep the caller's query-vector array instead of copying it, so a caller that refills that buffer before the query runs silently changes which documents the query matches and what it is equal to | 2 |
| LFV-330 | memory / MemoryIndex stored fields | medium | MemoryIndex stores binaryValue() instead of IndexableField.storedValue(), so stored StringField/KeywordField values built from a String and stored IntField/LongField/FloatField/DoubleField values come back as binary bytes (Document.get and numericValue() return null), and a StoredField built from a StoredFieldDataInput is dropped (released since 9.6.0) | 1 |
| LFV-105 | index / indexing chain (single-term BINARY inversion, norms) | medium | IndexingChain.invertTerm adds 2 to the field length for each single-term (InvertableType.BINARY) value, so untokenized DOCS_AND_FREQS fields with norms get double the norm and a lower BM25 score | 1 |
| LFV-333 | memory / MemoryIndex term inversion (custom term frequencies: FeatureField, TermFrequencyAttribute streams, DOCS_AND_CUSTOM_FREQS); reached in-tree through monitor single-document batches | medium | MemoryIndex ignores TermFrequencyAttribute, so FeatureField values and custom term frequencies are indexed as frequency 1 and their postings frequencies, term statistics, norms and scores differ from IndexWriter's (Lucene Monitor's single-document matching included) | 1 |
| LFV-340 | memory / MemoryIndex term inversion (multi-valued analyzed fields: positions and offsets carried from one value to the next); reached in-tree through monitor single-document batches | medium | MemoryIndex drops the final position increment of each value of a multi-valued field (and the gaps after leading values with no tokens), so phrase and other position queries disagree with IndexWriter, including Lucene Monitor's single-document matching | 1 |
| LFV-344 | memory / MemoryIndex lazy per-field read state (sorted terms, points and doc-values preparation, norms) | medium | An unfrozen MemoryIndex does not reset its lazily built per-field state when more values are added to a field after a read, so later searches miss the new terms or points, throw ArrayIndexOutOfBoundsException, return unsorted SORTED_NUMERIC values or score with stale norms | 1 |
| LFV-1112 | memory / MemoryIndex doc values (addField and fromDocument: BINARY and SORTED value storage) | medium | MemoryIndex keeps a SORTED or BINARY doc value as a shallow BytesRef clone of the caller's bytes, so if the caller later overwrites its byte array the value the MemoryIndex reports silently changes (regression of LUCENE-10405, since 9.1.0) | 1 |
| LFV-342 | memory / MemoryIndex field schema (FieldInfo built once from the first IndexableField of a name: omitNorms and norms); reached in-tree through monitor single-document batches | medium | MemoryIndex takes omitNorms from the first instance of a field name, so a doc-values or stored-only instance added first gives an omitNorms text or keyword field norms and different scores than IndexWriter | 1 |
| LFV-175 | index / stored fields (StoredFieldDataInput: DataInput-backed StoredField values, #14213) | medium | StoredFieldDataInput(ByteArrayDataInput) takes the input's end position as its length, so a ByteArrayDataInput that does not start at position 0 (a slice at a non-zero offset, or a partly read input) silently stores extra trailing bytes, or makes addDocument fail and close IndexWriter | 1 |
| LFV-766 | join / JoinUtil query-time join (single-valued term and numeric collectors) | medium | JoinUtil's single-valued term and numeric joins treat a 'from' document without a join value as if it had the empty term or the number 0, so they also return the 'to' document whose key is empty or 0 and add the value-less documents' scores to it (since 4.0.0) | 1 |
| LFV-1111 | join / JoinUtil numeric (point-based) query-time join: multi-valued Float/Double decode of core DoubleField/FloatField doc values | medium | JoinUtil's numeric join reads a DoubleField or FloatField from field as raw IEEE bits, so a join on a negative value silently misses its matches | 1 |
| LFV-1106 | join / JoinUtil term join (TermsIncludingScoreQuery, TermsQuery) | medium | A scoring JoinUtil term join re-sorts its shared BytesRefHash on every non-scoring createWeight, so one join query used by a scoring search and a count() at the same time silently returns too few hits (known: #13018 / open PR #13019, partial overlap) (released since 10.5.0) | 1 |
| LFV-410 | join / JoinUtil numeric score join (PointInSetIncludingScoreQuery createWeight boost) | medium | JoinUtil numeric score joins (PointInSetIncludingScoreQuery, ScoreMode Max, Min, Avg or Total) ignore the boost, so BoostQuery, boosted BooleanQuery clauses and BooleanQuery's folding of duplicate clauses leave their scores unchanged; the part of GITHUB#12388 that was left out | 1 |
| LFV-470 | queries / payloads (PayloadScoreQuery scoring with includeSpanScore=false) | medium | PayloadScoreQuery built with includeSpanScore=false ignores every positive query boost (BoostQuery, boosted BooleanQuery clauses, boosts propagated by parent queries): the score stays the bare payload function value, so the clause gets the wrong weight and ranking | 1 |
| LFV-218 | join / block join (ParentsChildrenBlockJoinQuery#rewrite, custom scoreCombiner) | medium | ParentsChildrenBlockJoinQuery.rewrite() drops a custom scoreCombiner, so hits are silently scored parent + child whenever the parent or child query rewrites | 1 |
| LFV-279 | queries / span queries (SpanNotQuery: the exclusion filter in SpanNotWeight#getSpans) | medium | SpanNotQuery with a negative post (or dist) drops every include span that follows the last exclude span in a document, because NO_MORE_POSITIONS - post overflows int | 1 |
| LFV-409 | queries / function queries (the ValueSource.fromDoubleValuesSource bridge: its FunctionValues inherits the float default FunctionValues.getRangeScorer that FunctionRangeQuery calls) | medium | FunctionRangeQuery over ValueSource.fromDoubleValuesSource(...) compares bounds and values as floats, not doubles, so double and long ranges silently gain or lose hits near a bound and beyond Float.MAX_VALUE | 1 |
| LFV-770 | core / search value sources (DoubleValuesSource, LongValuesSource adapters) | medium | DoubleValuesSource#toSortableLongDoubleValuesSource() loses its NumericUtils.doubleToSortableLong encoding when rewritten (rewrite() returns the plain toLongValuesSource() cast adapter), so values read after the documented rewrite step, and sorts on it through IndexSearcher, use (long) casts instead | 1 |
| LFV-641 | analysis / hunspell (Stemmer affix stripping: Hunspell.spell, getRoots, analyzeSimpleWord, Stemmer.stem, HunspellStemFilter; WordFormGenerator.getAllWordForms) | medium | Hunspell rejects, cannot stem and does not generate twofold-suffix words (a second suffix allowed by the first suffix's continuation class) when either suffix class has cross product N, although cross product only governs prefix+suffix combinations: with 'SFX S 0 st/E', 'SFX E N 2' (en, e) and raich/SE, spell("raichsten") is false; the real Luxembourgish dictionary rejects räichsten | 1 |
| LFV-100 | codecs / quantized vector formats merge (Lucene104 OSQ, Lucene102 BBQ) with index / SortingCodecReader | medium | Quantized vector merge asks every source reader for a field's vectors without checking that reader's FieldInfos, so re-sorting with SortingCodecReader and addIndexes fails with NullPointerException (AssertionError with -ea) when one segment lacks one of several vector fields | 1 |
| LFV-269 | index / merged CodecReader view (SlowCompositeCodecReaderWrapper vector values); misc / BP merge-time reordering | medium | The merged vector values of SlowCompositeCodecReaderWrapper throw NullPointerException from copy() when one merged segment has no vectors for the field, so merges through BPReorderingMergePolicy with BpVectorReorderer fail and close the IndexWriter, again after every reopen | 1 |
| LFV-128 | store / MMapDirectory (MemorySegmentIndexInput clone, slice and close) | medium | Closing a clone or full-length slice of a multi-chunk MMapDirectory input nulls the MemorySegment[] it shares with the original and other clones, which then fail with NullPointerException | 2 |
| LFV-492 | store / BufferedIndexInput (NIOFSDirectory, misc RAFDirectory, BufferedIndexInput.wrap; surfaces through CodecUtil.checkFooter and stored-fields reads) | medium | BufferedIndexInput.refill marks its buffer as filled before readInternal succeeds, so after a failed read the next reads of the same input return up to one buffer of stale bytes instead of re-reading or throwing (regression of LUCENE-1262 since 8.6.0) | 3 |
| LFV-346 | analysis / kuromoji (JapaneseCompletionFilter and JapaneseCompletionAnalyzer romanization, KatakanaRomanizer) | medium | JapaneseCompletionFilter expands a reading into every combination of romaji spellings with no bound, so 24-32 kana (for example 32 x "ン", or 32 x "し" in QUERY mode) throw OutOfMemoryError inside one incrementToken() call | 1 |
| LFV-644 | index / IndexWriter deletes (deleteDocuments, DocumentsWriterDeleteQueue array nodes, per-thread delete slices) | low | IndexWriter.deleteDocuments(Term...) and deleteDocuments(Query...) keep the caller's array without copying it, so documents still buffered in RAM are deleted by whatever the array holds when the per-thread writer later applies the delete (at its next addDocument or flush): a caller that refills or clears its array after the call returned keeps documents it deleted and deletes documents no call named, silently and also after commit (since 4.0.0) | 1 |
| LFV-010 | index / soft deletes | low | A try* un-delete or pending soft-delete change is ignored or lost by later term-based operations | 1 |
| LFV-014 | index / addIndexes | low | addIndexes publishes segments outside the full-flush boundary, breaking sequence-number ordering | 1 |
| LFV-359 | queryparser / SimpleQueryParser (near operator: consumePhrase phrase slop) | low | SimpleQueryParser drops the '+', '|', quote or '(' typed directly after a phrase slop, so "a b"~2+c parses as phrase OR c and "a b"~2|c (default operator AND) as phrase AND c | 1 |
| LFV-560 | queryparser / flexible StandardQueryParser (processor pipeline order: WildcardQueryNodeProcessor runs before MultiFieldQueryNodeProcessor) | low | StandardQueryParser with setMultiFields normalizes field-less prefix and wildcard terms with field null, before the multi-field expansion, so per-field analyzers are ignored for them (and a PerFieldAnalyzerWrapper over Map.of throws NullPointerException) | 1 |
| LFV-828 | queries / intervals (overlap filters Intervals.overlapping / nonOverlapping / notWithin vs the LUCENE-8477 disjunction rewrite that containedBy and within apply to their reference) | low | Intervals.overlapping, nonOverlapping and notWithin read a disjunctive reference through the minimized or(), while containedBy and within test every alternative, so for the reference or(york, "new york") the same interval is reported both within and not within n positions of it, and containedBy(new, ref) matches 'new york' where overlapping(new, ref) does not | 1 |
| LFV-909 | queries / span queries (per-document lockstep of the ContainSpans subclasses in SpanContainingQuery and SpanWithinQuery) | low | SpanContainingQuery and SpanWithinQuery miss documents and spans when the little query's spans end out of order (for example a SpanOrQuery of a longer near clause and a shorter clause that can occur inside it): their single forward pass tests only the current little span (containing) or never goes back to a big span it skipped (within), so a later, shorter little span inside a big span is never tried | 1 |
| LFV-1171 | core / search: FuzzyQuery and FuzzyTermsEnum (Levenshtein pattern built from Term.text()) | low | FuzzyQuery with maxEdits >= 1 on a term whose bytes are not valid UTF-8 builds its automaton from the hex display string of Term.text(), so it misses the identical term and matches terms near "[ff 61 62 63]" instead | 1 |
| LFV-248 | suggest / analyzing suggester (AnalyzingSuggester.build, inherited by FuzzySuggester) | low | AnalyzingSuggester and FuzzySuggester count skipped duplicate copies of a surface form toward maxSurfaceFormsPerAnalyzedForm, so distinct lower-weighted surface forms are silently dropped | 1 |
| LFV-1052 | util / FST (Util.TopNSearcher.search, 'Empty string!' branch) and suggest / FreeTextSuggester (lookup's per-level seen-token filter) | low | Util.TopNSearcher returns a queued final output without calling acceptResult, so FreeTextSuggester spends a top-N slot on a word it already predicted and drops a better suggestion | 1 |
| LFV-523 | analysis / TokenStreamToAutomaton (core), reached through ConcatenateGraphFilter (analysis-common) and the completion suggesters (suggest: NRT document suggester, AnalyzingSuggester, FuzzySuggester) | low | A zero-length token makes TokenStreamToAutomaton drop every path through it, so ConcatenateGraphFilter emits nothing and the document suggester, AnalyzingSuggester and FuzzySuggester silently lose that suggestion (stock trigger: a standalone tatweel U+0640 with ArabicAnalyzer, PersianAnalyzer or SoraniAnalyzer) | 1 |
| LFV-1118 | analysis-common / ConcatenateGraphFilter no-separator mode, and core / util.automaton (Automaton.addEpsilon); reached from suggest (CompletionAnalyzer preserveSep=false, document suggester) | low | ConcatenateGraphFilter without a token separator (and so CompletionAnalyzer with preserveSep=false) silently drops a concatenated path around a position hole, because Automaton.addEpsilon copies from a dest state that its own first addTransition sorts and reduces in place (AssertionError with -ea) | 1 |
| LFV-798 | suggest / document (NRT) suggester (SuggestField's raw-value reserved-character check vs. the analyzed form that CompletionTokenStream passes to NRTSuggesterBuilder's FST encoding) | low | The document suggester checks its reserved end byte U+0000 only in the raw SuggestField value, not in the analyzed form, so an analyzer that emits U+0000 (for example HTMLStripCharFilter decoding '�') hides another document's suggestion or its own and adds FST inputs out of order at flush (with assertions enabled the IndexWriter closes) | 1 |
| LFV-699 | suggest / ternary search tree suggester persistence (TSTLookup.store and load, writeRecursively and readRecursively) | low | TSTLookup.store/load writes each tree node's split char with DataOutput.writeString, so the two surrogate halves of an emoji or CJK Extension B character come back as U+FFFD: after load(), get() and lookups whose prefix runs through such a character silently find nothing, and some neighbouring BMP keys are lost too (every release since 4.7.0) | 1 |
| LFV-744 | search / similarities (IndriDirichletSimilarity constructors and the LMSimilarity collection model) | low | IndriDirichletSimilarity(float mu) uses LMSimilarity's default (cf+1)/(|C|+1) collection model instead of IndriCollectionModel (cf/|C|), so new IndriDirichletSimilarity(2000f) scores differently from new IndriDirichletSimilarity() although both print the same name | 1 |
| LFV-332 | monitor / query index updates (WritableQueryIndex.commitWithoutNotify and populateQueryCache, reached through both Monitor.register overloads and ConcurrentQueryLoader) | low | Monitor.register with the same query id twice in one call keeps both versions in the query index, so the query matches a mix of both versions, and after a reopen a persistent Monitor runs the older version while getQuery returns the newer one | 1 |
| LFV-499 | monitor / query index updates (WritableQueryIndex.commitWithoutNotify failure atomicity, reached through both Monitor.register overloads) | low | A Monitor.register call that IndexWriter rejects is not rolled back: the earlier versions of the queries in the call are deleted at the next commit or close(), and until then getQuery() and match() disagree | 1 |
| LFV-501 | monitor / query index updates (WritableQueryIndex.deleteQueries and clear versus commitWithoutNotify, reached through Monitor.deleteById, Monitor.clear and Monitor.register) | low | Monitor.deleteById and Monitor.clear issue their IndexWriter delete outside the commit lock, so a delete or clear that runs while register is indexing a decomposed query leaves that query partly indexed: it stays registered but silently stops matching what its deleted parts match, also after a reopen | 1 |
| LFV-779 | index / index sorting at merge time (IndexSorter.IntSorter merge keys, MultiSorter) -> search / TopFieldCollector index-sort early termination | low | With an INT index sort, merges order documents by the full 64-bit doc value while flush, sorted search and CheckIndex use its low 32 bits, so merging a value outside the int range writes a segment that violates its declared index sort (CheckIndex at level 2 or higher rejects it) and sorted searches that terminate early on the index sort return wrong top hits (a regression in 8.2.0) | 1 |
| LFV-1037 | search / sorting (SortField STRING_VAL, SortedSetSortField and KeywordField.newSortField missing values; index sorting) | low | SortField(STRING_VAL), SortedSetSortField and KeywordField.newSortField accept a missing value other than STRING_FIRST/STRING_LAST and silently treat it as STRING_FIRST; as an index sort the value is lost when the segment is written, so a new IndexWriter with the same config refuses the index ('cannot change previous indexSort') | 1 |
| LFV-1141 | core / kNN vector queries (COSINE) | low | kNN and vector-similarity queries accept an all-zero query target on a COSINE field, which the field itself rejects; the cosine is NaN, so the search returns no hits or the HNSW entry document with score NaN, with no error | 1 |
| LFV-467 | search / vector similarity-threshold queries (ExplicitVectorSimilarityCollector with the exhaustive scan and the HNSW graph search) | low | FloatVectorSimilarityQuery and ByteVectorSimilarityQuery with traversalSimilarity == resultSimilarity (the 3- and 4-argument constructors: the plain ones in 9.10.0-10.4.0, the deprecated Explicit classes in 10.5.2 and main) silently drop documents whose similarity is exactly resultSimilarity, because the collector's minCompetitiveSimilarity() rises to the inclusive threshold and every searcher treats an equal score as not competitive | 1 |
| LFV-429 | index / IndexWriter merge-time reordering (OneMerge#reorder guard; misc BPReorderingMergePolicy) | low | Reordering merges (BPReorderingMergePolicy) silently break document blocks written before Lucene 9.9, because IndexWriter's reorder guard reads the unrecorded LeafMetaData#hasBlocks flag as 'no blocks' | 1 |
| LFV-471 | index / IndexWriter sequence numbers (tryDeleteDocument, tryUpdateDocValue vs commit) | low | tryDeleteDocument / tryUpdateDocValue running while commit() flushes returns a sequence number above the commit's, yet its change is in that commit | 1 |
| LFV-590 | index / IndexWriter forced merge (forceMerge wait loop, mergeExceptions and mergeGen, tragic events) | low | IndexWriter.forceMerge(n) can return normally with more than n segments when a merge that was already pending or running at the call fails: forceMerge adopts that merge without updating its mergeGen, so addMergeException drops the failure, and the tragic event is published only after mergeFinish has woken the waiting forceMerge | 1 |
| LFV-838 | index / IndexWriter doc-values updates (BinaryDocValuesFieldUpdates value buffer, FrozenBufferedUpdates apply, applyUpdatesPacket tragic close) | low | A binary doc-values update whose term matches many documents copies its value once per matched document into one int-sized buffer when it is applied, so at 2^31 bytes in one segment (about 2^30 for the first update of a field in a packet) commit throws ArrayIndexOutOfBoundsException (AssertionError with -ea) and IndexWriter closes itself, losing the update and every uncommitted document (every release since 4.8.0) | 2 |
| LFV-1077 | index / IndexWriter delete queue (DeleteSlice of an idle DocumentsWriterPerThread, flush-by-RAM on pure deletes) | low | While a document sits buffered in an idle in-memory segment, IndexWriter keeps every later delete and doc-values update reachable, uncounted by ramBytesUsed() and never released by the RAM buffer, so a delete-only or update-only stream grows the heap until OutOfMemoryError (default config, since 4.0.0) | 1 |
| LFV-981 | core / index (ParallelLeafReader and ParallelCompositeReader index-sort metadata, LeafMetaData.sort; consumers: TopFieldCollector early termination, Sort.getPrimarySortField range shortcuts, IndexWriter.addIndexes(CodecReader...)) | low | ParallelLeafReader and ParallelCompositeReader advertise a sub-reader's index sort even when an earlier, unsorted sub-reader serves the sort field, so sorted searches and index-sort range shortcuts return wrong hits and IndexWriter.addIndexes writes a segment that breaks its declared index sort | 1 |
| LFV-1114 | core / index (ParallelCompositeReader.prepareLeafReaders: per-leaf field ownership through ParallelLeafReader's 'first reader having a given field wins' rule) | low | ParallelCompositeReader picks a field's owner separately in each segment, so when two parallel indexes share a field, the later index's values show through in segments where the earlier index has no document with that field, and hits change after a merge | 1 |
| LFV-445 | analysis / ICU (ICUTokenizer chunked buffer refill; ICUTokenizerFactory 'icu') | low | ICUTokenizer loses a supplementary character (an emoji, a CJK Extension B ideograph) whose surrogate pair straddles the end of its 4096-char read chunk in text with no whitespace, because refill() cuts the pair in half | 1 |
| LFV-659 | analysis / ICU (ICUTokenizer rule status: Default.rbbi WB3c chain, BreakIteratorWrapper emoji status, status-0 skip) | low | ICUTokenizer silently drops a word that is directly followed by ZERO WIDTH JOINER and an emoji, together with the emoji, because the joined 'word ZWJ emoji' segment gets rule status 0 (UAX #29 WB3c chain in Default.rbbi) and the emoji check looks only at its first code point | 1 |
| LFV-653 | analysis / ICU (DefaultICUTokenizerConfig break rules Default.rbbi / Default.brk, used for CJK text when cjkAsWords=false; ICUTokenizerFactory 'icu' with cjkAsWords="false") | low | ICUTokenizer with cjkAsWords=false silently drops the Japanese iteration mark 々 (U+3005), as in 人々, 時々 and 様々, and the other Han-script letters that are not Ideographic (U+303B, U+16FE3), because Default.rbbi gives them rule status 0 | 1 |
| LFV-665 | analysis-common / Arabic light stemmer (ArabicStemmer.stemPrefix; ArabicStemFilter, ArabicAnalyzer and the 'arabicStem' factory) | low | ArabicStemmer removes at most one prefix, so after it strips the conjunction waw it never strips the article that follows (wa+bi-al-, wa+li-l-, wa+ka-al-, wa+fa-al-), unlike the light10 algorithm ArabicAnalyzer documents | 1 |
| LFV-667 | analysis-common / Bengali normalizer (BengaliNormalizer.normalize; BengaliNormalizationFilter, BengaliAnalyzer and the 'bengaliNormalization' factory) | low | BengaliNormalizer's khio rule tests U+09BF (vowel sign I) instead of U+09B7 (SSA), so the common conjunct ক্ষ (KA+HASANTA+SSA) is never folded to KHA / KA+KHA as the rule comment and the cited paper say, and the malformed KA+HASANTA+VOWEL SIGN I is folded instead | 1 |
| LFV-676 | analysis-common / Bengali normalizer (BengaliNormalizer.normalize; BengaliNormalizationFilter, BengaliAnalyzer and the 'bengaliNormalization' factory) | low | BengaliNormalizer's medial-visarga rule copies the next character before that character is folded, so SHA, SSA, NNA (and the other one-to-one folded letters) survive after a visarga and those spellings stop matching the SA/NA spelling the same normalizer conflates everywhere else | 1 |
| LFV-734 | analysis / StandardTokenizer JFlex word rule (the <ALPHANUM> rule of core StandardTokenizerImpl.jflex; the same rule in analysis-common UAX29URLEmailTokenizerImpl.jflex) | low | StandardTokenizer (StandardAnalyzer's tokenizer) and UAX29URLEmailTokenizer misapply the UAX #29 Hebrew quote rules WB7a-WB7c next to other word characters: a Hebrew letter + ASCII apostrophe swallows a following digit or underscore (BET'2 is one term), an ASCII apostrophe after a Hebrew letter that ends a mid-word chain is dropped (HE.SHIN' -> HE.SHIN), and a word with an ASCII quotation mark between Hebrew letters is split when it also contains a mid-word '.', ':' or quote (ALEF.TSADI"LAMED, TAV"ALEF.BET) | 1 |
| LFV-818 | analysis-common / ASCIIFoldingFilter mapping table (foldToASCII switch) | low | ASCIIFoldingFilter folds six letters to the ASCII letter of the opposite case (ǥ U+01E5 and ǧ U+01E7 to 'G', insular ꞅ U+A785 to 'S' and Ꞅ U+A784 to 's', Ɐ U+2C6F to 'a', Ꜿ U+A73E to 'c'; stretched ʗ U+0297 to 'C' is contested), so a LowerCaseFilter-then-ASCIIFoldingFilter chain indexes 'naǧib' as 'naGib' and the ASCII query 'nagib' finds nothing | 1 |
| LFV-565 | analysis-smartcn / language analyzers (SmartChineseAnalyzer normalization: Analyzer#normalize vs the width and case folding inside HMMChineseTokenizer's SegTokenFilter, used by the query parsers for multi-term queries) | low | SmartChineseAnalyzer.normalize only lower-cases, but indexing folds full-width Latin letters and digits to half-width (in the tokenizer's SegTokenFilter), so full-width prefix, wildcard, regexp, range and fuzzy terms from the query parsers miss documents that the same word as a term query finds | 1 |
| LFV-317 | analysis / HTMLStripCharFilter (JFlex grammar: SingleQuoted, DoubleQuoted, OpenTagAttribute, EventAttribute) | low | HTMLStripCharFilter reads a backslash right before a quoted attribute value's closing quote as an escaped quote, so the tag runs on to the next quote of the same kind and the visible text in between is dropped (every quoted attribute since 9.9.0 / GITHUB#11724; on* event attributes since the 2012 JFlex rewrite) | 1 |
| LFV-708 | analysis-common / wikipedia: WikipediaTokenizer (JFlex grammar lexical states, WikipediaTokenizerImpl.jflex) | low | WikipediaTokenizer silently drops Chinese and Japanese text inside wiki markup (links, categories, headings, bold/italics, templates, citations, external-link labels): its grammar has a CJ token rule only for plain text, and every markup state matches ALPHANUM only | 1 |
| LFV-1096 | analysis / kuromoji and nori number filters (stacked tokens inside a number) | low | JapaneseNumberFilter and KoreanNumberFilter, meeting a stacked token after two or more numerals, drop the numerals after the first and keep the first one's text in the number buffer, where it is prepended to the next number (十一石二鳥と五 ends in 15 instead of 5) (known: #11398 / #11397, offsets only) (released since 6.0.0 / 8.2.0) | 1 |
| LFV-360 | analysis / kuromoji and nori number filters (JapaneseNumberFilter, KoreanNumberFilter: KeywordAttribute inside a number composition) | low | JapaneseNumberFilter and KoreanNumberFilter honour KeywordAttribute only on the token that starts a number, so a keyword-protected numeral word directly after a numeral token is merged into the number and normalized (三 + protected 京一 gives 30000000000000001, the name 오경일 with 경일 protected gives 50000000000000001) (released since 6.0.0 / 8.2.0) | 1 |
| LFV-651 | analysis / TeeSinkTokenFilter (SinkTokenStream replay through AttributeSource.restoreState without clearAttributes(): attributes that only the sink's chain adds) | low | TeeSinkTokenFilter: a sink never clears attributes that only its own filter chain adds (SinkTokenStream.incrementToken() calls restoreState() without clearAttributes()), so a keyword marker or StemmerOverrideFilter before a stemmer on a sink silently leaves every token after the first protected word unstemmed | 1 |
| LFV-654 | analysis / nori UserDictionary (right context id of user nouns, used by the Viterbi connection costs) | low | Nori UserDictionary picks a user noun's right context id (last syllable with a final consonant, without one, or not Hangul) from the last character of the whole entry line instead of the noun, so a trailing space or an inline comment ('학교 # memo') changes how the word after the noun is analysed | 1 |
| LFV-855 | analysis / icu (ICUFoldingFilter UTR#30 folding data: the hand-written 'Rule: verbatim' Cyrillic block of DiacriticFolding.txt, compiled into utr30.nrm) | low | ICUFoldingFilter folds the Tajik/Abkhaz letter CHE WITH DESCENDER (ҷ U+04B7, Ҷ U+04B6) to the different letter ABKHASIAN CHE (ҽ U+04BD) instead of to CHE (ч U+0447), so Tajik text is not found by the same words typed with plain ч | 1 |
| LFV-668 | analysis-common / Sorani normalizer (SoraniNormalizer.normalize; SoraniNormalizationFilter, SoraniAnalyzer and the 'soraniNormalization' factory) | low | SoraniNormalizer checks for a word-final HEH before it removes trailing directional marks, so a word ending in HEH followed by RLM, LRM or ALM keeps HEH (U+0647) instead of becoming AE (U+06D5) as the class javadoc says | 1 |
| LFV-046 | codecs / vectors | low | COSINE vectors whose float32 squared norm underflows pass validation and give Inf/NaN scores or poison OSQ segments | 1 |
| LFV-579 | codecs / vectors writers (Lucene99HnswVectorsWriter and Lucene104ScalarQuantizedVectorsWriter field writers over a flat field writer; columnar addBatch DENSE vector bulk path) | low | When IndexWriter#addBatch rejects a vector part-way through a DENSE vector column, the core HNSW and scalar-quantized vectors writers fall out of step with a flat field writer that keeps the default addDenseValues (new in #16734): the next commit closes the IndexWriter, or with assertions off commits a corrupt HNSW graph or misaligned COSINE quantization state | 1 |
| LFV-521 | facet / taxonomy writer (DirectoryTaxonomyWriter.addCategory exception safety: cacheIsComplete and reader-manager freshness after a failed near-real-time reader open) | low | DirectoryTaxonomyWriter gives an existing category a second ordinal after an addCategory call fails with an IOException while the writer opens its near-real-time reader, because the cache stays marked complete or the reader stays stale | 1 |
| LFV-978 | facet / taxonomy writer (DirectoryTaxonomyWriter.replaceTaxonomy failure path: deleteAll before addIndexes, writer state reset only on success) | low | DirectoryTaxonomyWriter.replaceTaxonomy is not failure-atomic: if addIndexes throws, the taxonomy is already emptied but the writer keeps its old ordinal counter and cache, so later addCategory calls and the next commit or close() store an empty or broken taxonomy | 1 |
| LFV-617 | core index / UpgradeIndexMergePolicy and IndexUpgrader with OneMergeWrappingMergePolicy delegates (SoftDeletesRetentionMergePolicy) | low | UpgradeIndexMergePolicy rewrites the old segments its delegate declines with its own plain OneMerge, which a wrapping delegate never sees, so IndexUpgrader (or UpgradeIndexMergePolicy) with a SoftDeletesRetentionMergePolicy inside silently purges the soft-deleted documents the retention policy must keep | 1 |
| LFV-520 | facet / taxonomy writer (DirectoryTaxonomyWriter.addCategoryDocument with the ordinal-document enrichment hook: ReindexingEnrichedDirectoryTaxonomyWriter / enrichOrdinalDocument) | low | DirectoryTaxonomyWriter gives every later category a wrong ordinal after IndexWriter rejects one enriched ordinal document: the rejected document keeps its docID but the writer's ordinal counter does not advance | 1 |
| LFV-977 | facet / taxonomy (ReindexingEnrichedDirectoryTaxonomyWriter.reindexWithNewOrdinalData) | low | ReindexingEnrichedDirectoryTaxonomyWriter.reindexWithNewOrdinalData is not failure-atomic: when the ordinal-data appender throws part-way, the taxonomy has already been deleted and only partly re-added, and a following close() commits it, so main-index ordinals lose their labels or are handed to other categories | 1 |
| LFV-244 | core / codecs: term vectors (TermVectorsWriter.addAllDocVectors merge copier; Lucene90 compressing term-vector writer and reader), reached through IndexWriter.addIndexes(CodecReader) | low | addIndexes(CodecReader) from a reader whose term vectors list a field with zero terms writes a term-vector chunk that the default codec cannot read back, and every later merge that re-encodes the segment closes the IndexWriter | 1 |
| LFV-760 | index / index sorting (IndexingChain index-sort field validation and flush-time sort) | low | With an index sort, a document whose sort field is indexed without doc values (for example only as a StringField) is accepted by addDocument, and the next flush throws IllegalStateException and closes the IndexWriter, losing every uncommitted document (since 8.6.0) | 1 |
| LFV-787 | suggest / document suggester (CompletionFieldsConsumer type check at flush and merge; core flush and merge abort paths) | low | Mixing SuggestField and ContextSuggestField under one field name is accepted by addDocument and rejected only when the completion postings are written at flush or merge, where the IllegalArgumentException is tragic: the IndexWriter closes and loses every uncommitted document, and two cleanly committed segments of the two types make every merge that combines them close the writer again, also in a new writer (released since 5.3.0) | 1 |
| LFV-759 | index / IndexWriter doc-values updates with index sorting (BinarySortField, custom IndexSorter) | low | IndexWriter accepts doc-values updates of a field that a custom index-sort key reads (such as a BinarySortField subclass that derives its key from another doc-values field), so the segment keeps its old order while still declaring the index sort: CheckIndex rejects it, sorted searches that terminate early return wrong top hits, and merges carry the disorder forward | 1 |
| LFV-726 | index / IndexWriter addIndexes(CodecReader...) accounting (reserveDocs, addIndexesReaderMerge soft-delete count) x MergePolicy#findMerges(CodecReader...) / OneMerge#wrapForMerge | low | addIndexes(CodecReader...) takes the reserved document count and the new segment's soft-delete count from the readers before OneMerge#wrapForMerge, so a merge whose wrapper removes documents over-reserves documents and, with soft deletes, commits a wrong soft-delete count that can drop live documents or corrupt a later merge (since 9.9.0) | 1 |
| LFV-151 | facet / range and range-on-range facet counts (FacetResult.value with a fastMatchQuery) | low | Range facet counters add every hit the fastMatchQuery rejects to FacetResult.value, so the dimension total is too high and depends on the segment layout | 1 |
| LFV-727 | facet / taxonomy facets (TaxonomyFacets#getTopChildrenForPath and #getAllChildren: FacetResult.value of a sub-path; FastTaxonomyFacetCounts, TaxonomyFacetFloatAssociations with a DoubleValuesSource) | low | Taxonomy facets: for a sub-path of a single-valued hierarchical dimension, FacetResult.value from getTopChildren/getAllChildren is the sum of the children, so documents labeled at the sub-path itself are left out, while getSpecificValue, drill-down and SortedSetDocValues faceting count them | 1 |
| LFV-1104 | facet / taxonomy facets getTopDims (TaxonomyFacets dimension admission) | low | Facets#getTopDims on taxonomy association and value-source facets leaves out a dimension that has hits but whose aggregated value is exactly 0, although getAllDims returns it (known: #13191 / open PR #13287) (released since 9.11.0) | 1 |
| LFV-884 | grouping / GroupSelector score needs (FirstPass, SecondPass/TopGroups, AllGroups, AllGroupHeads collector score modes) | low | Grouping collectors never ask for scores on behalf of their group selector, so DoubleRangeGroupSelector or LongRangeGroupSelector over a score-dependent source (e.g. DoubleValuesSource.SCORES) groups every hit by the placeholder score of a non-scoring search (0 in every repro) when no sort or reducer needs scores, or when AllGroups/AllGroupHeads runs alone (since 8.6.0) | 1 |
| LFV-1126 | grouping / function grouping (queries function value fillers: FloatDocValues and siblings; contract in core util.mutable MutableValueFloat) | low | Grouping by a function such as sum(a,b) puts documents without a value into several null groups, one per partial value, because the function value fillers keep the partial value when exists is false (AssertionError with -ea; second-pass NullPointerException since 10.4.0) | 1 |
| LFV-324 | facet / SortedSetDocValues faceting (DefaultSortedSetDocValuesReaderState: the per-dimension DimTree and OrdRange built from the field's ordinals in term order, shared by SortedSetDocValuesFacetCounts and ConcurrentSortedSetDocValuesFacetCounts) | low | SortedSetDocValues faceting builds its facet tree from the byte order of the encoded paths, so a label or dimension name that equals a sibling's name followed by a character below U+001F (TAB, CR, LF, or the U+001E that FacetsConfig writes when it escapes U+001E/U+001F) moves a label's children under that sibling, or drops a whole dimension or one of its labels | 1 |
| LFV-597 | facet / SortedSetDocValues faceting (FacetsConfig.processSSDVFacetFields path encoding with DELIM_CHAR U+001F / ESCAPE_CHAR U+001E, decoded by DefaultSortedSetDocValuesReaderState) | low | FacetsConfig writes the bare dimension term of a flat multiValued + requireDimCount SortedSetDocValues dimension without escaping it, so a dimension name containing U+001F or U+001E is read back as a different path: the dimension loses one label and reports that label's count as its own, a phantom dimension appears, a name with two U+001F makes facet-state construction throw for the whole field, and (-ea) a name ending in U+001E throws AssertionError | 1 |
| LFV-541 | facet / taxonomy writer (DirectoryTaxonomyWriter category identity: writer cache key vs taxonomy index term, perhapsFillCache) | low | DirectoryTaxonomyWriter indexes a facet label that contains an unpaired surrogate a second time, under a new ordinal, once its writer cache has been filled from the taxonomy index, because the cache compares the label's Java string while the index stores its UTF-8 term with the surrogate replaced by U+FFFD; the taxonomy then holds two categories with one path and facet counts for that value are split | 1 |
| LFV-425 | facet / sampling (RandomSamplingFacetsCollector.amortizeFacetCounts x FacetsConfig drill-down term indexing) | low | RandomSamplingFacetsCollector.amortizeFacetCounts caps each amortized label count at the docFreq of the label's drill-down term, so with a non-default FacetsConfig DrillDownTermsIndexing (NONE on any dimension, or FULL_PATH_ONLY / DIMENSION_AND_FULL_PATH on a hierarchical dimension) it silently returns 0, or a value below the true count | 1 |
| LFV-367 | facet / DrillDownQuery (clone() and the per-dimension BooleanQuery.Builder state) | low | DrillDownQuery.clone() shares the per-dimension BooleanQuery.Builder objects with the original, so adding a value to a dimension both copies already constrain changes what the other copy matches (released since 4.7.0) | 1 |
| LFV-900 | core / search collectors (PositiveScoresOnlyCollector; FilterCollector scoreMode and setWeight forwarding; TotalHitCountCollector Weight#count shortcut) | low | PositiveScoresOnlyCollector inherits its wrapped collector's scoreMode() and setWeight(), so a wrapped sort-by-field TopFieldCollector or TotalHitCountCollector silently gets the wrong hits or count instead of exactly the hits that score > 0 (score-mode leg since 5.1.0, count leg since 9.3.0) | 1 |
| LFV-882 | misc / DocValuesStats long statistics (DocValuesStatsCollectorManager concurrent reduce) | low | DocValuesStatsCollectorManager merges LongDocValuesStats and SortedLongDocValuesStats (lucene/misc) through their wrapping long sum(), so on a searcher with an executor mean(), variance() and stdev() are silently wrong (for example about 8x too small, or negative) once a slice's long sum or the reduce's running long sum passes Long.MAX_VALUE, as 6 epoch-nanosecond timestamps do, while the same search without an executor is exact | 1 |
| LFV-684 | classification / k-NN classifiers and BooleanPerceptronClassifier (training query) | low | KNearestNeighborClassifier, KNearestFuzzyClassifier, KNearestNeighborDocumentClassifier and BooleanPerceptronClassifier add their documented training filter query (and the class-field restriction) as scoring Occur.MUST clauses, so a training query that filters out nothing changes the k-NN class scores and can flip the assigned class, the nearest neighbours or the learned perceptron model (released since 4.6.0) | 1 |
| LFV-801 | classification / KNearestFuzzyClassifier (textFieldNames 'field^boost' syntax; NearestFuzzyQuery field lookup) | low | KNearestFuzzyClassifier ignores its documented 'field^boost' syntax: an entry such as 'title^10' in textFieldNames is looked up as a literal field name, so that field contributes nothing, and with a single boosted field assignClass returns null | 1 |
| LFV-681 | classification / utils: DatasetSplitter (split, createNewDoc fieldNames branch) | low | DatasetSplitter.split with explicit fieldNames copies only the first value of each multi-valued field into the split indexes | 1 |
| LFV-683 | classification / utils: DatasetSplitter (split: class count used as the GroupingSearch group limit) | low | DatasetSplitter.split can silently leave a whole labelled class out of all three output indexes when some documents have no class value, and throws NullPointerException, leaving the output writers locked, when a segment has no class field | 1 |
| LFV-388 | classification / BM25NBClassifier (assignClass and getClasses) | low | BM25NBClassifier scores a class that has no live, training-query-matching document as if it had probability 1 (log prior 0 and log-likelihood 0), so with few classes it outranks the trained classes and is assigned although it has no training data (released since 7.0.0) | 1 |
| LFV-682 | classification / utils: DatasetSplitter (split, test/cv/training assignment loop) | low | DatasetSplitter puts at most about half of each class into the test index, whatever testRatio is | 1 |
| LFV-088 | document / LatLonPoint#nearest | low | LatLonPoint#nearest reports an EQUAL_TO TotalHits that counts deleted documents | 1 |
| LFV-746 | spatial3d / Geo3D distance sort comparator (Geo3DPointDistanceComparator.compareBottom bounds shortcut; Geo3DDocValuesField.newDistanceSort and newPathSort) | low | Geo3D distance and path sorts (Geo3DDocValuesField.newDistanceSort, newPathSort) skip the secondary SortField for hits outside the shape's bounding box once the queue bottom is +Infinity, so top-N keeps the earliest out-of-radius documents in doc order instead of the first N of the sorted order (released since 6.1.0) | 1 |
| LFV-293 | queries / intervals (Intervals.before, OffsetIntervalsSource PRECEDING) | low | Intervals.before(source, reference) treats a source interval at position 0 as before a reference interval that also starts at position 0, so for example before(york, york) matches the one-word document 'york' | 1 |
| LFV-805 | queries / intervals (RepeatingIntervalsSource.minExtent for ordered/unordered of equal sub-sources; Disjunctions rewrite under phrase/maxgaps) | low | Intervals.ordered(a, a) and Intervals.unordered(a, a) report minExtent() 1, so the default disjunction rewrite under phrase/maxgaps leaves or(ordered(a, a), a) unsplit and phrase(x, or(ordered(a, a), a), c) misses 'x a a c' | 1 |
| LFV-826 | queries / intervals (gap-sensitive disjunction rewrite of LUCENE-8477: Disjunctions.splitDisjunctions and Disjunctions.pullUp vs an alternative of an or() that has disjunctions of its own: maxwidth, extend, fixField, ordered) | low | The intervals disjunction rewrite looks only one level into an or(), so an or() inside a maxwidth, fixField or extend wrapper (or inside an ordered()) that is itself one alternative of another or() is never split, and phrase, maxgaps or containedBy miss hits: phrase(x, or(maxwidth(5, or("b c", b)), y), d) misses 'x b c d', which phrase(x, maxwidth(5, or("b c", b)), d) matches | 1 |
| LFV-670 | spatial-extras / prefix-tree heatmap faceting (HeatmapFacetCounter.calcFacets, also reached through PrefixTreeStrategy.calcFacets; coarse 'ancestor' leaf cells reported by PrefixTreeFacetCounter) | low | Spatial heatmap: HeatmapFacetCounter gives non-zero counts to cells outside a non-rectangular input shape when documents are indexed with coarse leaf cells, although the javadoc says those cells are always 0 | 1 |
| LFV-678 | spatial-extras / spatial4j bridge to spatial3d (Geo3dShapeFactory line-string builder, Geo3dLineStringBuilder.build), reached through the public LineStringBuilder API, the deprecated lineString(List, double), multi-line builders and the Geo3d context's polyshape reader (and the GeoJSON reader when its optional parser is present) | low | Geo3dShapeFactory passes a line string's buffer distance to spatial3d's GeoPathFactory, which takes radians, without the degrees-to-radians conversion its circle() applies, so in the Geo3d spatial context a line buffered by 1 degree is 1 radian (57.3 degrees) wide and buffers above about 1.57 throw | 1 |
| LFV-777 | spatial-extras / PointVectorStrategy distance value source (vector/DistanceValueSource missing-document value; makeDistanceValueSource, makeRecipDistanceValueSource) | low | PointVectorStrategy's distance value source gives a document without a point the distance 180 * multiplier even in a non-geo (Cartesian) SpatialContext, so an ascending distance sort lists it before real documents farther than 180 units and makeRecipDistanceValueSource scores it as if it were 180 units away (the other strategies that implement makeDistanceValueSource use Double.MAX_VALUE there; regression in 7.0.0 from LUCENE-7737) | 1 |
| LFV-320 | facet / range drill-down queries (LongRange and DoubleRange ValueSourceQuery and MultiValueSourceQuery) and the query cache | low | LongRange/DoubleRange#getQuery(fastMatchQuery, valueSource) reports its Weight as cacheable without asking the fast-match query, so after an in-place doc-values update the query cache keeps returning the old matches | 1 |
| LFV-336 | core / search: LateInteractionFloatValuesSource (late-interaction multi-vectors) and the query cache | low | LateInteractionFloatValuesSource#isCacheable always returns true although it reads the multi-vectors from binary doc values, so after an in-place update of a LateInteractionField the query cache keeps returning the old matches of a FunctionMatchQuery or DoubleRange query over it | 1 |
| LFV-947 | spatial-extras / composite: CompositeVerifyQuery (Weight#isCacheable) and the query cache | low | CompositeVerifyQuery's Weight reports itself cacheable from its shape predicate alone and ignores the index query it runs, so after an in-place doc-values update a query cache keeps returning the old matches | 1 |
| LFV-829 | highlighter / original Highlighter, QueryScorer and WeightedSpanTermExtractor (MultiPhraseQuery-to-span conversion) | low | Classic Highlighter counts the unused positions before a MultiPhraseQuery's first position as gaps, so a phrase that starts at position 1 or later (a leading stop word plus a synonym) is highlighted with extra slop and non-matching pairs get marked | 1 |
| LFV-268 | highlighter / UnifiedHighlighter re-analysis offset source (MemoryIndexOffsetStrategy under WEIGHT_MATCHES) | low | UnifiedHighlighter re-analysis under the default WEIGHT_MATCHES flag builds its MemoryIndex without payloads, so payload-checking queries get missing or extra highlights or make highlight() throw IllegalArgumentException | 1 |
| LFV-508 | join / block join Weight#matches (ParentsChildrenBlockJoinQuery; consumers BooleanWeight#matches, UnifiedHighlighter, Monitor HighlightsMatch) | low | ParentsChildrenBlockJoinQuery's Weight#matches ignores the join and returns Matches for documents the query does not match (parent documents, children of non-matching parents, children over childLimitPerParent), so as a MUST_NOT clause it strips the Matches and highlights of real hits, and Lucene Monitor's HighlightsMatch matcher reports the wrong documents | 1 |
| LFV-266 | queries / span queries Matches API (SpanWeight#matches takes offsets and sub-matches from ContainSpans#collect for SpanWithinQuery; seen through the UnifiedHighlighter and MatchRegionRetriever) | low | SpanWithinQuery's Weight#matches reports the contained (little) span's positions but the enclosing (big) span's offsets and sub-matches, so Matches-based highlighting (the default UnifiedHighlighter, MatchRegionRetriever) marks the enclosing terms and a field with offsets highlights differently from the same text indexed with positions only | 1 |
| LFV-872 | search / IndriQuery (QueryVisitor traversal of Indri composite queries; consumers: QueryVisitor.termCollector, IndexSearcher's cumulative clause limit, RamUsageEstimator.sizeOf(Query), UnifiedHighlighter) | low | IndriQuery.visit reports the whole query as a leaf and never visits its clauses, so QueryVisitor.termCollector, UnifiedHighlighter term extraction, IndexSearcher's cumulative clause limit and RamUsageEstimator.sizeOf all ignore an IndriAndQuery's clauses | 1 |
| LFV-276 | highlighter / matchhighlight (MatchRegionRetriever default offset strategy OffsetsFromTokens for fields indexed without positions; MatchHighlighter on top of it) | low | MatchRegionRetriever's default OffsetsFromTokens strategy ignores QueryVisitor#consumeTermsMatching, so prefix, wildcard, regexp, term-range and multi-term TermInSetQuery matches on fields without positions get no hit regions | 1 |
| LFV-595 | highlighter / matchhighlight: MatchHighlighter multi-query highlighting (DocHit field values on top of MatchRegionRetriever's per-query stored-field loading) | low | MatchHighlighter.highlight(topDocs, q1, q2, ...) silently drops the highlights of every field that only the second or a later query matches: each document keeps only the stored field values of the first query's MatchRegionRetriever, which loads just the fields that first query affects (regression in 10.0.0) | 1 |
| LFV-1044 | search / BooleanQuery MUST_NOT bulk scoring (ReqExclBulkScorer) | low | Since #16669 (10.6.0 and main), ReqExclBulkScorer no longer skips long runs of excluded doc IDs: for +R -X it scores the required clause in every 4096-doc window, even windows X fully excludes, so R's iterator steps through all of its matches inside X's runs (10,001 moves for 1,000 hits in a 10,000-doc segment, where 10.0.0-10.5.2 need 1,001; performance regression, results correct) | 1 |
| LFV-1057 | search / field sorting: TopFieldCollector + NumericComparator points-based sort pruning (competitive iterator) | low | Since #16857 (upstream main and branch_11x, unreleased), a numeric field-sorted search reads a later segment's whole competitive points range before the scorer is set: TopFieldLeafCollector's constructor calls setHitsThresholdReached() while NumericComparator's iteratorCost is still its -1 'no scorer yet' value, so the 8x selectivity check never rejects (1,001 point doc IDs read where releases read 0; performance regression, results correct) | 1 |
| LFV-791 | search / sorting (TopFieldCollector, relevance-first sort: minimum competitive score at the totalHitsThreshold crossing) | low | A relevance-first TopFieldCollector (Sort.RELEVANCE or Sort(FIELD_SCORE, tiebreak)) never sets the minimum competitive score when totalHitsThreshold is crossed, so skipping starts only if a later hit is competitive, and the search can score every match (performance regression since 8.7.0; results correct) | 1 |
| LFV-334 | core / search: DoubleValuesSourceRescorer.rescore and explain (score-dependent DoubleValuesSource) | low | DoubleValuesSourceRescorer.rescore passes null scores to a DoubleValuesSource whose needsScores() is true, so rescoring with DoubleValuesSource.SCORES, an expression that reads _score or a FunctionScoreQuery.boostByValue source throws (AssertionError with -ea; NullPointerException or a misleading 'Unrecognized variable (_score)' RuntimeException with -da), while explain() on the same input returns normally | 1 |
| LFV-1101 | highlighter / classic Highlighter (WeightedSpanTermExtractor internal reader FieldInfos) | low | Classic Highlighter throws IllegalStateException for queries whose rewrite runs a search on its internal one-document reader (RescoreTopNQuery over a doc-values source; filtered or seeded kNN clauses when the token stream comes from term vectors), because that reader reports the highlighted text field's FieldInfo for every field name since 10.5.0 (on 10.3.0 and 10.4.0 the same calls threw UnsupportedOperationException because that reader did not implement getFieldInfos) (known: #7450 / LUCENE-6390, partial overlap) (released) | 1 |
| LFV-729 | facet / FacetsConfig drill-down term indexing (DrillDownTermsIndexing.NONE in a shared indexFieldName) vs the core per-field schema check (IndexingChain FieldSchema, FieldInfo.verifySameIndexOptions) | low | A facet dimension set to DrillDownTermsIndexing.NONE that shares its index field ($facets by default) with term-indexing dimensions makes FacetsConfig emit two schemas for that field, so since 9.0.0 IndexWriter rejects documents of one kind once a document of the other kind is indexed, and after a commit until the index is cleared or rebuilt | 1 |
| LFV-967 | suggest / document (NRT) suggester: CompletionWeight#scorerSupplier vs the Weight/ScorerSupplier contract and IndexSearcher#searchLeaf | low | CompletionWeight returns a non-null ScorerSupplier whose bulkScorer() is null, so IndexSearcher#search of a CompletionQuery throws NullPointerException on a segment the query cannot match (regression in 10.0 from #13408) | 1 |
| LFV-969 | suggest / document (NRT) suggester: CompletionScorer under IndexSearcher's windowed execution (setTimeout, intra-segment partitions) | low | CompletionScorer silently ignores the BulkScorer [min, max) window instead of rejecting it, so a CompletionQuery run through IndexSearcher#search with a timeout (even one that never fires) or with intra-segment partitions returns repeated suggestions and drops others | 1 |
| LFV-237 | index / vector values iteration (KnnVectorValues.fromDISI) with backward-codecs / Lucene 9.4 sparse byte vector reader | low | KnnVectorValues.fromDISI's advance() leaves index() stale, so on Lucene 10 sparse byte vectors in segments written by Lucene 9.4 read back as zeros or as another document's vector | 1 |
| LFV-396 | core / document: shape doc values (ShapeDocValues reader behind LatLonShapeDocValues / XYShapeDocValues relate and the slow doc-values shape queries; MemoryIndex shape doc-values fields) | low | ShapeDocValues.relate() rewinds to position 0 of the backing array instead of to the BytesRef's offset, so a LatLonShape or XYShape doc value built from a BytesRef slice (offset != 0) silently relates wrongly to queries | 1 |
| LFV-405 | facet / facet sets (MatchingFacetSetsCounts.count, a BinaryDocValues consumer; reached through MemoryIndex, custom readers and the backward-codecs Lucene80 BEST_COMPRESSION doc-values producer) | low | MatchingFacetSetsCounts decodes the facet-set binary doc value from position 0 of BytesRef.bytes instead of BytesRef.offset, so a value that a reader returns as a slice of a larger array is counted from the wrong bytes (silently wrong facet-set counts, or NegativeArraySizeException / ArrayIndexOutOfBoundsException) | 1 |
| LFV-227 | join / JoinUtil query-time term join (TermsWithScoreCollector.SV and SV.Avg, ScoreMode Min/Avg) | low | JoinUtil's single-valued term join forgets a from-document that scored exactly 0, so ScoreMode.Min and ScoreMode.Avg give too-high, order-dependent scores | 1 |
| LFV-584 | core / util QueryBuilder phrase building with token boosts (analyzeMultiPhrase; BoostAttribute from DelimitedBoostTokenFilter and weighted synonyms; reached through the classic, multi-field and simple query parsers) | low | QueryBuilder drops every token boost (BoostAttribute) from a quoted phrase as soon as one of its words has a single-word synonym, so typed word|weight boosts and weighted-synonym weights are silently ignored there, while plain phrases, graph phrases and unquoted queries keep them | 1 |
| LFV-1148 | core / util QueryBuilder (createFieldQuery position count choosing the phrase branch over the single-position synonym branch; reached through the classic, multi-field and simple query parsers) | low | QueryBuilder counts a removed leading stop word as a position, so a quoted phrase such as "the dogs", whose one remaining word carries a same-position synonym or variant, becomes a one-position MultiPhraseQuery instead of the SynonymQuery that "dogs" gives, and is scored differently (since 6.0.0) | 1 |
| LFV-686 | queryparser / surround (FieldsQuery field prefixes and ^ weights) | low | Surround query parser ignores a ^ weight written directly on the operand of a field prefix (title: lucene^3, title: body: lucene^3, body: or(a, b)^2), because FieldsQuery builds its operand with makeLuceneQueryFieldNoBoost | 1 |
| LFV-852 | monitor / query decomposition and match scoring (QueryDecomposer DisjunctionMaxQuery split, ScoringMatch/ExplainingMatch resolve) | low | Lucene Monitor's ScoringMatch and ExplainingMatch score a registered DisjunctionMaxQuery with a tie-breaker below 1 as the sum of its matching disjuncts instead of max + tieBreaker * others | 1 |
| LFV-687 | queryparser / surround (QueryParser.jj QUOTED token and SimpleTerm production, SrndTermQuery) | low | Surround query parser keeps the escaping backslashes inside a quoted term, so "a\"b" searches for a\"b instead of a"b and "c:\\temp dir" searches for c:\\temp dir instead of c:\temp dir | 1 |
| LFV-747 | queryparser / flexible StandardQueryParser interval functions (StandardSyntaxParser.jj IntervalText and IntervalFuzzyTerm, intervalfn AnalyzedText and FuzzyTerm) | low | Flexible StandardQueryParser: term literals inside fn: interval functions keep their escape backslashes, so fn:or(a\:b) searches for the text a\:b instead of the term a:b | 1 |
| LFV-714 | queryparser / complexPhrase: ComplexPhraseQueryParser (ComplexPhraseQuery.parsePhraseElements second-pass parse, read by ComplexPhraseQuery.rewrite) | low | ComplexPhraseQueryParser: a quoted phrase that is only one parenthesized group is read as a sequence of positions, so "(john OR jonathan)" matches only the sequence 'john jonathan' and "(jo* -john)" matches documents whose only jo* term is john | 1 |
| LFV-479 | suggest / FST completion suggester (FSTCompletionLookup.build weight bucketing) | low | FSTCompletionLookup sorts weights as unsigned bytes, so negative weights get the highest buckets and are suggested before positive ones | 1 |
| LFV-689 | suggest / document (NRT) suggester (FuzzyCompletionQuery: FuzzyCompletionWeight.setNextMatch prefix-similarity boost in unicodeAware mode, also inside ContextQuery) | low | FuzzyCompletionQuery with unicodeAware=true compares the query's code points with the UTF-8 bytes of the matched suggestion, so its prefix-similarity boost stops at the first non-ASCII letter and exact prefixes lose their boost advantage over typos | 1 |
| LFV-706 | suggest / FST completion suggester (FSTCompletionLookup build/load exactMatchFirst wiring) | low | FSTCompletionLookup ignores exactMatchFirst=false for by-weight lookups after build() and load(), so an exact match is always ranked first | 1 |
| LFV-649 | analysis-common / minhash (MinHashFilter.FixedSizeTreeSet bottom-k set; MinHashFilterFactory 'minHash') | low | MinHashFilter with hashSetSize >= 2 drops one of the kept lowest hash values when a token repeats while its (hash, bucket) set is full, so the min-hash signature depends on token repeats and order instead of only on the token set ('b a a' keeps 1 of 2 values; 'c a c b' and 'c a b c' give different signatures) | 1 |
| LFV-867 | analysis-common / synonym.word2vec (Word2VecModel.addTermAndVector term-to-vector mapping; Dl4jModelReader; Word2VecSynonymProvider and Word2VecSynonymFilter as consumers) | low | Word2VecModel: a term added twice silently shifts the vector of every later term, so Word2VecSynonymFilter returns synonyms computed from other terms' vectors | 1 |
| LFV-504 | misc / store: DirectIODirectory (DirectIOIndexInput.fill and seek) | low | DirectIOIndexInput.fill moves filePos to the next block, and clears the buffer, before its EOF check and before the channel read succeeds, so after a read that threw, a legal seek or the next read on the same input returns bytes of another file position or a spurious EOFException (since 9.0.0) | 1 |
| LFV-646 | suggest / analyzing infix suggester (AnalyzingInfixSuggester.build() failure path; inherited unchanged by BlendedInfixSuggester) | low | AnalyzingInfixSuggester.build() can commit and then throw, and its catch block leaves writer == null, so refresh() becomes a no-op: the old suggestions stay served while the directory holds the build that threw, and the next add()/update() or a reopen silently switches to it (default settings, since 9.2.0) | 1 |
| LFV-394 | index / merge policy (LogMergePolicy.findMerges level window; LogDocMergePolicy, LogByteSizeMergePolicy) | low | LogMergePolicy.findMerges wraps 'start + mergeFactor' when mergeFactor is Integer.MAX_VALUE (or within about the segment count of it), which setMergeFactor accepts, so commit and flush throw once two size levels exist (every release since 2.3.0) | 1 |
| LFV-454 | search / kNN vector queries (per-segment collector sizing: AbstractKnnVectorQuery, TopKnnCollectorManager, TopKnnCollector; join DiversifyingNearestChildrenKnnCollectorManager) | low | kNN vector queries size each segment's result heap from the requested k, not from what the segment can return, so k = Integer.MAX_VALUE throws IllegalArgumentException and k = 2^28 runs out of a 2 GiB heap on a 3-document index (core KnnFloat/KnnByteVectorQuery without a filter: regression in 9.10.0; join DiversifyingChildren*KnnVectorQuery: since 9.8.0) | 1 |
| LFV-997 | search / rescoring (SortRescorer; expressions ExpressionRescorer inherits rescore()) | low | SortRescorer and Expression#getRescorer size their sort collector by topN instead of by the number of first-pass hits, so a topN far above the hit count (such as Integer.MAX_VALUE for 're-sort them all') throws (OutOfMemoryError on main, IllegalArgumentException in current releases) or allocates memory in proportion to topN, while QueryRescorer and DoubleValuesSourceRescorer return the hits | 1 |
| LFV-442 | index / TieredMergePolicy merge selection (doFindMerges candidate loop; setMaxMergedSegmentMB validation) | low | TieredMergePolicy.setMaxMergedSegmentMB(0), a value the setter accepts, makes commit(), close() and forceMergeDeletes() throw once a segment has enough deletes: the doFindMerges candidate loop never admits a segment, so the merge candidate is empty (AssertionError with -ea, IndexOutOfBoundsException with -da); a regression since 7.5.0 | 1 |
| LFV-908 | search / CachingCollector first-pass caching (CachingCollector, CachingCollectorManager) x grouping GroupingSearch two-pass caching | low | A negative cache limit (GroupingSearch.setCaching(-1, ..) / setCachingInMB(-1.0, ..), CachingCollector.create(.., -1), CachingCollectorManager) is accepted and caches nothing, yet isCached() stays true, so replay() delivers no documents and grouped search silently returns groups with no documents and totalHitCount 0 (since 9.8.0; from 5.0.0 to 9.7.0 replay threw instead) | 1 |
| LFV-966 | queryparser / flexible core: QueryNodeProcessorPipeline (java.util.List views and default methods) | low | QueryNodeProcessorPipeline's listIterator()/subList() views, and replaceAll / Collections.replaceAll built on them, put processors on the pipeline without its QueryConfigHandler, so the flexible query parser silently skips point, boost and default phrase slop handling or throws NullPointerException | 1 |
| LFV-210 | geo / Tessellator hole elimination (polygon indexing for LatLonShape and XYShape) | low | Tessellator bridges a hole whose left-most vertex touches an outer-ring edge to a vertex off that edge, so LatLonShape and XYShape index the hole (in some shapes also area outside the polygon) as part of the shape, or reject a valid polygon | 2 |
| LFV-757 | geo / Tessellator hole elimination (polygon indexing for LatLonShape and XYShape) | low | Tessellator: after a hole that touches the outer ring at one vertex is merged, the leftover copies of that vertex make a later hole's bridge cross the first hole, so LatLonShape and XYShape index a valid two-hole polygon with triangles that cover a hole, or reject it (regression from #15211, in 10.4.0 and 9.12.3) | 1 |
| LFV-796 | geo / Tessellator hole elimination (polygon indexing for LatLonShape and XYShape) | low | Tessellator bridges a later hole across an earlier hole when the earlier hole touches the outer ring at a vertex where an outer edge and a hole edge are collinear: after filterPoints drops the straight-run copy of that vertex, fetchHoleBridge breaks an equal-x ray tie at it by ring order, so LatLonShape and XYShape match points inside the hole (depends on the outer ring's start vertex) | 1 |
| LFV-794 | geo / Tessellator hole-bridge edge flags (LatLonShape and XYShape CONTAINS queries) | low | Tessellator flags a hole bridge that lies inside a longer outer-ring edge as an internal edge, so LatLonShape and XYShape CONTAINS queries match boxes that stick out of a valid polygon whose two holes touch the same outer edge | 1 |
| LFV-793 | geo / Tessellator hole elimination (polygon indexing for LatLonShape and XYShape) | low | Tessellator covers a hole of a valid polygon when two holes and the outer ring meet at one vertex and an outer edge continues straight into a hole edge there: the filterPoints call after each hole merge drops the copy of that vertex the next hole needs, so LatLonShape and XYShape match points inside the hole (since 8.2.0) | 1 |
| LFV-764 | geo / XYShape point queries (Component2D.pointInTriangle; ShapeField.encodeTriangle orientation for XY) | low | XYShape point queries can miss a polygon at one of its own vertices: Component2D.pointInTriangle rejects the second vertex (b) of a clockwise triangle, and ShapeField.encodeTriangle makes XY triangles counter-clockwise only on their sortable-int encodings, so a stored triangle can decode clockwise; an INTERSECTS point query at that vertex misses the polygon and DISJOINT returns it (since 8.5.0) | 1 |
| LFV-795 | geo / Tessellator hole bridges (fetchHoleBridge, isLocallyInside) behind LatLonShape and XYShape polygon indexing | low | Tessellator rejects a valid polygon whose holes touch nothing, depending on the outer ring's start vertex, when an earlier hole's bridge continues an outer edge: isLocallyInside treats the resulting straight angle as never inside, so fetchHoleBridge cannot switch to the only correct copy of the bridge end (regression in 8.2.0) | 1 |
| LFV-762 | geo / Tessellator hole elimination (polygon indexing for LatLonShape and XYShape) | low | Tessellator: when three or more holes meet at one vertex P, maybeMergeHoleWithSharedVertices joins the hole whose left-most vertex is P to the first copy of P in ring order (since #15700) even when the hole lies outside that copy's wedge, so LatLonShape and XYShape reject a valid polygon with 'Unable to Tessellate shape' depending on the order of its holes; upstream's own LUCENE-9400 test polygon is rejected in 3 of its 6 hole orders (regression in 10.4.0) | 1 |
| LFV-755 | geo / Tessellator hole elimination (polygon indexing for LatLonShape and XYShape) | low | Tessellator rejects a valid polygon whose holes touch the outer ring and each other at single vertices with 'Unable to Tessellate shape', because #15739 made the reflex-vertex test in isLocallyInside inclusive ('<= 0'): a regression in 10.5.0 (10.4.0 accepts the polygon) | 1 |
| LFV-215 | geo / shape queries (GeoUtils.lineCrossesLineWithBoundary, EdgeTree.crossesTriangle, Polygon2D and Line2D intersectsTriangle; LatLonShape and XYShape polygon and line queries) | low | GeoUtils.lineCrossesLineWithBoundary treats collinear segments that do not overlap as crossing and EdgeTree.crossesTriangle lets such pairs through, so LatLonShape/XYShape polygon and line INTERSECTS queries match disjoint shapes and DISJOINT queries drop them | 2 |
| LFV-206 | geo / shape queries (Polygon2D containsLine/containsTriangle, LatLonShape and XYShape WITHIN) | low | Polygon2D.containsLine/containsTriangle accept a segment or triangle whose vertices lie on the boundary of a non-convex polygon even when it passes outside between them, so LatLonShape/XYShape WITHIN queries return false positives | 2 |
| LFV-711 | geo / shape queries (Polygon2D.withinTriangle; LatLonShape and XYShape CONTAINS with a query polygon that has holes) | low | LatLonShape/XYShape CONTAINS with a query polygon that has holes returns indexed shapes that do not contain it, because Polygon2D.withinTriangle never tests the query's hole edges | 1 |
| LFV-573 | core / geo distance queries (GeoUtils.distanceQuerySortKey, shared by LatLonPoint, LatLonDocValuesField and LatLonShape circle queries) | low | Lat/lon distance queries can drop a point whose distance equals the radius and match a point one ulp beyond it, because GeoUtils.distanceQuerySortKey does not return the largest sort key within the radius (every release since 6.1.0) | 1 |
| LFV-767 | geo / XYShape circle queries (XYRectangle.fromPointDistance, Circle2D.CartesianDistance) | low | XYShape circle queries miss lines and polygons that enter the circle only near its extreme x or y, and can report CONTAINS for a polygon the circle sticks out of, when the centre coordinate is large relative to the radius, because XYRectangle.fromPointDistance rounds the circle's bounding box inward | 2 |
| LFV-274 | spatial3d / geom outside distance (Plane.arcDistance and Plane.linearDistance behind GeoStandardCircle and GeoExactCircle computeOutsideDistance; user-facing Geo3DDocValuesField.newOutsideDistanceSort via Geo3DPointOutsideDistanceComparator) | low | On WGS84 and other non-spherical planet models, the outside distance from a point to a geo3d circle smaller than about 50 km is +Infinity in most directions (GeoCircle.computeOutsideDistance with the ARC or LINEAR style, and so Geo3DDocValuesField.newOutsideDistanceSort, which then sorts valid documents as if they had no value), because Plane.arcDistance and Plane.linearDistance look for the edge on the line where the circle's plane meets a plane through the origin, the plane normal and the point, and on an ellipsoid that line misses a small circle | 1 |
| LFV-735 | spatial3d / geom path outside distance (GeoStandardPath segment endpoints; Geo3DDocValuesField.newOutsidePathSort) | low | GeoStandardPath outside distance measures end caps (and one-point paths) to the end point instead of the cap edge, so values are too large by up to the path half-width and Geo3DDocValuesField.newOutsidePathSort misorders documents | 1 |
| LFV-782 | spatial3d / geom polar rectangles outside distance (GeoNorthRectangle, GeoSouthRectangle) and the Geo3DDocValuesField outside-box sort | low | Geo3D outside distance to a lat/lon box that reaches a pole (GeoNorthRectangle / GeoSouthRectangle) ignores the pole, so Geo3DDocValuesField.newOutsideBoxSort gives documents beyond the pole the distance to a far corner (39.88 instead of 10 degrees for the box lat 60..90 x lon -10..10 and the point (80, 180)) and sorts them after nearer documents | 1 |
| LFV-378 | spatial3d / geom shape relationships (GeoBaseAreaShape.getRelationship with GeoStandardCircle's single edge point and Plane.intersects' tangency test), reached through the spatial-extras Geo3d spatial4j adapter (Geo3dShape.relate, SpatialOperation IsWithin/Contains, SerializedDVStrategy, CompositeSpatialStrategy) | low | Geo3d reports two shapes that touch at a single point as nested (WITHIN/CONTAINS) instead of overlapping when the touch point is a circle's one sampled edge point, so IsWithin and Contains spatial queries (SerializedDVStrategy, CompositeSpatialStrategy) return circles that lie mostly outside the query shape | 1 |
| LFV-611 | spatial3d / geom bounding boxes (GeoBBox.expand in the 13 GeoBBox classes with a longitude range, GeoBBoxFactory.makeGeoBBox); spatial-extras / spatial4j Geo3D context (Geo3dRectangleShape.getBuffered, reached by spatial4j's WKT BUFFER) | low | GeoBBox.expand clamps a widened longitude bound at +-180 degrees instead of wrapping it across the antimeridian, so expanded geo3d boxes (and Geo3dRectangleShape.getBuffered / WKT BUFFER(ENVELOPE(...)) in a Geo3D spatial context) miss the part beyond the dateline | 1 |
| LFV-614 | spatial3d / geom bounding boxes (GeoDegenerateLatitudeZone, which GeoBBoxFactory.makeGeoBBox returns for a box with equal top and bottom latitude spanning all longitudes), reached through Geo3DPoint.newBoxQuery / newShapeQuery and the spatial-extras Geo3D spatial context (Geo3dShape.relate, RecursivePrefixTreeStrategy, CompositeSpatialStrategy) | low | GeoDegenerateLatitudeZone.isWithin compares z with sin(latitude) at a 1e-10 tolerance instead of using its own planet-model plane, so a zero-height geo3d box spanning all longitudes rejects the points on its own latitude on WGS84 and, on any planet model, can report CONTAINS for areas just below it, which makes Geo3D prefix-tree searches match points tens of degrees away | 1 |
| LFV-737 | spatial3d / geom exact-circle outside distance (GeoExactCircle.outsideDistance, reached through GeoCircleFactory.makeExactGeoCircle and GeoOutsideDistance.computeOutsideDistance) | low | GeoExactCircle.computeOutsideDistance never measures the slice end points where two of its approximation slices meet, so a point outside whose nearest edge point is such a joint gets +Infinity or the distance to the far side of the circle: on WGS84 every point due north or due south of the centre, at any radius; on the sphere a point 0.001 rad due west of a 1e-4 rad exact circle gets 0.0012 | 1 |
| LFV-1014 | core / geo Rectangle (LatLonShape box queries, newGeometryQuery(Rectangle), SimpleWKTShapeParser ENVELOPE) | low | geo.Rectangle checks minLat <= maxLat only with an assert, so a lat/lon box with swapped latitudes (new Rectangle, LatLonShape.newBoxQuery, a WKT ENVELOPE) throws a bare AssertionError with -ea and is silently accepted with -da, where LatLonShape box queries then return hits that match no region; the Cartesian twin XYRectangle throws IllegalArgumentException for the same mistake | 1 |
| LFV-434 | core / document: XYShape queries (XYShape.newLineQuery and newGeometryQuery, XYShapeQuery, Line2D) | low | XYShape.newLineQuery / newGeometryQuery accept QueryRelation.WITHIN with an XYLine, which LatLonShape (and XYShape itself up to 8.4.1) rejects with IllegalArgumentException; the accepted query silently returns only indexed points lying on the line and never an indexed line, not even one identical to the query line (the check was lost in LUCENE-9194, 8.5.0) | 1 |
| LFV-1203 | core / document: LatLon point geometry query factories (LatLonPoint.newGeometryQuery CONTAINS shortcut, LatLonDocValuesField.newSlowGeometryQuery) | low | LatLonPoint.newGeometryQuery with QueryRelation.CONTAINS returns a query that matches nothing instead of the documented IllegalArgumentException when the geometry array is empty or holds a null (LatLonDocValuesField.newSlowGeometryQuery does the same for a null element), because the CONTAINS shortcut runs before any argument check (since 8.8.0, LUCENE-9641) | 1 |
| LFV-316 | spatial-extras / prefix trees (QuadPrefixTree, PackedQuadPrefixTree under RecursivePrefixTreeStrategy) | low | QuadPrefixTree/PackedQuadPrefixTree with non-power-of-two world bounds put a point that lies on a grid line into a cell whose shape excludes it, so Intersects misses the document (deep trees throw InvalidShapeException) | 1 |
| LFV-371 | spatial-extras / prefix trees (S2PrefixTree and S2PrefixTreeCell under RecursivePrefixTreeStrategy; Contains through ContainsPrefixTreeQuery) | low | S2PrefixTree: a Contains query whose shape is a point P misses a document indexed with that same point P when P lies on an S2 cell edge (the equator, an S2 face edge, (0,0)), because the query side follows every child cell that touches P while indexing puts P in one cell per level | 1 |
| LFV-705 | spatial-extras / prefix trees: PackedQuadPrefixTree point-to-cell lookup (RecursivePrefixTreeStrategy and CompositeSpatialStrategy point queries) | low | PackedQuadPrefixTree in a geo context indexes a point at longitude +180 under the -180 edge cell, but point queries look in the +180 edge cell, so RPT and CompositeSpatialStrategy Intersects/Contains with that same point miss the document | 1 |
| LFV-301 | spatial-extras / PointVectorStrategy (Intersects and IsWithin rectangle queries: makeWithin x filter) | low | PointVectorStrategy misses a point at longitude +180 or -180 when a rectangle query that does not cross the dateline has its edge on that meridian with the other sign (-180 vs +180) | 1 |
| LFV-1113 | spatial-extras / BBoxStrategy and PointVectorStrategy query construction (inclusive DoublePoint range bounds taken unchanged from spatial4j rectangles: BBoxStrategy.makeNumericRangeQuery, PointVectorStrategy.rangeQuery) | low | BBoxStrategy and PointVectorStrategy miss a shape on a query edge at 0 when the shape's coordinate and the edge are zeros of opposite sign (-0.0 vs +0.0), so BBoxStrategy finds a point Intersecting a rectangle but not Within it | 1 |
| LFV-619 | spatial-extras / prefix trees (DateRangePrefixTree date parsing: parseCalendar, also reached through NumberRangePrefixTree.parseShape for single dates and range bounds) | low | DateRangePrefixTree.parseCalendar (and parseShape) rejects day 32 but accepts a day that its month does not have (2014-11-31, 2014-02-30, 2013-02-29) and silently rolls it into the next month, so the range [2014-11-01 TO 2014-11-31] also matches December 1st | 1 |
| LFV-550 | core document / LatLon distance sort (LatLonPointDistanceComparator competitive bounding box, Rectangle.fromPointDistance pad) | low | LatLon distance sort from a pole origin: the competitive bounding box (7 cm margin) rejects documents that tie with the queue bottom near the opposite pole, so the secondary SortField is skipped and top-N and searchAfter results are wrong | 1 |
| LFV-578 | core document + geo / LatLon box queries (the newBoxQuery/newSlowBoxQuery 90/180 special case vs Rectangle2D.create and LatLonShapeBoundingBoxQuery) | low | LatLonPoint and LatLonDocValuesField box queries at exactly latitude 90 (box lat 90..90) or longitude 180..180 match nothing through newBoxQuery/newSlowBoxQuery but match the edge point through the Rectangle2D-based paths of the same field, so one point is reported as neither INTERSECTS nor DISJOINT (8.8.0 to main) | 2 |
| LFV-1134 | core / geo (Circle2D.containsLine/containsTriangle for haversine circles whose bounding box crosses the dateline, behind LatLonShape.newDistanceQuery WITHIN) | low | LatLonShape WITHIN a circle that crosses the dateline matches a line or polygon whose vertices lie inside the circle on both sides of the dateline, although Lucene runs its edges through longitude 0, far outside the circle: Circle2D.containsLine/containsTriangle test only the vertices | 1 |
| LFV-366 | document / shape doc values (ShapeDocValues centroid; LatLonShapeDocValuesField and XYShapeDocValuesField getCentroid) | low | ShapeDocValues getCentroid() returns (0, 0), far outside the shape's own bounding box, when the shape's total encoded length or area is zero (a line whose points coincide after encoding, or a polygon thinner than one encoding step) | 1 |
| LFV-1130 | core / document: shape doc values (ShapeDocValues.ShapeComparator bounding box behind LatLonShapeDocValues / XYShapeDocValues getEncodedMinX, getEncodedMinY, getEncodedMaxX, getEncodedMaxY) | low | LatLonShapeDocValues and XYShapeDocValues getEncodedMinX/MinY/MaxX/MaxY return a tree node's box instead of the shape's bounding box after a relate() call that descends the shape's tree, because the getters read the reader's reusable scratch box | 1 |
| LFV-792 | geo / Tessellator cure step (polygon indexing for LatLonShape and XYShape, shape doc values) | low | Tessellator.cureLocalIntersections adds each triangle it cuts off twice, so LatLonShape and XYShape index that triangle twice and the shape doc-values centroid counts its area twice | 1 |
| LFV-675 | spatial-extras / spatial4j bridge to spatial3d (Geo3dRectangleShape.reset), read by BBoxStrategy's value sources (BBoxValueSource: makeShapeValueSource, makeOverlapRatioValueSource) | low | Geo3dRectangleShape.reset(minX, maxX, minY, maxY) replaces the wrapped spatial3d box but keeps the old minX/maxX/minY/maxY, so with the Geo3d spatial context BBoxStrategy shape values report a stale box for every document and BBoxStrategy overlap-ratio relevance scores are wrong | 1 |
| LFV-778 | spatial-extras / SpatialStrategy recip-distance scoring (every strategy with a distance value source) | low | SpatialStrategy.makeRecipDistanceValueSource takes zScaling from half the corner-to-corner great-circle distance of the query's bounding box, which goes the short way round the globe once a geo box is wider than 180 degrees of longitude, so edge scores fall far below the documented ~0.1 (0.0082 for rect(-170,170,-10,10), 0.0028 for a 5S-5N band of all longitudes; released since 4.0.0) | 1 |
| LFV-369 | spatial-extras / BBoxStrategy overlap-ratio relevance (BBoxOverlapRatioValueSource.score: intersection width when both boxes cross the dateline) | low | BBoxStrategy's overlap-ratio relevance (BBoxOverlapRatioValueSource) undercounts the overlap of two dateline-crossing boxes that intersect in two longitude pieces, so the score is too low | 1 |
| LFV-240 | suggest / spell checking (DirectSpellChecker.suggestSimilar with a non-default StringDistance; FuzzyTermsEnum competitive-boost pruning) | low | DirectSpellChecker with a non-default StringDistance prunes candidates by comparing the metric's score with FuzzyTermsEnum boosts, so better candidates are never inspected (regression since 7.0) | 1 |
| LFV-647 | suggest / spell: SpellChecker.indexDictionary de-duplication (cached searcher vs. the new IndexWriter's index; clearIndex, swapSearcher) | low | SpellChecker.indexDictionary de-duplicates against its cached searcher instead of the index its new IndexWriter writes, so a rebuild with OpenMode.CREATE silently drops every word of the new dictionary that the old spell index already had (and after a failed searcher reopen, later calls drop words or index them twice) | 1 |
| LFV-583 | suggest / SuggestStopFilter (query analysis of the analyzing and document suggesters) | low | SuggestStopFilter.end() leaves out the positions of the stop words it removes at the end of the input (StopFilter counts them), so a suggester with SuggestStopFilter in its query analyzer returns extra suggestions for text that ends in removed stop words and a space (two or more stop words for AnalyzingSuggester and FuzzySuggester, one for the document suggester; wrong end() since 4.5.0, visible in suggesters since 6.5.0) | 1 |
| LFV-918 | analysis-common / Russian analyzer default stop words (RussianAnalyzer, snowball/russian_stop.txt; interaction with the Snowball RussianStemmer's ё-to-е fold) | low | RussianAnalyzer does not remove its default stop words when they are written with ё (её, ещё, всё, неё, чём): its StopFilter runs before the stemmer folds ё to е, although the bundled stop list says ё is translated to е | 1 |
| LFV-677 | analysis-common / language analyzers (TeluguAnalyzer default stop set te/stopwords.txt, applied after IndicNormalizationFilter and TeluguNormalizationFilter) | low | TeluguAnalyzer runs its StopFilter after Indic and Telugu normalization, but its default stop list is not normalized, so 13 of the 43 single-word default stop words (for example కూడా, 'also') are never removed | 1 |
| LFV-672 | analysis-common / Bengali analyzer default stop words (BengaliAnalyzer, bn/stopwords.txt; interaction with IndicNormalizationFilter and BengaliNormalizationFilter) | low | BengaliAnalyzer never removes 13 of its 116 default stop words (e.g. কারণ, শুধু, মধ্যে, অন্য) because its StopFilter runs after Indic/Bengali normalization while the bundled stopwords.txt has only unnormalized spellings | 1 |
| LFV-703 | analysis-common / language analyzers (default stop sets of SoraniAnalyzer, LatvianAnalyzer and GalicianAnalyzer; choice of WordlistLoader overload) | low | SoraniAnalyzer, LatvianAnalyzer and GalicianAnalyzer load the '#' comment lines of their bundled stopwords.txt as stop words: 60 of the 122 entries of SoraniAnalyzer.getDefaultStopSet(), 9 of 170 for Latvian (including a bare '#') and 1 of 161 for Galician are comment text | 1 |
| LFV-851 | analysis / WordDelimiterGraphFilterFactory and WordDelimiterFilterFactory types option (parseTypes) versus the default WordDelimiterIterator character-type table | low | WordDelimiterGraphFilterFactory's types option (and the deprecated WordDelimiterFilterFactory's) refills the whole Latin-1 type table from getType() instead of the filter's default table, so any rule, even one that restates a character's own type, silently changes how 8 other characters (¹ ² ³ ¼ ½ ¾ ª º) are tokenized | 1 |
| LFV-862 | analysis-common / synonym.word2vec (Word2VecSynonymProvider.getSynonyms result cap; Word2VecSynonymFilter) | low | Word2VecSynonymProvider returns maxSynonymsPerTerm + 1 synonyms when the query term is not among its own k+1 HNSW hits (tied vectors or an approximate-search miss), so Word2VecSynonymFilter emits one synonym more than the documented maximum | 1 |
| LFV-518 | suggest / spell: SpellChecker.indexDictionary (n-gram spell index build) | low | SpellChecker.indexDictionary checks for already-indexed words only against the spell index as it was before the call, so a word that one dictionary repeats is indexed once per occurrence and suggestSimilar returns it several times, pushing distinct suggestions out | 1 |
| LFV-566 | suggest / spell: SpellChecker.suggestSimilar (index-based n-gram spell checker; comparator vs. full-queue accuracy cutoff) | low | SpellChecker.suggestSimilar with SuggestWordFrequencyComparator drops more frequent suggestions: once the queue is full it raises the accuracy cutoff to the score of the least frequent queued word, which is a valid bound only for a score-first order (since 3.1, LUCENE-2479) | 1 |
| LFV-538 | suggest / spell (WordBreakSpellChecker word breaks) | low | WordBreakSpellChecker.suggestWordBreaks drops better suggestions when maxChanges >= 3: the full-queue early return added in 9.12.0 (GITHUB#12100) assumes a breadth-first order that the depth-first recursion does not follow | 1 |
| LFV-986 | suggest / spell checking (DirectSpellChecker.suggestSimilar candidate budget numSug * maxInspections) | low | DirectSpellChecker.suggestSimilar computes its candidate budget numSug * maxInspections in int: with setMaxInspections(Integer.MAX_VALUE) ('inspect everything') and any even numSug the budget wraps to -numSug, so the call throws NullPointerException or silently returns no suggestions | 1 |
| LFV-999 | suggest / document (NRT) suggester: NRTSuggester.lookup topN = num x prefix paths (SuggestIndexSearcher.suggest with ContextQuery, RegexCompletionQuery or FuzzyCompletionQuery; Util.TopNSearcher) | low | Document suggester: NRTSuggester computes topN = num * prefixPaths.size() in int, so when the product passes Integer.MAX_VALUE it wraps and SuggestIndexSearcher.suggest can silently return no suggestions or a truncated list (10^6 contexts in a segment: num 2147 returns 2147 suggestions, num 2148 returns none) | 1 |
| LFV-571 | queries / MoreLikeThis query construction (MoreLikeThis.createQuery truncation at IndexSearcher.getMaxClauseCount) | low | MoreLikeThis keeps the lowest-scoring selected terms when the query reaches the boolean clause limit, so the truncated query silently drops the most interesting terms (regression since 4.10.0) | 1 |
| LFV-1072 | suggest / spell (WordBreakSpellChecker word combinations) | low | WordBreakSpellChecker.suggestWordCombinations still applies minSuggestionFrequency under SUGGEST_MORE_POPULAR, although the setter says it does not apply in that mode (suggestWordBreaks follows the setter), so valid combined words are silently dropped | 1 |
| LFV-1073 | suggest / spell (WordBreakSpellChecker word combinations) | low | WordBreakSpellChecker.suggestWordCombinations looks every combined word up in the field of terms[0], so a leading SEPARATOR_TERM silently disables all combination suggestions | 1 |
| LFV-800 | suggest / spell (WordBreakSpellChecker word breaks) | low | WordBreakSpellChecker.suggestWordBreaks ignores a maxChanges below 1: with setMaxChanges(0) it still returns one-break suggestions, while suggestWordCombinations returns none | 1 |
| LFV-373 | analysis / hunspell (Hunspell.spell compound checking) | low | Hunspell spell-checker: CHECKCOMPOUNDTRIPLE misses an x|xx triple letter (one letter before the boundary, two after) at the second and later boundaries of a compound, so words such as operabareeel (opera + bare|eel) are accepted (absolute break position compared with the tail's relative length) | 1 |
| LFV-731 | analysis / hunspell (Hunspell.spell compound checking, COMPOUNDRULE) | low | Hunspell spell() skips the per-entry checks on COMPOUNDRULE compound parts, so it accepts compounds that C Hunspell rejects: a KEEPCASE first part in capitalized or upper case, a FORCEUCASE last part in lower case, and a NEEDAFFIX or FORBIDDENWORD entry as a first or middle part | 1 |
| LFV-639 | analysis / hunspell (WordFormGenerator: getAllWordForms, generateAllSimpleWords) | low | Hunspell getAllWordForms and generateAllSimpleWords return no forms for an entry with a COMPOUNDBEGIN, COMPOUNDMIDDLE or COMPOUNDEND flag and drop every affix whose continuation class has one, although spell() accepts those words on their own: with 'COMPOUNDBEGIN B' and foo/AB, getAllWordForms("foo") = [] instead of [foo, foos] (Swedish sv_SE: förökelse/AEIXY gives []) | 1 |
| LFV-932 | analysis / hunspell (Dictionary FLAG UTF-8 parsing under the SET encoding) | low | Hunspell Dictionary with FLAG UTF-8 and an 8-bit SET other than ISO8859-1 silently merges UTF-8 flags that share a lead byte, so spell() and the stemmer accept forms the dictionary forbids (some SET values fail to load instead) | 1 |
| LFV-693 | analysis-stempel / egothor stemmer trie reductions (Optimizer, Optimizer2; Compile tool, Trie.reduce) | low | Stempel: running Optimizer or Optimizer2 on an already merge-reduced trie silently corrupts it, because Optimizer.optimize remaps references to rows it has not placed yet to row 0 | 1 |
| LFV-694 | analysis/stempel / egothor stemmer table serialization (Row.store vs Row(DataInput); Gener, Compile 'G', StempelStemmer.load) | low | Stempel's Row.store writes the count of all cells but skips the empty ones, so a stemmer table reduced with Gener (Compile method letter G) fails to load with EOFException or loads misaligned and gives wrong stems | 1 |
| LFV-377 | analysis / hunspell (Hunspell.spell and suggest compound checking, CHECKCOMPOUNDPATTERN replacements) | low | Hunspell spell-checker: a CHECKCOMPOUNDPATTERN simplified compound form (the optional replacement field) after the first compound part is checked from the start of the whole word, so valid compounds such as dampfschiffahrt (dampf + schiff|fahrt with 'ff f ff') are rejected and some words (schiffschiffahrt, or auu with 'u u u') make spell()/suggest() throw StackOverflowError (expandReplacement returns offset 0 over an array that still holds the earlier parts) | 1 |
| LFV-374 | analysis / hunspell (affix conditions: Dictionary loading, Hunspell.spell/getRoots, Stemmer and HunspellStemFilter) | low | Hunspell: a bracket or dot affix condition with fewer character patterns than the strip is checked against the wrong end of the strip (a suffix rule at the strip's start, a prefix rule at its end), so the rule never applies when it should, or always applies when it should not | 1 |
| LFV-642 | analysis / hunspell (Stemmer affix compatibility: COMPLEXPREFIXES twofold prefixes) | low | Hunspell COMPLEXPREFIXES accepts a second prefix after an inner prefix rule whose continuation class does not allow it: with 'PFX A 0 re', 'PFX C 0 un', 'PFX C 0 dis/A' and foo/C, spell("reunfoo") is true and HunspellStemFilter stems reunfoo to foo, although only dis, not un, allows re (a regression since 9.5.0) | 1 |
| LFV-638 | analysis / hunspell (WordFormGenerator: canStemToOriginal, getAllWordForms, generateAllSimpleWords, compress) | low | Hunspell getAllWordForms, generateAllSimpleWords and compress return words that spell() rejects: the sanity check canStemToOriginal accepts any affix path that strips a form back to the stem text, so with 'NEEDAFFIX X', 'SFX A 0 s/XB', an unrelated 'SFX C 0 s' and foo/A, getAllWordForms("foo") returns foos | 1 |
| LFV-376 | analysis / hunspell (AffixCondition: affix conditions used by Hunspell.spell/suggest and by stemming through Stemmer/HunspellStemFilter) | low | Hunspell: the part of an affix condition that overlaps the strip is checked with java.util.regex without escaping the dash, so a bracket such as [a-c] there means the range a..c instead of the set {a, -, c} that hunspell(5) defines, and the rule is applied or dropped wrongly | 1 |
| LFV-724 | analysis / hunspell (Hunspell.spell compound checking, COMPOUNDWORDMAX) | low | Hunspell spell() accepts two-word flag-based compounds (COMPOUNDFLAG or COMPOUNDBEGIN/END) when COMPOUNDWORDMAX is 1 (or 0, which the parser clamps to 1), because the word-count check skips the first compound part | 1 |
| LFV-634 | analysis / hunspell (WordFormGenerator: getAllWordForms, generateAllSimpleWords, compress) | low | Hunspell getAllWordForms, generateAllSimpleWords and compress never generate a suffix that only a prefix's continuation class allows: with ampere/U and 'PFX U 0 kilo/S', spell() accepts amperes and kiloamperes, but getAllWordForms("ampere") returns only [ampere, kiloampere] | 1 |
| LFV-318 | index / addIndexes reorder path: SlowCompositeCodecReaderWrapper doc-ID-to-reader lookup (stored fields, term vectors), reached through misc BPReorderingMergePolicy or any OneMerge#reorder | low | A reordered addIndexes(CodecReader...) silently drops the stored fields and term vectors of the first document after an empty (maxDoc 0) input reader: SlowCompositeCodecReaderWrapper.docIdToReaderId keeps an Arrays.binarySearch hit on a repeated doc start and reads that document from the empty reader | 1 |
| LFV-1133 | index / index sorting at merge: MultiSorter doc maps, reached through IndexWriter.addIndexes(CodecReader...) | low | Index-sorted IndexWriter.addIndexes(CodecReader...) with an empty (maxDoc 0) input reader silently writes a corrupt segment: MultiSorter gives the empty reader's nonexistent doc 0 a merged doc id, so the postings of later documents point one document too far | 1 |
| LFV-788 | memory / MemoryIndex reader FieldInfos vs term vectors (consequence in index / addIndexes(CodecReader...) term-vector merge) | low | MemoryIndex returns term vectors for fields whose FieldInfo says storeTermVector=false (a regression of LUCENE-6402 since 6.5.0), so its reader fails CheckIndex and IndexWriter.addIndexes(SlowCodecReaderWrapper.wrap(reader)) writes a segment that CheckIndex rejects | 1 |
| LFV-325 | monitor / query decomposition (QueryDecomposer.decomposeBoolean) | low | Monitor's QueryDecomposer ignores minimumNumberShouldMatch=1 when a BooleanQuery has one required clause and no usable SHOULD clause, so Monitor.match reports queries that match nothing | 1 |
| LFV-853 | monitor / query decomposition (QueryDecomposer.decomposeBoolean; ScoringMatch, ExplainingMatch) | low | Monitor's QueryDecomposer turns a BooleanQuery whose only required clause is a single FILTER clause into that clause as a scoring query, so ScoringMatch and ExplainingMatch report a positive score for a query (or query part) that scores 0, and twice the true score when such a query is nested in a disjunction | 1 |
| LFV-773 | monitor / read-only query index (ReadonlyQueryIndex.purgeCache refresh) | low | A read-only Monitor's purgeCache() returns without refreshing when another refresh is running, so a query committed before the call can stay invisible after it returns | 1 |
| LFV-856 | monitor / query decomposition and match scoring (QueryDecomposer Set<Query> parts, ScoringMatch/ExplainingMatch resolve) | low | Lucene Monitor's QueryDecomposer collects a query's parts in a Set, so a sub-query that occurs more than once in a registered query (a repeated SHOULD or MUST clause, or a term shared by two nested disjunctions) is scored once by ScoringMatch and ExplainingMatch instead of once per occurrence | 1 |
| LFV-915 | monitor / HighlightsMatch hit set (Hit.compareTo used as TreeSet identity) | low | Monitor HighlightsMatch drops a hit when another hit has the same positions but different offsets (for example shingles or multi-word synonyms), because HighlightsMatch.Hit.compareTo ignores offsets | 1 |
| LFV-337 | analysis / WordDelimiterGraphFilter catenation runs (CATENATE_WORDS, CATENATE_NUMBERS; WordDelimiterIterator character types; factory 'types' option; term-level half shared with the deprecated WordDelimiterFilter) | low | WordDelimiterGraphFilter catenates non-adjacent subwords and gives catenations a too-long position length when a catenation run starts with a subword typed ALPHA|DIGIT (any supplementary character such as an emoji, or a character mapped to ALPHANUM in a types table), so graph phrase queries can match documents that lack a subword (released since 6.5.0) | 1 |
| LFV-876 | analysis-common / Thai (ThaiCharFilter.read single-pass look-ahead; the 'thai' char filter factory and the default ThaiAnalyzer as consumers; new in 10.6.0) | low | ThaiCharFilter tests its multi-character rules (double Sara E, decomposed Sara Am, tone mark before an above/below vowel) on the raw look-ahead characters, before its own zero-width removal and deduplication have run on them, so a zero-width character or a repeated tone mark inside such a pattern leaves the anomaly in the output and the default ThaiAnalyzer merges the word with its neighbours | 1 |
| LFV-873 | analysis-common / Thai (ThaiNormalizer.normalize rule order; ThaiNormalizationFilter, the 'thaiNormalization' factory and the default ThaiAnalyzer as consumers; new in 10.6.0) | low | ThaiNormalizer looks for a decomposed Sara Am before it converts Lakkhangyao or removes an extra tone mark, so its output can still be the decomposed form (Nikhahit + tone + Sara Aa), and the default ThaiAnalyzer indexes น้ำ ('water') typed with two tone marks inside a decomposed Sara Am as a different term | 1 |
| LFV-621 | analysis-opennlp / sentence-aware filters (SentenceAttributeExtractor.extractSentenceAttributes, shared by OpenNLPPOSFilter, OpenNLPChunkerFilter and OpenNLPLemmatizerFilter; factories opennlpPOS, opennlpChunker, opennlplemmatizer) | low | OpenNLP POS, chunker and lemmatizer filters emit no token for a whole field value when an earlier filter removes every token of its first sentence, because SentenceAttributeExtractor starts at sentence index 0 and reads a first token from sentence 1 as an empty sentence, which the filters take as the end of the stream | 1 |
| LFV-616 | analysis / kuromoji JapaneseTokenizer n-best output (analysis-common morph.ViterbiNBest.fixupPendingList) | low | JapaneseTokenizer n-best output (nBestCost > 0) with the default discardPunctuation=true gives a dictionary word that spans a discarded punctuation character (アイワ・コーポ) a position length one too long, so its path in the token graph skips the next word and a QueryBuilder query for アイワ・コーポ東京支店 makes 東京 optional | 1 |
| LFV-354 | analysis / WordDelimiterGraphFilter final position increment (end of stream, accumPosInc) | low | WordDelimiterGraphFilter drops the hole of a swallowed last token (a punctuation-only token such as the '--' in 'foo --', or a token whose parts the flags all switch off) and any stop-word hole that token carries, because it has no end() override, so the final position increment is 0 and the next value of a multi-valued field starts too early (released since 6.5.0) | 1 |
| LFV-532 | analysis / common n-gram token filters (NGramTokenFilter, EdgeNGramTokenFilter: final position increment in end()) | low | NGramTokenFilter and EdgeNGramTokenFilter end() overwrite the input's final position increment instead of adding to it, so a trailing hole (such as a removed trailing stop word) is lost and the next value of a multi-valued field starts too early (released since 7.4.0) | 1 |
| LFV-542 | analysis / common miscellaneous (ConditionalTokenFilter#end and OneTimeWrapper#end: final position increment on the delegate branch) | low | ConditionalTokenFilter (ProtectedTermFilter, CustomAnalyzer when()/whenTerm()) reports a final position increment of 0 when the last token went through the wrapped filters, so a trailing hole from upstream (such as a removed trailing stop word) is lost and the next value of a multi-valued field starts one position too early (since 7.4.0) | 1 |
| LFV-488 | analysis / common miscellaneous (ConcatenatingTokenStream#incrementToken and #end: carry-over of child final position increments) | low | ConcatenatingTokenStream loses a source's trailing position increment (for example a removed stop word) when the next source produces no tokens, so later tokens are indexed too close and phrase queries over-match | 1 |
| LFV-517 | analysis-common / ConcatenateGraphFilter and ConcatenateGraphFilterFactory (custom tokenSeparator) | low | ConcatenateGraphFilter treats a custom tokenSeparator as its internal one-byte separator label: an ASCII separator is doubled wherever it already occurs inside a token ('e-mail' becomes 'e--mail'), and a non-ASCII separator fails an assertion with -ea or is written as one truncated byte with -da (U+2013 becomes U+0013, U+00B7 a lone 0xB7 byte, i.e. invalid UTF-8) | 1 |
| LFV-522 | suggest / document (NRT) suggester (ContextSuggestField context validation; the context then passes through ConcatenateGraphFilter's SEP_LABEL escaping and HOLE removal) | low | ContextSuggestField accepts contexts that contain U+001E or U+001F although its javadoc promises an IllegalArgumentException for reserved characters; the completion analysis then drops U+001E (a suggestion indexed under context 'a<U+001E>b' is stored as, returned for and labelled with the exact context 'ab') and doubles U+001F (context 'a<U+001F>b' never matches its own exact query and is reported as 'a<U+001F><U+001F>b') | 1 |
| LFV-601 | suggest / analyzing suggester (AnalyzingSuggester FST input encoding: analyzed form + END_BYTE 0x00 + dedup byte, inherited by FuzzySuggester; Util.TopNSearcher result path) | low | AnalyzingSuggester and FuzzySuggester do not escape the 0x00 byte that ends each analyzed form, so a U+0000 in a suggestion or key makes them return the same suggestion twice, lose the EXACT_FIRST exact match, or return entries that do not start with the key | 1 |
| LFV-982 | suggest / FreeTextSuggester (n-gram suggester; build() failure atomicity of the unigram token total) | low | FreeTextSuggester.build() resets its unigram token total before it reads the input, so a rebuild that throws (an empty dictionary, an IOException from the input, or build()'s own separator-byte rejection) leaves the previous model scored against a zero or partial total: unigram suggestions get wrong scores (every one Long.MAX_VALUE, i.e. 1.0, when the total is 0), a backed-off unigram outranks the real bigram predictions, and store() persists it | 1 |
| LFV-784 | suggest / analyzing suggester (AnalyzingSuggester.build failure atomicity: hasPayloads is published before the new FST; inherited by FuzzySuggester) | low | AnalyzingSuggester and FuzzySuggester take the new input's payload flag before build() can fail, so after a failed rebuild (or during a rebuild) lookups decode the previous FST in the wrong payload format: the payload glued to the suggestion text, or the suggestion returned as the payload | 1 |
| LFV-979 | suggest / Lookup persistence (load() failure atomicity: TSTLookup, AnalyzingSuggester, FuzzySuggester, FreeTextSuggester, FSTCompletionLookup, WFSTCompletionLookup) | low | Suggest Lookup.load() assigns its count and model fields while it is still reading the stream, so a load that throws (a stored copy cut short, a read failure, or FreeTextSuggester rejecting a model saved with other settings) leaves a mix of the previous and the new model: TSTLookup serves part of the new tree and some lookups throw NullPointerException, AnalyzingSuggester/FuzzySuggester can decode the new FST with the old payload flag, FreeTextSuggester scores the old FST with the new token total, and FST/WFSTCompletionLookup report the new count over the old FST | 1 |
| LFV-763 | classification / Naive Bayes classifiers (CachingNaiveBayesClassifier, SimpleNaiveBayesDocumentClassifier vs SimpleNaiveBayesClassifier, BM25NBClassifier) | low | CachingNaiveBayesClassifier and SimpleNaiveBayesDocumentClassifier offer and assign the empty class term '', which SimpleNaiveBayesClassifier and BM25NBClassifier skip, so the Naive Bayes classifiers disagree on the same index | 1 |
| LFV-510 | analysis / common miscellaneous (ProtectedTermFilterFactory#populateInnerFilters: wrappedFilters factory construction; symptom in TruncateTokenFilterFactory prefixLength) | low | ProtectedTermFilterFactory does not pass its luceneMatchVersion to the filters it builds from wrappedFilters, so since 10.5 a wrapped truncate with prefixLength under a pinned pre-10.5 version truncates by code points instead of the legacy UTF-16 chars | 1 |
| LFV-857 | analysis / icu (ICUFoldingFilter UTR#30 folding data: the gennorm2 input order of the utr30.nrm regeneration step in lucene/analysis/icu/build.gradle, and the shipped utr30.nrm) | low | Since 9.0 the utr30.nrm build passes gennorm2 its inputs sorted by file name, so the standard NFKC data overrides Lucene's own UTR#30 folding tables and ICUFoldingFilter turns spacing accents such as ´ ¨ ¯ ¸ into a space inside the term instead of removing them, while ` and ^ are still removed | 1 |
| LFV-1119 | analysis / icu (ICUTransformFilterFactory: 'direction' parameter parsing through AbstractAnalysisFactory.get(..., caseSensitive=false)) | low | ICUTransformFilterFactory accepts direction="Forward" or "FORWARD" without error (it validates the value case-insensitively) but then builds the reverse transliterator, so every token is silently transformed the wrong way (regression of LUCENE-4877, since 4.3.0) | 1 |
| LFV-956 | analysis-common / synonym file loading (SynonymGraphFilterFactory and the deprecated SynonymFilterFactory loadSynonyms -> SolrSynonymParser, WordnetSynonymParser) | low | SynonymGraphFilterFactory and SynonymFilterFactory keep a UTF-8 byte order mark at the start of a synonyms file, so the file's first rule silently stops working and a commented-out first line that contains a comma becomes a live rule | 1 |
| LFV-950 | analysis-kuromoji + analysis-nori / user dictionary loading (UserDictionary.open, reached through the JapaneseTokenizerFactory / KoreanTokenizerFactory userDictionary argument) | low | Kuromoji and Nori UserDictionary.open keep a leading UTF-8 byte order mark, so Nori silently drops the first user-dictionary entry and Kuromoji refuses to load the file | 1 |
| LFV-990 | suggest / text-file dictionaries (FileDictionary feeding Lookup.build, PlainTextDictionary feeding SpellChecker.indexDictionary) | low | FileDictionary(InputStream) and PlainTextDictionary(Path/InputStream) decode the file as UTF-8 themselves but keep a leading byte order mark, so the file's first entry carries an invisible U+FEFF: prefix suggesters never suggest it and SpellChecker.exist() does not find it | 1 |
| LFV-718 | core + analysis-common + suggest / words-file factories (format="snowball" loader: AbstractAnalysisFactory.getSnowballWordSet, WordlistLoader.getSnowballWordSet) | low | With format="snowball", StopFilterFactory, KeepWordFilterFactory, CommonGramsFilterFactory and SuggestStopFilterFactory keep a leading UTF-8 byte order mark glued to the first word of the words file, so that word silently stops matching, while the default "wordset" format of the same factories strips the mark | 1 |
| LFV-719 | analysis / ICU (ICUTokenizerFactory per-script rule files: rulefiles, parseRules) | low | ICUTokenizerFactory keeps the UTF-8 byte order mark at the start of a custom per-script rule file (rulefiles) as rule text, so the file either fails with a misleading ICU syntax error or loads without error and the tokenizer then emits no tokens for that script (every release since 4.1.0) | 1 |
| LFV-696 | analysis/stempel / egothor stemmer trie reductions (Trie.reduce with Lift and Gener; the shared PolishAnalyzer.getDefaultTable() table) | low | Stempel's Trie.reduce with Gener or Lift rewrites the cells of the trie it is given, so reducing PolishAnalyzer.getDefaultTable(), documented as unmodifiable, silently changes the stems of every later PolishAnalyzer and StempelPolishStemFilterFactory in the JVM | 1 |
| LFV-598 | analysis / analysis-common payloads (DelimitedPayloadTokenFilterFactory, PayloadEncoder, DelimitedPayloadTokenFilter) | low | DelimitedPayloadTokenFilterFactory creates one instance of a custom PayloadEncoder class and hands it to every filter it creates, so all threads using the analyzer share it, and nothing documents that a custom encoder must be thread-safe: an encoder that reuses its BytesRef silently stores other documents' payloads during ordinary concurrent indexing, and one whose payloads vary in length makes the next flush throw and the IndexWriter close itself | 1 |
| LFV-605 | analysis / kuromoji romanization (ToStringUtil.getRomanization; JapaneseReadingFormFilter romaji mode) | low | Kuromoji's romaji reading (ToStringUtil.getRomanization, used by JapaneseReadingFormFilter with useRomaji=true) writes the small tsu ッ as a doubled consonant only before the k, s, t and p rows and silently drops it before any other kana, so loanwords with ッ before g, z/j, d, b or h/f lose it: バッグ 'bag' and バグ 'bug' both become 'bagu', ベッド becomes 'bedo' | 1 |
| LFV-850 | analysis / kuromoji (JapaneseCompletionFilter and JapaneseCompletionAnalyzer romanization data: the bundled table romaji_map.txt that KatakanaRomanizer reads) | low | Kuromoji's completion table romaji_map.txt has no rows for チェ, イェ, ツァ/ツィ/ツェ/ツォ, ディ/デュ and ウォ, although it has rows for their siblings (チャ/チュ/チョ, シェ/ジェ, ッイェ, ティ/テュ, ウィ/ウェ), so raw-romaji prefixes such as 'che', 'ye' and 'tsa' suggest nothing for words like チェック, イェール and ツァー | 1 |
| LFV-848 | analysis / kuromoji (JapaneseCompletionFilter and JapaneseCompletionAnalyzer romanization table romaji_map.txt, read by KatakanaRomanizer) | low | Kuromoji's completion table romaji_map.txt has three typo rows: the ッヘ row uses a hiragana へ (U+3078) in its key, so katakana ッヘ is romanized 'xtuhe' instead of 'hhe' and a word like ヨッヘン is not suggested for 'yohhen', and the ッスォ and ッドゥ rows carry the copied spellings 'suxo' and 'ddoxi' | 1 |
| LFV-854 | analysis / kuromoji completion (JapaneseCompletionFilter QUERY-mode handling of mid-IME composition; the partial-input rows of romaji_map.txt, read by KatakanaRomanizer) | low | Kuromoji completion suggester (JapaneseCompletionAnalyzer / JapaneseCompletionFilter, QUERY mode) suggests nothing while an input method shows a small tsu plus a pending c, j, f or v ('まっc' while typing maccha for 抹茶, 'ばっj' for bajji, 'すたっf' for sutaffu), because romaji_map.txt has the partial-input rows ッk..ッw but none for ッc, ッj, ッf or ッv, although its full rows double those letters (ッチャ ccha, ッジ jji, ッフ ffu, ッヴ vvu) | 1 |
| LFV-607 | analysis-kuromoji / Japanese char filters (JapaneseIterationMarkCharFilter kana iteration marks ゝ/ヽ: isHiraganaDakuten / isKatakanaDakuten over the h2d / k2d voicing tables, used by normalizedHiragana / normalizedKatakana; JapaneseIterationMarkCharFilterFactory 'japaneseIterationMark') | low | JapaneseIterationMarkCharFilter expands the unvoiced kana iteration mark ゝ/ヽ after the na-row, the small tsu and the handakuten kana (な に ぬ ね の, っ, ぱ ぴ ぷ ぺ and their katakana forms) to a different kana, so なゝめ becomes などめ instead of ななめ (のゝしる becomes のねしる, ぱゝ becomes ぱば), because kana that have no voiced form are stored as self-mappings in the voicing table and the 'is voiced' check reads every self-mapping as voiced | 1 |
| LFV-819 | analysis-common / ASCIIFoldingFilter mapping table (foldToASCII switch) | low | ASCIIFoldingFilter folds the ligature st (U+FB06) to 'st' but has no entry for its sibling ſt (U+FB05 LATIN SMALL LIGATURE LONG S T, NFKD 'st'), so 'faſt' is indexed unchanged and the ASCII query 'fast' does not find it | 1 |
| LFV-877 | analysis / icu (ICUFoldingFilter UTR#30 folding data: the hand-written 'Rule: verbatim' Cyrillic block of DiacriticFolding.txt, compiled into utr30.nrm) | low | ICUFoldingFilter removes the hook, stroke or descender from older Cyrillic letters such as ҧ (U+04A7) but from none of the 24 letters of that kind added in Unicode 4.1-7.0, such as its modern Abkhaz counterpart ԥ (U+0525), so the two spellings of a word give different terms | 1 |
| LFV-688 | analysis-common / es (SpanishPluralStemmer special-case list, SpanishPluralStemFilter) | low | SpanishPluralStemmer's special-case list has the singular 'contrarreloj' where the plural 'contrarrelojes' belongs, so the singular is cut to 'contrarrel', the plural stems to 'contrarreloje', and the two forms never match | 1 |
| LFV-669 | analysis-common / Telugu normalizer (TeluguNormalizer.normalize; TeluguNormalizationFilter and the 'teluguNormalization' factory) | low | TeluguNormalizer composes ఒ + ౌ (U+0C12 LETTER O + U+0C4C VOWEL SIGN AU) into AU (U+0C14) but never applies its own AU -> OO fold to the result, so in a chain without IndicNormalizationFilter in front the two spellings of AU normalize to different terms | 1 |
| LFV-459 | analysis / kuromoji and nori Viterbi unknown-word length cap (JapaneseTokenizer and the 'japanese' factory; KoreanTokenizer, KoreanAnalyzer and the 'korean' factory) | low | JapaneseTokenizer and KoreanTokenizer cut an unknown word at the 1024-char cap (MAX_UNKNOWN_WORD_LENGTH) even in the middle of a surrogate pair, so a supplementary character (an emoji, a CJK Extension B ideograph) at char 1023 of a long same-class run is emitted as two unpaired surrogate halves and indexed as U+FFFD | 1 |
| LFV-749 | analysis / kuromoji and nori Viterbi tokenizers, discardPunctuation (ja.ViterbiNBest.isPunctuation and its three discard sites, ko.Viterbi.shouldFilterToken) | low | JapaneseTokenizer and KoreanTokenizer with discardPunctuation=true (the default) keep punctuation and symbols outside the BMP (U+10100, U+1E95E, emoji such as U+1F600) as tokens, because isPunctuation classifies a single UTF-16 unit (the high surrogate), while BMP characters of the same general category are dropped (released since 3.6.0 and 7.4.0) | 1 |
| LFV-720 | analysis / ICU (DefaultICUTokenizerConfig syllable rules MyanmarSyllable.rbbi / MyanmarSyllable.brk, used for Myanmar text when myanmarAsWords=false; ICUTokenizerFactory 'icu' with myanmarAsWords="false") | low | ICUTokenizer with myanmarAsWords=false silently drops the Myanmar modifier letters U+A9E6 and U+AA70 (Shan and Khamti reduplication, as in 'ကꧦ'), and Common-script letters such as MICRO SIGN that fall into a Myanmar run, because MyanmarSyllable.rbbi gives a token status only to syllables and numbers | 1 |
| LFV-738 | analysis / UAX29URLEmailTokenizer JFlex URL rules (FTPurl production; analysis-common) | low | UAX29URLEmailTokenizer does not emit an ftp URL with no path ('ftp://host') as one URL token, although its http rule and RFC 1738 make the path optional | 1 |
| LFV-895 | analysis-common / util CSVUtil (CSV line parsing for the kuromoji user dictionary and the kuromoji/nori dictionary builders) | low | CSVUtil.parse decodes every quoted field except the last one of the line, so a quoted last field (for example the part-of-speech of a kuromoji user-dictionary entry) keeps its quote characters | 1 |
| LFV-889 | analysis-common / util CSVUtil (CSV line parsing for the kuromoji user dictionary and the kuromoji/nori dictionary builders) | low | CSVUtil.parse keeps the enclosing quotes of a field that holds both a comma and a double quote, so it does not decode CSVUtil.quoteEscape output | 3 |
| LFV-712 | analysis / kuromoji system dictionary builder (ja.dict.TokenInfoDictionaryEntryWriter reading and pronunciation length bytes; TokenInfoMorphData decoding; custom dictionaries built with DictionaryBuilder) | low | Kuromoji's DictionaryBuilder silently accepts a reading or pronunciation of 128 or more chars and stores its length in 7 bits, so the built system dictionary returns an empty or truncated reading and a garbage pronunciation (a too-long base form, by contrast, is rejected) | 1 |
| LFV-717 | analysis / nori system dictionary builder (DictionaryBuilder, TokenInfoDictionaryEntryWriter; custom system dictionaries) | low | Nori's DictionaryBuilder checks that rows sharing a left context id have the same part of speech only with a Java assert, so with assertions off a custom system dictionary silently gives those words the part of speech of another row and KoreanPartOfSpeechStopFilter drops or keeps them wrongly | 1 |
| LFV-710 | analysis / nori system dictionary builder (DictionaryBuilder, TokenInfoDictionaryEntryWriter; custom system dictionaries) | low | Nori's DictionaryBuilder rejects a left context id of 8192 or more but silently accepts such a right context id, which does not round-trip through the compiled format, so the compiled dictionary returns a wrapped right id (changing segmentation) or makes KoreanTokenizer throw IndexOutOfBoundsException | 1 |
| LFV-545 | analysis / pattern tokenizers (analysis-common: SimplePatternTokenizer, SimplePatternSplitTokenizer and their simplePattern / simplePatternSplit factories) | low | SimplePatternTokenizer and SimplePatternSplitTokenizer restart a failed match one UTF-16 unit after a supplementary start character, so they can emit tokens that start or end inside a surrogate pair | 1 |
| LFV-685 | analysis-common / ga (IrishLowerCaseFilter and IrishAnalyzer case mapping) | low | IrishLowerCaseFilter lower-cases one UTF-16 unit at a time, so IrishAnalyzer leaves upper-case letters outside the BMP (Adlam, Osage, Deseret and others) unchanged | 1 |
| LFV-477 | analysis / phonetic (DoubleMetaphoneFilter#incrementToken alternate-code branch; DoubleMetaphoneFilterFactory, SPI name doubleMetaphone) | low | DoubleMetaphoneFilter drops the alternate (secondary) code of a token whose text already equals its primary code, so 'JR' gets only JR while 'jr' gets JR and AR | 1 |
| LFV-535 | analysis-common / miscellaneous (CapitalizationFilter, CapitalizationFilterFactory) | low | CapitalizationFilter treats a second delimiter in a row ('. ', a double space) or a delimiter at the start of the token as the first character of the next word, so that word is not capitalized and misses keep, okPrefix and minWordLength ('dr. jekyll' -> 'Dr. jekyll', 'new york' -> 'New york', ' hello' -> ' hello') | 2 |
| LFV-533 | analysis-common / miscellaneous (CapitalizationFilter case mapping) | low | CapitalizationFilter changes case one UTF-16 char at a time, so cased letters outside the BMP (Adlam, Osage, Deseret and five other scripts) are neither capitalized nor lower-cased, while BMP letters in the same token are | 1 |
| LFV-752 | analysis-common / Sorani normalizer (SoraniNormalizer.normalize; SoraniNormalizationFilter, SoraniAnalyzer and the 'soraniNormalization' factory) | low | SoraniNormalizer tests for format characters one UTF-16 char at a time, so format characters outside the BMP (U+E0001, the tag characters U+E0020..U+E007F, U+1BCA0..U+1BCA3, U+1D173..U+1D17A and others) are kept in the term, while BMP ones such as RLM and LRM are removed | 1 |
| LFV-350 | suggest / spell checking (LuceneLevenshteinDistance.getDistance, the StringDistance class behind DirectSpellChecker.INTERNAL_LEVENSHTEIN) | low | LuceneLevenshteinDistance.getDistance returns 0 for two empty strings and max(n, m) (for example 3.0) when one string is empty, instead of a similarity score (a 2011 regression from LUCENE-3662) | 1 |
| LFV-049 | util / automaton | low | Operations.isTotal returns true for a deterministic automaton that can reach a dead state, so an AutomatonQuery can match every term | 1 |
| LFV-845 | queryparser / classic and flexible standard grammars (Range lexical state, RANGE_GOOP token) | low | Classic QueryParser and flexible StandardQueryParser: a TAB, LF, CR or U+3000 next to a range bound inside [..] or {..} becomes part of the bound, because RANGE_GOOP excludes only U+0020 although both grammars declare these characters as whitespace and skip them in the Range state; such ranges fail to parse or, when the character touches a bracket, silently change their bounds | 1 |
| LFV-082 | queryparser / flexible | low | Flexible StandardQueryParser narrows out-of-range int literals with intValue(), so i:[2147483648 TO *] matches every document with the field | 1 |
| LFV-645 | core / document (DateTools date-to-string term encoding: timeToString/dateToString and stringToTime/stringToDate) | low | DateTools strings stop sorting by date and stop round-tripping outside years AD 1..9999: the 'yyyy' year-of-era pattern drops the BC era (2 BC sorts after AD 1 and parses back as AD 2; 1 BC and AD 1 give the same string) and gives years after 9999 a fifth digit (10000 sorts before 2026, and stringToTime throws ParseException on DateTools' own output) | 1 |
| LFV-283 | queryparser / classic and flexible date ranges (QueryParserBase.getRangeQuery, TermRangeQueryNodeProcessor; setTimeZone and ConfigurationKeys.TIMEZONE) | low | QueryParser.setTimeZone (and StandardQueryParser.setTimeZone) is used only to round the inclusive end of a date range to 23:59:59.999; both dates are still parsed in the JVM default time zone, so with a non-default zone d:[6/1/2005 TO 6/4/2005] covers a shifted window and exclusive ranges ignore the setting | 1 |
| LFV-1206 | core / document (DateTools string-to-date decoding: stringToDate and stringToTime) | low | DateTools.stringToDate and stringToTime parse with a lenient SimpleDateFormat and ignore trailing text, so a string of a supported length that is not in the yyyyMMdd... format ("2024123X", the ISO date "2019-12-31", month 13) silently returns another date instead of the documented ParseException (since 1.9) | 1 |
| LFV-1123 | core / document (DateTools resolution limiting: round(long, Resolution) and round(Date, Resolution)) | low | DateTools.round returns a time near Long.MAX_VALUE (AD 292278994) for Long.MIN_VALUE, and for times before the first resolution-unit boundary above it, instead of rounding down: the rounded-down time lies below the long range and the lenient Calendar arithmetic silently wraps | 1 |
| LFV-196 | search / phrase matching (ExactPhraseMatcher, SloppyPhraseMatcher and PhrasePositions position arithmetic; PhraseQuery.Builder and MultiPhraseQuery.Builder accept the positions) | low | The phrase matchers add a document position and a query position offset in int: with an offset near 2^31 an exact PhraseQuery or MultiPhraseQuery loops forever inside one document (IndexSearcher#setTimeout does not stop it) and a sloppy one returns false hits | 1 |
| LFV-397 | highlighter / original Highlighter, QueryScorer and WeightedSpanTermExtractor (phrase-to-span conversion) | low | Highlighter with the default QueryScorer returns no fragment for a matching PhraseQuery or MultiPhraseQuery that has a position hole (for example a removed stop word) and a slop within the number of holes of Integer.MAX_VALUE: WeightedSpanTermExtractor converts it to a SpanNearQuery with the plain int sum slop + positionGaps, which wraps to about Integer.MIN_VALUE, so the span query matches nothing | 1 |
| LFV-401 | highlighter / vectorhighlight BaseFragListBuilder (FastVectorHighlighter, SimpleFragListBuilder, WeightedFragListBuilder) | low | FastVectorHighlighter with fragCharSize = Integer.MAX_VALUE (or any value above Integer.MAX_VALUE - spanStart) returns the whole field with only the first match highlighted: BaseFragListBuilder computes spanStart + fragCharSize in int, the sum wraps negative, and every later match is silently dropped (SimpleFragListBuilder, the default, and WeightedFragListBuilder) | 1 |
| LFV-1091 | highlighter / classic Highlighter (OffsetLimitTokenFilter, maxDocCharsToAnalyze) | low | Classic Highlighter with QueryScorer drops matches inside setMaxDocCharsToAnalyze when tokens are stacked, because OffsetLimitTokenFilter adds up token lengths instead of checking start offsets (known: #7435 / LUCENE-6375) (released) | 1 |
| LFV-859 | highlighter / classic Highlighter fragmenting (SimpleSpanFragmenter.isNewFragment position counter; Highlighter.getBestTextFragments) | low | Classic Highlighter's SimpleSpanFragmenter splits a short phrase match across two fragments because its position counter lags the real token positions: the Highlighter never shows it the first token or tokens that overlap the previous one, so the phrase is recognised one or more words late and getBestFragment can return only half of it | 1 |
| LFV-861 | highlighter / classic Highlighter fragmenting (SimpleSpanFragmenter.start, state carried across texts) | low | Classic Highlighter's SimpleSpanFragmenter.start() does not reset waitForPos, so a Highlighter reused for the next text (or for the same text again) keeps suppressing fragment boundaries after a phrase match that ended the previous text: one oversized fragment, then one-word fragments and a different best fragment, depending on what was highlighted before | 1 |
| LFV-498 | highlighter / UnifiedHighlighter default summary (FieldHighlighter.getSummaryPassagesNoHighlight over the SplittingBreakIterator that splits multi-valued fields on MULTIVAL_SEP_CHAR) | low | UnifiedHighlighter's no-match summary of a multi-valued field counts the internal U+0000 value separator as a passage, so the summary contains a NUL character and shows one value or sentence fewer than requested | 1 |
| LFV-494 | highlighter / UnifiedHighlighter break iterators (LengthGoalBreakIterator#preceding under the SplittingBreakIterator that UnifiedHighlighter puts around every field's iterator, multi-valued fields) | low | UnifiedHighlighter with LengthGoalBreakIterator on a multi-valued field: a passage in a later value starts at the U+0000 value separator | 1 |
| LFV-887 | highlighter / classic Highlighter formatters (GradientFormatter, SpanGradientFormatter) | low | GradientFormatter and SpanGradientFormatter reverse the colour gradient on every channel where the min colour is larger than the max colour, so with the javadoc's own white-to-black example the top-scoring term is drawn white | 1 |
| LFV-858 | highlighter / classic Highlighter fragmenting (SimpleSpanFragmenter.isNewFragment; Highlighter.getBestTextFragments) | low | Classic Highlighter's SimpleSpanFragmenter splits a phrase match across fragments when two phrases overlap, when a longer phrase shares a shorter one's start (the result then depends on clause order), or when the phrase starts on stacked synonyms: it protects only the first span that starts at the current position, skips the span lookup while it waits for a span to end, and never sees a span that starts on a token the Highlighter does not show it | 1 |
| LFV-599 | highlighter / UnifiedHighlighter (multi-value joining with the in-band MULTIVAL_SEP_CHAR U+0000: SplittingBreakIterator, ANALYSIS re-analysis) | low | UnifiedHighlighter mistakes a U+0000 inside a stored value for its internal multi-value separator, so snippets are cut there and, with the ANALYSIS offset source, matches the query found are not highlighted | 1 |
| LFV-783 | highlighter / UnifiedHighlighter (multi-valued content: postings and term-vector offset sources vs Analyzer#getOffsetGap; LimitedStoredFieldVisitor value join) | low | UnifiedHighlighter with postings or term-vector offsets highlights the wrong characters, or drops the match, in the second and later values of a multi-valued field when the analyzer's offset gap is not 1 | 1 |
| LFV-913 | highlighter / UnifiedHighlighter re-analysis without a searcher (highlightWithoutSearcher: MemoryIndexOffsetStrategy reader == null branch + WEIGHT_MATCHES) | low | UnifiedHighlighter.highlightWithoutSearcher returns the text with no highlights under its default flags (WEIGHT_MATCHES) when the query also has a required or filter clause on another field | 1 |
| LFV-775 | highlighter / UnifiedHighlighter stored-value loading (LimitedStoredFieldVisitor maxLength cut) | low | UnifiedHighlighter cuts a stored value at maxLength UTF-16 units even between the two halves of a supplementary character (an emoji, a CJK Extension B ideograph), so the snippet can end in an unpaired high surrogate, for example '<b>Hello</b> \uD83D' | 1 |
| LFV-756 | highlighter / UnifiedHighlighter (highlightWithoutSearcher entry point, maxLength option) | low | UnifiedHighlighter.highlightWithoutSearcher ignores maxLength (the default 10,000 included): it analyzes and highlights the whole supplied text, although getMaxLength and Builder.withMaxLength document that content is truncated to maxLength before highlighting | 1 |
| LFV-496 | highlighter / UnifiedHighlighter break iterators (CustomSeparatorBreakIterator, alone or as the base of LengthGoalBreakIterator) | low | CustomSeparatorBreakIterator is off by one next to the separator: following(p) skips the break right after a separator at p, preceding(p) returns p itself, a leading separator is not a break and a trailing one makes next() return the end twice, so UnifiedHighlighter passages built on it start or end one segment off | 1 |
| LFV-622 | analysis / opennlp OpenNLPSentenceBreakIterator (java.text.BreakIterator implementation, next(int)) | low | OpenNLPSentenceBreakIterator.next(n) returns DONE instead of the end of the text when the n-th boundary is the last one, so next(1) differs from next() and a caller that steps with next(n) until DONE loses the final sentence group | 1 |
| LFV-623 | analysis-opennlp / OpenNLPSentenceBreakIterator (public java.text.BreakIterator over OpenNLP sentence spans: setText, previous, following, moveToSentenceAt) | low | OpenNLPSentenceBreakIterator on text that starts with whitespace: a backward walk with previous() returns a non-boundary and then throws ArrayIndexOutOfBoundsException, and following() at an offset inside the leading whitespace throws StackOverflowError, because setText keeps the sentence detector's whitespace-trimmed first sentence start while first() and next() use the text's begin index | 1 |
| LFV-180 | search / CachingCollector first pass and score-caching replay (CachingCollector, CachingCollectorManager) | low | CachingCollector (and CachingCollectorManager) never calls LeafCollector#finish on the collector it wraps, nor on the second-pass collector when it replays cached scores, so finish-dependent collectors such as FacetsCollector silently report no hits | 1 |
| LFV-880 | grouping / GroupReducer and SecondPassGroupingCollector (second-pass per-group collectors) | low | SecondPassGroupingCollector and GroupReducer never call LeafCollector#finish on the per-group leaf collectors, so a custom GroupReducer whose collector does its per-segment work in finish (for example a stock FacetsCollector per group) silently sees no documents | 1 |
| LFV-883 | grouping / GroupReducer and SecondPassGroupingCollector (second-pass per-group collectors) | low | GroupReducer lets one group's CollectionTerminatedException escape SecondPassGroupingCollector, so IndexSearcher ends the whole segment and every other group silently misses its remaining documents in that segment | 2 |
| LFV-468 | codecs / vectors (flat scalar-quantized format: byte kNN and byte similarity search) | low | The flat scalar-quantized vectors format (Lucene104ScalarQuantizedVectorsFormat) accepts BYTE vector fields but its byte search is a no-op, so unfiltered byte kNN and byte similarity queries return no hits | 3 |
| LFV-230 | grouping / block grouping (BlockGroupingCollector.getTopGroups group maxScore; GroupingSearch(Query) and BlockGroupingCollectorManager within-group paging) | low | Block grouping reports the wrong group maxScore when paging inside groups (withinGroupOffset > 0, relevance order): the score of the first document on the page, or -Infinity for an empty page; regression in 10.5.0 | 1 |
| LFV-1054 | grouping / GroupingSearch two-pass grouping (term, function and GroupSelector grouping), TopGroups.totalGroupCount | low | GroupingSearch with setAllGroups(true) returns totalGroupCount null ("not computed") for a query without hits or a page past the last group, although it computed the group count | 1 |
| LFV-407 | grouping / range group selectors (LongRangeFactory and DoubleRangeFactory, used by LongRangeGroupSelector and DoubleRangeGroupSelector) | low | Grouping LongRangeFactory and DoubleRangeFactory give the last range below max the full width, so its reported group bounds run past max and overlap the range for values >= max | 1 |
| LFV-412 | grouping / range group selectors (DoubleRangeFactory, used by DoubleRangeGroupSelector) | low | Grouping DoubleRangeFactory picks a value's bucket and computes that bucket's bounds with separately rounded arithmetic, so with a decimal width such as 0.1 the returned range can exclude the value and adjacent ranges leave gaps or overlap (DoubleRangeFactory(0, 0.1, 10).getRange(0.6) = DoubleRange(0.5, 0.6)) | 1 |
| LFV-411 | grouping / range group selectors (DoubleRangeFactory, used by DoubleRangeGroupSelector) | low | Grouping DoubleRangeFactory gives the below-min group the lower bound Double.MIN_VALUE (4.9E-324, the smallest positive double) instead of the most negative value, so that group's DoubleRange label does not contain its own members | 1 |
| LFV-881 | grouping / GroupingSearch doc-block path (BlockGroupingCollectorManager score mode) | low | GroupingSearch ignores setIncludeMaxScore for doc-block grouping: with field-only group and within-group sorts, TopGroups.maxScore and every GroupDocs.maxScore are NaN, while two-pass grouping with the same settings reports the real max scores (since 8.0.0) | 1 |
| LFV-511 | grouping / max-score reporting (TopGroupsCollector, BlockGroupingCollector) | low | Grouping starts its running maxScore at Float.MIN_VALUE (the smallest positive float), so TopGroups.maxScore and GroupDocs.maxScore report 1.4E-45 instead of 0 when every hit scores 0, and since 10.5.0 (#15873) TopGroupsCollector.getTopGroups reports 1.4E-45 instead of NaN when no scores were computed | 1 |
| LFV-064 | codecs / vectors | low | Quantized MIP/EUCLIDEAN scores become NaN when OSQ correction terms overflow | 1 |
| LFV-1120 | core / search: late-interaction rescoring (LateInteractionField, LateInteractionFloatValuesSource, LateInteractionRescorer) | low | LateInteractionField and LateInteractionFloatValuesSource accept all-zero (and non-finite) token vectors, so late-interaction rescoring under its default COSINE gives the document a NaN score (AssertionError in VectorUtil.cosine with -ea) | 1 |
| LFV-140 | document / range fields (DoubleRange, FloatRange, their doc-values fields; facet range-on-range) | low | DoubleRange and FloatRange accept the bounds [0.0, -0.0] and store them inverted, so range queries silently miss such documents and contradict each other (WITHIN [0,0] but not INTERSECTS [0,0]) | 1 |
| LFV-310 | facet / range facet counts (DoubleRange bounds and values converted to sortable longs in DoubleRangeFacetCounts, against DoubleRange.accept and getQuery) | low | DoubleRangeFacetCounts orders -0.0 below +0.0 while DoubleRange.accept and getQuery treat the two zeros as equal: a document holding a zero of the opposite sign at an inclusive zero bound (for example -0.0 in [0, 1]) is matched by the range's own drill-down but not counted, and the accepted range [+0.0, -0.0] makes counting throw | 1 |
| LFV-313 | facet / range, rangeonrange and facetset (exclusive-bound adjustment of double and float ranges: range.DoubleRange, rangeonrange.DoubleRange, facetset.DimRange.fromDoubles/fromFloats) | low | Facet DoubleRange, range-on-range DoubleRange and DimRange.fromDoubles/fromFloats do not exclude an exclusive bound that is an infinity: the empty ranges (+Inf, +Inf] and [-Inf, -Inf) are accepted and match the +Infinity / -Infinity documents instead of matching nothing | 1 |
| LFV-1131 | facet / facetset and rangeonrange (exclusive-bound stepping of double and float ranges: facetset.DimRange.fromDoubles/fromFloats with RangeFacetSetMatcher, rangeonrange.DoubleRange with DoubleRangeOnRangeFacetCounts) | low | Facet-set DimRange.fromDoubles/fromFloats (and range-on-range DoubleRange) make an exclusive bound inclusive with Math.nextUp/Math.nextDown, which skip the other signed zero, so a facet set holding -0.0 is counted by neither of the adjacent ranges [-1, 0) and [0, 1] | 1 |
| LFV-416 | queries / function queries (FunctionRangeQuery range scorers: DoubleDocValues.getRangeScorer and the float default FunctionValues.getRangeScorer) | low | FunctionRangeQuery over a double or float source drops -Infinity / +Infinity documents when an omitted (null) bound is marked exclusive ({* TO x] or [x TO *}), while int, long, enum and string sources treat an omitted bound as unbounded | 1 |
| LFV-1108 | queries / function queries (DocTermsIndexDocValues.getRangeScorer: string ValueSource range matching behind FunctionRangeQuery) | low | FunctionRangeQuery on a string field (BytesRefFieldSource / SortedSetFieldSource) compares term ordinals as float, so in a segment with more than 2^24 distinct values of the field it also matches values just outside the range bounds | 1 |
| LFV-879 | misc / DocValuesStats double statistics (DocValuesStatsCollector, DocValuesStatsCollectorManager) | low | DoubleDocValuesStats and SortedDoubleDocValuesStats (lucene/misc) return mean() = NaN instead of +/-Infinity when any value is collected after an infinite value, so the mean of {+Infinity, 1.0} is NaN while the mean of {1.0, +Infinity} is +Infinity | 1 |
| LFV-940 | benchmark / search-quality package (trec.TrecJudge, the qrels reader used by QualityBenchmark and QueryDriver) | low | TrecJudge counts every qrels grade other than the literal string "0" as relevant, so negative TREC grades (such as -2 for spam pages in TREC Web track qrels) are judged relevant and inflate the relevant-document count, precision, AP and MRR | 1 |
| LFV-937 | benchmark / quality (utils.SubmissionReport, the TREC run-file writer used by QualityBenchmark and QueryDriver) | low | SubmissionReport writes scores of 1000 or more with a grouping comma ("1,200.5000") into the TREC run file that QueryDriver documents as the submission file for trec_eval, so trec_eval reads such a score as 1.0 and ranks those hits wrongly | 1 |
| LFV-935 | benchmark / search-quality evaluation (QualityStats) | low | QualityStats.average(stats).getPrecisionAt(n) is not the mean per-query precision at n when n is above the mean result count: the mean that average() stored is replaced by a second extrapolation (mean P@10 0.4 instead of 0.6) | 1 |
| LFV-825 | facet / taxonomy facets (TopOrdAndFloatQueue order of float-valued child labels in getTopChildren: float association and value-source facets) | low | Float taxonomy facets: if one child label aggregates to NaN, getTopChildren can return a lower-valued label in place of a higher one (a=5, b=NaN, c=10 gives top-1 [a]), because TopOrdAndFloatQueue compares values with < and >; a regression in 9.11.0 from #12966 | 1 |
| LFV-427 | grouping / function grouping (core util.mutable: MutableValueFloat and MutableValueDouble equality) | low | MutableValueFloat and MutableValueDouble equals() compare with ==, so a NaN value is not equal to itself and grouping by a float or double function puts NaN documents into empty groups (4.0.0 to 10.5.2) or throws IllegalArgumentException (main and, by reading, 10.6.0) | 1 |
| LFV-820 | facet / taxonomy facets (TaxonomyFacets#getAllDims ordering of float-valued dims: float association and value-source facets) | low | Taxonomy Facets#getAllDims sorts float-valued dims with a NaN-unsafe < / > comparator, so one dim whose value is NaN puts the other dims out of value order, breaks the documented rule that getTopDims equals the first entries of getAllDims, and with 32 or more dims can make getAllDims throw 'Comparison method violates its general contract!' (released since 4.7.0) | 1 |
| LFV-212 | spatial3d / geom circles (GeoStandardCircle cut plane and SidedPlane sidedness, behind Geo3DPoint.newDistanceQuery and GeoCircleFactory.makeGeoCircle) | low | Geo3D circles with a radius between about 2e-5 m and 20 cm take the inside of their cut plane from the sign of rounding noise, so Geo3DPoint.newDistanceQuery with such a radius can match every point document on the planet | 1 |
| LFV-187 | search / phrase queries (SloppyPhraseMatcher repetition groups: gatherRptGroups, non-multi-term branch) | low | A sloppy PhraseQuery in which two different terms each repeat (for example "a b a b"~1) misses documents of a segment, exact-phrase matches included, when the segment's first candidate document has two of those terms stacked at one position, because SloppyPhraseMatcher builds its repetition groups once, from that document, by position instead of by term | 1 |
| LFV-193 | search / phrase queries (SloppyPhraseMatcher repetition groups: gatherRptGroups same-offset exclusion, collide, advanceRepeatGroups, sortRptGroups tie order) | low | A sloppy PhraseQuery or MultiPhraseQuery with two entries at one position that a third entry pulls into the same repetition group misses documents its exact (slop 0) form matches, and for MultiPhraseQuery one unchanged query matches on some evaluations and misses on others, because SloppyPhraseMatcher checks its 'same offset is not a repetition' rule only pairwise and breaks equal-offset ties in HashSet order | 1 |
| LFV-465 | search / IndexSearcher#count (two-clause term-disjunction shortcut, GITHUB#13036) under IndexSearcher#setTimeout | low | IndexSearcher#count on a two-term disjunction over-counts, even above maxDoc, when the searcher timeout fires while the intersection is counted | 1 |
| LFV-117 | search / kNN query rewrite (AbstractKnnVectorQuery optimistic re-entry pass) under the IndexSearcher timeout | low | A multi-segment kNN query's optimistic second pass, when cut short by the IndexSearcher timeout, replaces the hits a complete first pass already found, so a later timeout can return fewer or farther hits than an earlier one, down to 0 hits | 2 |
| LFV-091 | index / doc values (single-valued SortedSetDocValues view, DocValuesRangeIterator) | low | SingletonSortedSetDocValues.intoBitSet does not refresh its cached ordinal, so nextOrd() returns an earlier document's ordinal and DocValuesRangeIterator.forOrdinalRange can return extra hits on single-valued segments | 1 |
| LFV-415 | codecs / doc values (Lucene90 sparse multi-valued sorted-numeric rangeIntoBitSet) | low | Sparse multi-valued SortedNumericDocValues#rangeIntoBitSet (default codec), called after advanceExact(d) returned false, judges doc d by a neighbouring document's values (or throws ArrayIndexOutOfBoundsException) | 1 |
| LFV-142 | index / MultiDocValues merged norms view (also the merged reader passed to MergePolicy.OneMerge#reorder) | low | MultiDocValues norms view (also the merged reader passed to MergePolicy.OneMerge#reorder): advance(target) returns a document before target when target's segment has no norms for the field, so queries over that view can return duplicate or non-matching hits | 1 |
| LFV-419 | index / SortedDocValues bulk ordinal range (default implementation; Lucene90 sparse SORTED iterator) | low | SortedDocValues#ordinalRangeIntoBitSet's default implementation, called after advanceExact(d) returned false, reads ordValue() for doc d, which has no value, so it marks d using a neighbouring document's ordinal (or throws EOFException) | 1 |
| LFV-911 | core / index: SlowCodecReaderWrapper vector reader metadata (KnnVectorsReader#getVectorCount, new in 10.6.0) | low | SlowCodecReaderWrapper's KnnVectorsReader.getVectorCount (new in 10.6.0) returns the vector count of the SegmentReader under every FilterLeafReader/FilterCodecReader layer instead of the wrapped view's, so it disagrees with get*VectorValues(field).size() of the same reader (6 instead of 3 for a view that exposes 3 of 6 vectors), and it throws NullPointerException for a vector field that the view adds | 1 |
| LFV-157 | codecs / block-tree terms dictionary (Lucene103 SegmentTermsEnum; also BlockTreeOrds and the Lucene90 block tree in backward-codecs) | low | Block-tree TermsEnum.next() after seekExact(term, TermState) on a never-positioned enum restarts at the field's first term instead of returning the next term | 1 |
| LFV-487 | codecs / BlockTreeOrds terms dictionary (lucene-codecs OrdsSegmentTermsEnum) | low | BlockTreeOrds TermsEnum: seekExact(term, termState) right after seekExact(ord) marks the enum positioned over an incomplete frame stack, so a later seekExact returns false for an existing term and seekCeil/next() throw or return made-up terms | 1 |
| LFV-745 | memory / MemoryIndex stored fields (StoredFieldVisitor protocol) | low | MemoryIndex's StoredFields.document offers the visitor fields that have no stored value and asks needsField only once per field name instead of once per stored value, so LazyDocument fails with ArrayIndexOutOfBoundsException or silently loses values, and per-value NO/STOP decisions are ignored | 1 |
| LFV-871 | search / IndriAndQuery (clause Occur handling in matching and explain) | low | IndriAndQuery accepts MUST, FILTER and MUST_NOT clauses without complaint but ignores them when matching (it always matches the union of all clauses), while its explain does read MUST/FILTER, so it explains some of its own hits as non-matches | 1 |
| LFV-785 | memory / MemoryIndex reader FieldInfos (index options and norms of fields that index no terms); seen through the IndexWriter.addIndexes(CodecReader...) schema check and FieldExistsQuery | low | MemoryIndex reports a field that indexes no terms (doc values, points, vectors or stored only) as indexed with positions and norms, so IndexWriter.addIndexes(SlowCodecReaderWrapper.wrap(reader)) fails next to the same document, or records the wrong schema in an empty index, after which the writer rejects that document | 1 |
| LFV-1143 | core / search (DisjunctionScorer two-phase verified matches vs DisjunctionDISIApproximation.docIDRunEnd) | low | Calling docIDRunEnd() on a two-phase disjunction's approximation between matches() and score() corrupts DisjunctionScorer's list of verified matches, so score() and getChildren() include a clause that does not match the current document, or never return (since 10.2.0) | 1 |
| LFV-1145 | codecs / doc values bulk range scan (Lucene90DocValuesProducer dense paths -> internal vectorization PanamaDocValuesRangeSupport) | low | With the Panama vector provider, NumericDocValues.rangeIntoBitSet on a dense default-codec field sets bits for a reversed, and therefore empty, doc range [fromDoc, toDoc) with fromDoc > toDoc, where the scalar provider and every other implementation set none (since 10.5.0) | 1 |
| LFV-205 | store / NRTCachingDirectory (commit durability: IndexWriter.startCommit, SegmentInfos.prepareCommit/finishCommit) | low | NRTCachingDirectory.sync creates a commit's cached segment files in the underlying directory after the commit's directory fsync, so an OS crash right after the segments_N rename can leave a newest commit whose files are missing and an index that will not open | 1 |
| LFV-839 | index / commit protocol failure cleanup (SegmentInfos.finishCommit, IndexWriter.finishCommit and rollback) | low | If Directory.rename(pending_segments_N, segments_N) throws after it took effect, the failed commit leaves the new segments_N in the index (SegmentInfos.finishCommit deletes only pending_segments_N), and IndexWriter then deletes files that this newest segments_N references, so DirectoryReader.open and a new IndexWriter fail until the file is removed by hand (every release since 5.0.0; the rename-branch residual of LUCENE-9477) | 4 |
| LFV-1217 | index / SegmentDocValues (per-generation doc-values producer cache shared by the SegmentReaders of one segment core; reopen with openIfChanged(reader, commit)) | low | After one failed close of a doc-values producer, SegmentDocValues keeps the closed producer in its per-generation cache, so a reader later reopened onto a commit that uses that doc-values generation is handed the closed producer and every doc-values read on it throws AlreadyClosedException | 1 |
| LFV-489 | facet / taxonomy (SearcherTaxonomyManager NRT constructors: index and taxonomy reader open order) | low | SearcherTaxonomyManager's IndexWriter (near-real-time) constructors open the taxonomy reader before the index reader, so a manager created while another thread indexes can hand out a first pair whose searcher holds documents with categories the paired taxonomy reader does not know (facet counting throws ArrayIndexOutOfBoundsException until the index changes and the manager refreshes) | 1 |
| LFV-512 | facet / taxonomy writer (DirectoryTaxonomyWriter lock-free getSize/getParent reads vs a concurrent addCategory: nextID is published before TaxonomyIndexArrays.add stores the parent) | low | DirectoryTaxonomyWriter counts a new ordinal in getSize() before it stores that ordinal's parent, so a concurrent getParent(getSize() - 1) returns 0 (the root) instead of the real parent, or throws ArrayIndexOutOfBoundsException | 2 |
| LFV-650 | analysis / TeeSinkTokenFilter (sinks: newSinkTokenStream() attribute snapshot, SinkTokenStream replay through AttributeSource.restoreState) | low | TeeSinkTokenFilter: a sink created with newSinkTokenStream() before a filter that adds an attribute is put on the tee (the order of the class javadoc example), for example any stemmer adding KeywordAttribute, throws IllegalArgumentException from restoreState on its first token, so IndexWriter.addDocument rejects the document | 1 |
| LFV-894 | analysis-common / compound hyphenation (TernaryTree.compact via HyphenationTree.loadPatterns and HyphenationCompoundWordTokenFilter) | low | Loading some well-formed hyphenation grammars (e.g. the current TeX Afrikaans patterns) throws ArrayIndexOutOfBoundsException, because TernaryTree.insert(char[], int, char) sizes its node arrays with strlen(key) instead of strlen(key, start) | 1 |
| LFV-933 | analysis-common / hunspell WordStorage (dictionary word hash table) | low | Hunspell Dictionary can fail to load with 'Too many collisions' when its entry count is a multiple of 961, because WordStorage takes the raw String.hashCode() modulo the table size (for example the en_US dictionary plus a 300-word custom list) | 1 |
| LFV-929 | analysis / WordDelimiterGraphFilterFactory and WordDelimiterFilterFactory types option (parseTypes) versus the getLines resource-file format | low | WordDelimiterGraphFilterFactory (and the deprecated WordDelimiterFilterFactory) throw a java.util.NoSuchElementException with no message from inform() when the 'types' file holds no rule (empty, only comment or blank lines, or a sole '# => ...' rule that the loader drops as a comment), because parseTypes calls TreeMap.lastKey() on the empty rule map | 1 |
| LFV-928 | analysis / hunspell (Dictionary SET encoding lookup) | low | Hunspell Dictionary cannot load SET ISO8859-10, or ISO8859-14 spelled any way except exactly "ISO8859-14" (UnsupportedCharsetException at load) | 1 |
| LFV-329 | search / rescoring | low | DoubleValuesSourceRescorer and LateInteractionRescorer throw NoSuchElementException instead of returning no hits when the searcher's reader has no segments: rescore() takes leaves().getFirst() before it looks at the hits | 1 |
| LFV-251 | suggest / ternary search tree suggester (TSTLookup.lookup and get, TSTAutocomplete.prefixCompletion) | low | TSTLookup.get('') and TSTLookup.lookup('') throw StringIndexOutOfBoundsException instead of returning null or an empty list: TSTAutocomplete.prefixCompletion reads key.charAt(0) before it checks the key length (every release since 3.3.0) | 1 |
| LFV-985 | suggest / ternary search tree suggester (TSTLookup add, build, store, load and ramBytesUsed; TSTAutocomplete.insert; TernaryTreeNode.sizeInBytes) | low | TSTLookup recurses once per ternary-tree level in add/build, store, load and ramBytesUsed, so a deep tree (short keys added in sorted order, or one suggestion thousands of characters long) throws StackOverflowError, often only when the lookup is stored or loaded (every release since 3.3.0) | 1 |
| LFV-786 | suggest / ternary search tree suggester (TSTLookup.build: rebuild failure atomicity and rebuild consistency) | low | TSTLookup.build empties its tree before it reads the new input but resets its count only after the input is sorted, so a rebuild that throws while the input is read or sorted leaves a lookup that suggests nothing while getCount() and store()/load() still report the previous build; lookups made while a rebuild reads its input also find nothing | 1 |
| LFV-666 | spatial-extras / prefix-tree heatmap faceting (HeatmapFacetCounter.calcFacets, reached through PrefixTreeStrategy.calcFacets) | low | HeatmapFacetCounter.calcFacets throws InvalidShapeException for a box that ends at the world's east or north edge in a non-geo context with projected (Web Mercator) world bounds, because floating-point rounding adds one cell past that edge | 1 |
| LFV-478 | suggest / FileDictionary (text-file dictionary for Lookup.build) | low | FileDictionary treats its fieldDelimiter as a regular expression, so a delimiter such as '|', '.', '+' or '$' makes a valid suggestion file fail to load or silently mis-parse | 1 |
| LFV-455 | queries / intervals (PayloadFilteredTermIntervalsSource per-segment hasPayloads check) | low | Intervals.term(term, payloadFilter) throws IllegalArgumentException ('no indexed payloads') for every segment in which no document indexed a payload for the field, so the whole search fails and whether it fails depends on segment layout | 1 |
| LFV-776 | facet / range drill-down and filter queries (DoubleRange/LongRange.ValueSourceQuery) | low | DoubleRange#getQuery(Query, DoubleValuesSource) and LongRange#getQuery(Query, LongValuesSource) never call rewrite(searcher) on the values source, so a source that needs rewriting (DoubleValuesSource.fromQuery, IndexReaderFunctions) throws 'must be rewritten', and a legacy QueryValueSource view silently ignores the searcher's Similarity | 1 |
| LFV-893 | queries / function queries (ValueSource to DoubleValuesSource/LongValuesSource bridge: asDoubleValuesSource, asLongValuesSource) | low | ValueSource#asDoubleValuesSource and #asLongValuesSource never call createWeight, so a ValueSource that keeps per-query state in its context (ttf, sttf, or a user ValueSource) fails with NullPointerException through FunctionScoreQuery, its explain, or a LongValuesSource sort | 1 |
| LFV-886 | queries / function queries (RangeMapFloatFunction, map(): createWeight propagation to sub-ValueSources) | low | RangeMapFloatFunction (map()) never calls createWeight on its target and default value sources, so a target or default that keeps per-query state in the context (ttf, sttf, or a user ValueSource) fails with NullPointerException | 1 |
| LFV-299 | search / IndriAndQuery (composite query clause rewriting) | low | IndriAndQuery does not rewrite its clauses, so a PrefixQuery, WildcardQuery, FuzzyQuery or other rewrite-only clause makes search, count and explain throw UnsupportedOperationException | 1 |
| LFV-463 | queries / intervals (PayloadFilteredTermIntervalsSource Matches API; UnifiedHighlighter WEIGHT_MATCHES) | low | Intervals.term(term, payloadFilter) match iterators throw UnsupportedOperationException from getQuery(), so Weight#matches of ordered/unordered/maxgaps/atLeast over such a term, and Matches-based (default UnifiedHighlighter) highlighting of most positional combinations, throw for every matching document | 1 |
| LFV-604 | queries / intervals (MultiTermIntervalsSource behind Intervals.prefix, wildcard, regexp, range, fuzzyTerm and multiterm; IntervalQuery search and Weight#matches) | low | Multi-term interval sources (Intervals.prefix, wildcard, regexp, fuzzyTerm, range, multiterm) skip the has-positions check that Intervals.term performs, so positional interval queries over them on a field indexed without positions silently return wrong hits (usually none) instead of throwing the documented exception | 1 |
| LFV-393 | classification / NearestFuzzyQuery (KNearestFuzzyClassifier) | low | NearestFuzzyQuery (used by KNearestFuzzyClassifier) computes idf from reader.numDocs() (live documents) and reader.docFreq() (which still counts deleted documents), so when deleted documents that are not yet merged away make up most of the index the idf is negative and rewrite throws 'boost must be a positive float' (released since 8.0.0) | 1 |
| LFV-559 | queries / MoreLikeThis boosted query construction (MoreLikeThis.createQuery boost normalisation) | low | MoreLikeThis with setBoost(true) divides every term's score by the lowest selected score, so a selected term that scores 0 (a TFIDFSimilarity whose idf is 0, such as the textbook log(N/df) for a term in every document) makes like() throw 'boost must be a positive float, got NaN' (8.0 and later) or build NaN and Infinity boosts (4.10 to 7.x) | 1 |
| LFV-263 | suggest / analyzing infix suggester (AnalyzingInfixSuggester NRT add/update/refresh after build(); inherited unchanged by BlendedInfixSuggester [read]) | low | AnalyzingInfixSuggester.ensureOpen() publishes its new IndexWriter before the SearcherManager opened on it and does not undo that when the manager cannot be opened, so refresh() refreshes the manager over build()'s closed writer and throws AlreadyClosedException | 1 |
| LFV-769 | monitor / QueryIndex term-filter map (searcher refresh vs concurrent match, writable and read-only Monitor) | low | Monitor.match can throw NullPointerException while queries are being registered (or while a read-only Monitor refreshes), because QueryIndex keeps its per-reader term filters in a plain HashMap that the searcher refresh and reader-close listeners modify while match threads read it without a lock | 2 |
| LFV-399 | suggest / analyzing suggester (AnalyzingSuggester.build payload check, inherited by FuzzySuggester) | low | AnalyzingSuggester and FuzzySuggester check a payload-enabled surface form for the reserved byte U+001F in bytes[0, length) of the backing array instead of in the BytesRef slice [offset, offset + length), so a valid slice is rejected with IllegalArgumentException and a slice that contains U+001F is accepted and later mis-split | 1 |
| LFV-600 | suggest / FreeTextSuggester (n-gram model joined with an in-band separator byte; build-side separator check) | low | FreeTextSuggester.build accepts a token that contains the separator byte whenever the shingled term stays within the gram limit, although its javadoc promises an IllegalArgumentException; later lookups whose last complete word occurs only inside that token throw AssertionError (-ea) or NullPointerException (-da) | 1 |
| LFV-431 | suggest / analyzing suggester (AnalyzingSuggester.build and getCount, inherited by FuzzySuggester) | low | AnalyzingSuggester and FuzzySuggester getCount() counts analyzed paths instead of entries when the analyzer produces a token graph (synonyms, word-delimiter graphs), and store()/load() persist the inflated count | 1 |
| LFV-296 | core / index: SegmentOrder (query-time segment re-ordering) and leaf core cache helpers | low | SegmentOrder.fromSort(numeric sort).reorder(reader) throws NullPointerException when a leaf's getCoreCacheHelper() returns null, which LeafReader documents as legal (ParallelCompositeReader over two or more readers, SortingCodecReader or MemoryIndex leaves, content-altering FilterLeafReaders) | 1 |
| LFV-1187 | core / index: SegmentOrder (query-time segment re-ordering helper) | low | A SegmentOrder built by SegmentOrder.fromSort(numeric Sort) sorts the leaves of every reorder() call with one shared comparator whose per-segment memo is an unsynchronized HashMap, so two threads calling reorder() on the same SegmentOrder at the same time can throw NullPointerException (Map.get returns null and is unboxed) (since 10.4.0) | 1 |
| LFV-438 | highlighter / UnifiedHighlighter passage selection (FieldHighlighter.highlightOffsetsEnums passage-queue sizing; maxPassages is never range-checked by UnifiedHighlighter.highlightFieldsAsObjects) | low | UnifiedHighlighter with maxPassages = Integer.MAX_VALUE throws a message-less IllegalArgumentException for every document that has a match (FieldHighlighter sizes its passage queue with Math.min(64, maxPassages + 1), which wraps) | 1 |
| LFV-964 | grouping / GroupingSearch (term, function, cached two-pass and doc-block grouping) x the first-pass, TopGroups and block collector managers | low | GroupingSearch with groupLimit or groupDocsLimit = Integer.MAX_VALUE ('all remaining groups/documents') throws NegativeArraySizeException, OutOfMemoryError or an IllegalArgumentException naming -2147483648, because it does not cap the limits at maxDoc as IndexSearcher.search does and its collectors add offset + limit in int (every release since 4.0.0) | 1 |
| LFV-1004 | suggest / Lookup.lookup result sizing (AnalyzingInfixSuggester, WFSTCompletionLookup, FreeTextSuggester) | low | AnalyzingInfixSuggester, WFSTCompletionLookup and FreeTextSuggester allocate storage for num results before they know how many suggestions match, so lookup(key, false, Integer.MAX_VALUE) on an 8-entry suggester throws instead of returning the 8 suggestions, and a large num allocates memory in proportion to num | 1 |
| LFV-1007 | analysis-common / n-gram tokenizers (NGramTokenizer.init buffer sizing, shared by EdgeNGramTokenizer; NGramTokenizerFactory and EdgeNGramTokenizerFactory pass maxGramSize through unchecked) | low | NGramTokenizer and EdgeNGramTokenizer accept maxGram = Integer.MAX_VALUE, but their int buffer sizing wraps to a 1022-char read buffer and leaves the 16-char default term buffer, so the first text of 17 or more chars throws (ArrayIndexOutOfBoundsException up to 1021 chars, an unrelated IllegalArgumentException from 1022) | 1 |
| LFV-994 | facet / SortedSetDocValues child queue (AbstractSortedSetDocValueFacetCounts.computeTopChildren, inherited by SortedSetDocValuesFacetCounts and ConcurrentSortedSetDocValuesFacetCounts) | low | SortedSetDocValues facets size the child priority queue from topN instead of the number of labels, so getTopChildren, getAllDims and getTopDims(.., topNChildren) with topN = Integer.MAX_VALUE throw IllegalArgumentException where taxonomy facets return every label, and a large topN allocates topN + 1 queue slots even for a 3-label dim | 1 |
| LFV-983 | facet / getTopDims dimension queue (AbstractSortedSetDocValueFacetCounts and TaxonomyFacets overrides, inherited by SortedSetDocValuesFacetCounts, ConcurrentSortedSetDocValuesFacetCounts, FastTaxonomyFacetCounts, TaxonomyFacetIntAssociations and TaxonomyFacetFloatAssociations) | low | SortedSetDocValues and taxonomy Facets#getTopDims size their dimension priority queue by the caller's topNDims without a cap, so getTopDims(Integer.MAX_VALUE, n) throws IllegalArgumentException where getAllDims(n) and the default Facets#getTopDims return every dim, and a large topNDims allocates topNDims + 1 queue slots even for 2 dims | 1 |
| LFV-995 | search / top-n rescoring and geo nearest search (queue sizing: RescoreTopNQuery.rewrite; LatLonPoint.nearest -> NearestNeighbor) | low | RescoreTopNQuery and LatLonPoint.nearest size their priority queue from the caller's n, not from what the index can return, so n = Integer.MAX_VALUE ('all') throws IllegalArgumentException and a large n throws OutOfMemoryError, even on an index of a few documents | 1 |
| LFV-1005 | highlighter / matchhighlight passage selection (PassageSelector.pickBest passage-queue sizing; used by MatchHighlighter through FieldValueHighlighters.highlighted, which passes maxPassages through unchecked) | low | 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 | 1 |
| LFV-265 | highlighter / UnifiedHighlighter passage selection (FieldHighlighter.maybeAddPassage; maxPassages is never range-checked by UnifiedHighlighter.highlightFieldsAsObjects) | low | UnifiedHighlighter with maxPassages=0 throws NullPointerException for every document that has a match (a per-field 0 makes the whole multi-field call fail) | 1 |
| LFV-493 | highlighter / UnifiedHighlighter break iterators (LengthGoalBreakIterator.next on the no-match default-summary path, FieldHighlighter.getSummaryPassagesNoHighlight) | low | UnifiedHighlighter with a LengthGoalBreakIterator length goal of 0 throws IllegalArgumentException 'offset out of bounds' instead of returning the default summary for every hit that has no match in the field (8.5.0 regression from LUCENE-9093) | 1 |
| LFV-546 | highlighter / UnifiedHighlighter no-match default summary (FieldHighlighter.highlightFieldForDoc maps only '== -1' to maxPassages; FieldHighlighter.getSummaryPassagesNoHighlight) | low | UnifiedHighlighter with maxNoHighlightPassages below -1 throws IllegalArgumentException 'Illegal Capacity' for every document with no match in the field, although the javadoc says any value below 0 falls back to maxPassages | 1 |
| LFV-808 | search / TermInSetQuery visitor (consumeTermsMatching automaton supplier over the util/automaton string-union builder's 1000-byte term limit), reached from highlighter / UnifiedHighlighter without WEIGHT_MATCHES | low | TermInSetQuery#visit gives QueryVisitor an automaton supplier that throws IllegalArgumentException when any term is longer than 1000 bytes, so UnifiedHighlighter without WEIGHT_MATCHES fails on such a query | 1 |
| LFV-574 | queries / MoreLikeThis interesting-terms convenience API (MoreLikeThis.retrieveInterestingTerms(int) and retrieveInterestingTerms(Reader, String)) | low | MoreLikeThis.retrieveInterestingTerms pre-sizes its result list to maxQueryTerms, so a large maxQueryTerms that like() accepts (for example Integer.MAX_VALUE as 'no limit') throws OutOfMemoryError even for a one-word document | 1 |
| LFV-958 | grouping / SearchGroup.merge (merging first-pass top groups across shards or slices; reduce step of FirstPassGroupingCollectorManager) | low | SearchGroup.merge (the shard-merge helper of grouped search) with topN = Integer.MAX_VALUE ('all remaining groups') throws OutOfMemoryError because it pre-sizes its result list by topN (regression in 6.2.0, LUCENE-7356), and with offset >= 1 throws NullPointerException because offset + topN wraps to a negative queue bound (since 3.3.0) | 1 |
| LFV-1002 | suggest / document suggester: TopSuggestDocs.merge (merging per-shard suggestion results) | low | TopSuggestDocs.merge, documented as analogous to TopDocs.merge, sizes its priority queue by topN before it reads any shard, so merging with topN = Integer.MAX_VALUE ('all') throws IllegalArgumentException 'maxSize must be >= 0 and < 2147483631' even for 3 hits or no shards (NegativeArraySizeException before 7.5.0), while TopDocs.merge returns the hits; a large legal topN allocates topN + 1 queue slots for a few hits | 1 |
| LFV-996 | suggest / spell checking (SpellChecker.suggestSimilar hit budget 10 * numSug and SuggestWordQueue size) | low | SpellChecker.suggestSimilar computes its hit budget 10 * numSug in int, so numSug = Integer.MAX_VALUE ('all suggestions'), 214748365 and every other count whose product wraps to <= 0 throw IllegalArgumentException 'numHits must be > 0' instead of returning the suggestions, and counts whose product wraps to a small positive value silently return fewer suggestions | 1 |
| LFV-998 | suggest / analyzing: BlendedInfixSuggester lookup over-fetch (num * numFactor) | low | BlendedInfixSuggester.lookup computes num * numFactor in int, so a large num wraps: num = Integer.MAX_VALUE throws IllegalArgumentException 'numHits must be > 0', some values throw NoSuchElementException, and specific values silently return fewer suggestions than exist | 1 |
| LFV-577 | queries / MoreLikeThis field-name resolution (setFieldNames(null) and the convenience method retrieveInterestingTerms(int)) | low | MoreLikeThis.retrieveInterestingTerms(int) throws NullPointerException after the documented setFieldNames(null) ('determined at runtime from the IndexReader'), unless like(int) or like(Map) ran first on the same instance | 2 |
| LFV-469 | queries / intervals (Intervals.atLeast: MinimumShouldMatchIntervalsSource); queryparser / flexible StandardQueryParser fn:atLeast | low | Intervals.atLeast accepts minShouldMatch 0 (also from query text such as fn:atLeast(0 a b)), and the query then throws NullPointerException or ArrayIndexOutOfBoundsException on every non-empty segment it searches instead of being rejected as an invalid argument | 1 |
| LFV-606 | highlighter / matchhighlight: MatchRegionRetriever low-level API (highlightDocument with a custom FieldValueProvider) and the offset strategies OffsetsFromPositions, OffsetsFromTokens, OffsetsFromValues and the OffsetsFromMatchIterator fallback | low | MatchRegionRetriever.highlightDocument throws NullPointerException when a custom FieldValueProvider returns null for a matched field, which FieldValueProvider#getValues documents as allowed ('null if the field is not loaded or does not exist'), instead of returning no hit regions | 1 |
| LFV-1009 | facet / facet sets (FacetSetsField packing of custom FacetSet encodings) | low | FacetSetsField.create sizes its buffer from the first FacetSet's sizePackedBytes(), so a list of custom variable-size facet sets (e.g. compressed, which the FacetSet javadoc and FacetSets.adoc allow) throws ArrayIndexOutOfBoundsException when a later set packs to more bytes than the first, and whether a document can be built depends only on the order of its sets | 1 |
| LFV-968 | queryparser / flexible core (QueryParserHelper; inherited by StandardQueryParser and PrecedenceQueryParser) | low | Flexible query parser: QueryParserHelper.setQueryNodeProcessor(null) throws NullPointerException, although its javadoc says null is allowed and means no query-node processing (StandardQueryParser and PrecedenceQueryParser inherit the setter; every release since 2.9.0) | 1 |
| LFV-1188 | core / index: IndexWriterConfig (setIndexWriterEventListener) and IndexWriter commit (merge-on-commit) | low | IndexWriterConfig.setIndexWriterEventListener accepts null, unlike the class's other component setters, so a later commit() that runs a merge-on-commit merge (on by default) throws NullPointerException instead of the setter rejecting the null (since 9.0.0; with the default config since 9.3.0) | 1 |
| LFV-655 | highlighter / TermVectorLeafReader (LeafReader over one document's term vectors; LeafMetaData invariant) | low | TermVectorLeafReader.getMetaData() always throws IllegalArgumentException ('minVersion must be set when createdVersionMajor is >= 7'), so a TermVectorLeafReader cannot be searched with a Sort, wrapped in a ParallelLeafReader or copied with addIndexes | 1 |
| LFV-692 | analysis-stempel / egothor stemmer trie reduction (Reduce.optimize, reached through Trie.reduce, MultiTrie.reduce and MultiTrie2.reduce) | low | Stempel's base Reduce.optimize passes its new, empty row list to removeGaps instead of the trie's rows, so every Trie.reduce(new Reduce()) call throws IndexOutOfBoundsException | 1 |
| LFV-936 | benchmark / search-quality package (QualityQuery, TREC topic readers) | low | QualityQuery.compareTo is not a total order when numeric and non-numeric topic ids are mixed (ints compared as numbers, everything else as strings), so TrecTopicsReader and Trec1MQReader.readQueries, and with them QueryDriver, can throw IllegalArgumentException 'Comparison method violates its general contract!' | 1 |
| LFV-404 | misc / index: BpVectorReorderer merge-time reordering (BPReorderingMergePolicy) over core / index: SortingCodecReader vector views | low | addIndexes of a SortingCodecReader (including the reader that BPIndexReorderer.reorder returns) into a writer that uses BPReorderingMergePolicy with BpVectorReorderer throws UnsupportedOperationException, because SortingCodecReader's vector views do not support copy() | 1 |
| LFV-1023 | misc / vector BP reordering (BpVectorReorderer command line: in-place rewrite through IndexWriter.addIndexes) | low | On unreleased main and branch_11x, the BpVectorReorderer command line cannot reorder an index created by Lucene 9.x or 10.x, or one with a soft-deletes field: it rewrites the index through a default IndexWriterConfig (created major 11 on branch_11x and 12 on main, no soft-deletes field), so the first addIndexes throws IllegalArgumentException | 1 |
| LFV-695 | misc / index tools (IndexRearranger.execute: writer configs of the rearrange pass and the apply-deletes pass) | low | Since 10.0.0 IndexRearranger keeps only the analyzer from the IndexWriterConfig it is given, so the rearranged index loses the configured codec and index sort, OpenMode.CREATE is ignored, and an index with a soft-deletes or parent field cannot be rearranged | 1 |
| LFV-618 | misc / index tools (MultiPassIndexSplitter.split, output IndexWriterConfig); IndexWriter.addIndexes field-role checks | low | MultiPassIndexSplitter builds every output part with a bare IndexWriterConfig and accepts no config, so it cannot split any index that uses soft deletes (7.4.0+) or has a parent field (9.10.0+): split() and its command line throw IllegalArgumentException before any part gets a document | 1 |
| LFV-1071 | classification / utils: DatasetSplitter (split, createNewDoc all-fields copy of a stored binary value) | low | DatasetSplitter.split in its all-fields mode (fieldNames omitted) throws at the first document with a stored binary field, because it copies the bytes into an indexed, tokenized TextField-type field that Field rejects | 1 |
| LFV-223 | join / ToParentBlockJoinSortField string sort (ToParentDocValues missing-child ordinals, since #15727) | low | ToParentBlockJoinSortField on a STRING field with max-child selection and childMissingValue=STRING_LAST throws IndexOutOfBoundsException when a parent has children both with and without the field | 1 |
| LFV-121 | codecs / HnswBitVectorsFormat x index / IndexingChain aborting-exception classification | low | A float vector field routed to HnswBitVectorsFormat is rejected inside an aborting step of the indexing chain, so the one rejected document closes the IndexWriter and rolls back every document added since the last commit | 1 |
| LFV-281 | index / IndexingChain inversion with custom term frequencies (TermVectorsConsumerPerField, FreqProxTermsWriterPerField) x aborting-exception classification | low | A document rejected for a custom TermFrequencyAttribute on a field with term-vector positions or offsets, postings positions or DOCS-only postings is rejected inside an aborting step of the indexing chain, so it closes the IndexWriter and rolls back every change since the last commit | 1 |
| LFV-1189 | index / IndexingChain inversion, term-doc (DOCS_AND_CUSTOM_FREQS) duplicate-term rejection (TermsHashPerField.add) x aborting-exception classification | low | A term repeated in one document of a DOCS_AND_CUSTOM_FREQS field closes IndexWriter, instead of skipping the document, when the term is a non-UTF-8 binary term such as the single byte 0xC3: the duplicate-term rejection builds its message with utf8ToString, which throws (since 10.5.0) | 1 |
| LFV-1170 | document / stored values (Field.storedValue, StoredField) | low | Field.storedValue() handles a String but no other CharSequence, so a stored field built from a StringBuilder, CharsRef or other CharSequence through the public StoredField(String, CharSequence, FieldType) or Field(String, CharSequence, IndexableFieldType) constructor makes IndexWriter.addDocument throw IllegalStateException 'Cannot store value of type ...' (regression in 9.6.0 from #12116) | 1 |
| LFV-1229 | core / document column batch indexing: IndexWriter#addBatch, BinaryColumnAdapter invertable type (experimental column API) | low | IndexWriter#addBatch rejects an untokenized BinaryColumn or DictionaryColumn whose FieldType indexes positions or term-vector positions, which addDocument with the same Field type accepts: the column adapter always takes the single-term InvertableType.BINARY path for untokenized values, so the row pass throws 'Fields that are tokenized or index proximity data must produce a non-null TokenStream' after ColumnValidation accepted the type (since 10.5.0) | 1 |
| LFV-1154 | index / IndexingChain inversion (FieldInvertState.setAttributeSource attribute cache) | low | When an AttributeFactory throws while IndexWriter adds TermFrequencyAttribute, FieldInvertState keeps the previous stream's attribute handles, so later accepted documents of that field are indexed with the wrong positions and offsets until the next flush | 1 |
| LFV-1135 | index / IndexingChain inversion with custom term frequencies (TermFrequencyAttribute, FreqProxTermsWriterPerField) | low | IndexWriter accepts a custom term frequency of 0 without any check: the frequency goes into the postings and the committed segment fails CheckIndex ('freq 0 is out of bounds'), or the commit throws and closes the writer | 1 |
| LFV-1218 | core / index: SlowCompositeCodecReaderWrapper (merged CodecReader view handed to OneMerge#reorder), term vectors | low | The term-vectors reader of the merged view that IndexWriter hands to OneMerge#reorder (SlowCompositeCodecReaderWrapper) throws NullPointerException from clone() as soon as one merged segment has no term vectors, although the same class handles that null sub-reader in get, prefetch, checkIntegrity and close; on the merge path this closes the IndexWriter (since 9.9.0) | 1 |
| LFV-375 | analysis / hunspell (Stemmer affix removal) | low | Hunspell COMPLEXPREFIXES: after removing the second prefix the Stemmer keeps removing prefixes, so words with three prefixes are accepted and a zero-length prefix recurses until StackOverflowError (also in HunspellStemFilter, where it closes the IndexWriter) | 1 |
| LFV-282 | spatial3d / Geo3DPoint polygon and shape queries (Geo3DUtil.fromPolygon, PointInGeo3DShapeQuery, PointInShapeIntersectVisitor) | low | Geo3DPoint.newPolygonQuery turns a degenerate polygon (for example three vertices on the equator) into an empty GeoCompositePolygon that is meant to match nothing, but every search with the query throws NullPointerException; Geo3DPoint.newShapeQuery with an empty GeoCompositePolygon fails the same way | 1 |
| LFV-352 | spatial3d / Geo3DDocValuesField outside-distance sort fields (Geo3DPointOutsideSortField equality) | low | Geo3DPointOutsideSortField.equals casts its argument to the sibling class Geo3DPointSortField, so comparing two distinct outside-distance sort fields on the same field (directly, through Sort.equals, or in a HashMap keyed by Sort) throws ClassCastException instead of returning true or false | 1 |
| LFV-1055 | core / HNSW merge-time graph reuse (util/hnsw InitializedHnswGraphBuilder.rebalanceGraph, codecs/lucene99 Lucene99HnswVectorsFormat) | low | With maxConn = 1, a merge that reuses an HNSW graph with a deleted vector never finishes: InitializedHnswGraphBuilder.rebalanceGraph adds one full graph level per pass until OutOfMemoryError | 1 |
| LFV-1056 | core / HNSW graph construction (util/hnsw HnswGraphBuilder constructor; codecs/lucene99 Lucene99HnswVectorsFormat beamWidth range) | low | With beamWidth = 1, which the HNSW formats accept, every HnswGraphBuilder sizes its level-0 merge queue min(beamWidth / 2, M * 3) = 0 and throws, so building any HNSW graph fails and a merge closes the IndexWriter (since 10.2.0) | 1 |
| LFV-589 | codecs / HNSW vectors formats (constructor parameter validation; concurrent HNSW merge) | low | The HNSW vectors formats (Lucene99HnswVectorsFormat, Lucene104HnswScalarQuantizedVectorsFormat, HnswBitVectorsFormat and, since 10.6.0, the sandbox DedupHnswVectorsFormat and DedupHnswScalarQuantizedVectorsFormat) accept numMergeWorkers <= 0 together with a merge ExecutorService, and then every merge that builds an HNSW graph throws ArrayIndexOutOfBoundsException (0 workers) or NegativeArraySizeException (negative) and closes the IndexWriter as a tragic event (since 9.9.0) | 1 |
| LFV-166 | codecs / UniformSplit postings formats (BlockWriter last-block split; UniformSplit and SharedTermsUniformSplit) | low | UniformSplit postings formats fail to flush or merge a field when deltaNumLines > targetNumBlockLines/3, a setting validateSettings accepts | 1 |
| LFV-226 | misc / store DirectIODirectory (direct-I/O merge buffers) | low | DirectIODirectory accepts a mergeBufferSize that is not a multiple of the file system block size, and then every direct-I/O read fails, so merges hit a tragic exception; a size below the block size can also give a zero-capacity write buffer (BufferOverflowException, or writeBytes making no progress) | 1 |
| LFV-1175 | core / codecs: compressing term vectors format (Lucene90CompressingTermVectorsFormat blockSize validation; FieldsIndexWriter, DirectMonotonicWriter) | low | Lucene90CompressingTermVectorsFormat documents and validates its last argument, blockSize, as a chunk count (>= 1), but the writer uses it as a DirectMonotonic block shift limited to [2, 22], so values such as 1024 or 1 are accepted and the first flush with term vectors throws and closes the IndexWriter (since 8.5.0) | 1 |
| LFV-1183 | core / search: filtered kNN accept docs (AcceptDocs.createBitSet behind KnnFloatVectorQuery/KnnByteVectorQuery filters, read by Lucene99HnswVectorsReader and HnswGraphSearcher) | low | A kNN query whose filter iterates a BitSetIterator over a bit set shorter than the segment's maxDoc throws ArrayIndexOutOfBoundsException (AssertionError with -ea) instead of returning the filtered hits, because AcceptDocs reuses that set as the accept bits without checking its length (since 9.3.0) | 1 |
| LFV-1176 | codecs / Lucene104 scalar-quantized vectors (flat format search on a field with no vectors: Lucene104ScalarQuantizedVectorsReader.search) | low | With the flat Lucene104ScalarQuantizedVectorsFormat, a FloatVectorSimilarityQuery (or the 4-argument LeafReader.searchNearestVectors) on a segment whose float vector field has no vectors left (every vector document deleted and merged away) throws NullPointerException ('quantizer' is null) instead of returning no hits (10.4.0 through 10.6.0 and main) | 1 |
| LFV-1185 | search / kNN vector queries (SeededKnnVectorQuery seed-to-ordinal mapping: MappedDISI and the entry-point count) | low | SeededKnnVectorQuery built with its public seed-Weight constructor makes IndexSearcher.search throw IllegalArgumentException (or EOFException on a DENSE block) when a seed hit has no vector, because MappedDISI advances the vector iterator to a doc at or before its current one and the entry-point count includes seeds without a vector (since 10.3.0) | 1 |
| LFV-1184 | core / codecs: MultiLevelSkipListWriter (multi-level skip lists for postings; @lucene.experimental) | low | MultiLevelSkipListWriter.bufferSkip throws ArrayIndexOutOfBoundsException for a one-level skip writer (maxSkipLevels = 1) at the first df that is a multiple of skipInterval * skipMultiplier (regression since 9.9.0, #12653) | 1 |
| LFV-1238 | core / util/hnsw: HnswGraphSearcher (bulk-scoring scratch of the unfiltered searcher) | low | HnswGraphSearcher.search throws NegativeArraySizeException (-2) on every search of a non-empty HnswGraph whose maxConn() is the public constant HnswGraph.UNKNOWN_MAX_CONN, a value its own dispatch deliberately sends to the unfiltered searcher, because that searcher sizes its bulk-scoring scratch as graph.maxConn() * 2 (since 10.3.0) | 1 |
| LFV-1234 | core / util/hnsw: OnHeapHnswGraph (upper-level node cache of getNodesOnLevel and getSortedNodes) | low | OnHeapHnswGraph.getNodesOnLevel(1) throws NullPointerException on the empty graph that HnswGraphBuilder.build(0) returns, although that graph reports numLevels() == 2, because the upper-level node cache counts as up to date whenever lastFreezeSize == size(), and both start at 0, so it is never built (since 9.9.0) | 1 |
| LFV-1197 | core / util/hnsw: InitializedHnswGraphBuilder (fromGraph, addGraphNode; @lucene.experimental) | low | InitializedHnswGraphBuilder.fromGraph documents initializedNodes as 'can be null if not tracking', but the returned builder's addGraphNode(int) reads it without a null check, so a builder created with null throws NullPointerException on its first insertion (since 10.4.0) | 1 |
| LFV-125 | search / kNN query layer (PatienceKnnVectorQuery over SeededKnnVectorQuery) | low | PatienceKnnVectorQuery over a SeededKnnVectorQuery stores a searcher-specific seed Weight in its own field during rewrite, so every search changes the query's equals/hashCode, and searching one query object concurrently on two different readers fails | 1 |
| LFV-567 | queries / function queries (ValueSource context map under concurrent search) | low | FunctionQuery, FunctionRangeQuery and ValueSource sort fields share one non-thread-safe context map across the slices of an executor search, and scale() (ScaleFloatFunction) writes to it during the search, so when that write grows the map the search throws NullPointerException or silently returns different scores | 2 |
| LFV-863 | search / BooleanWeight.explain (span and payload-span queries under non-scoring clauses; FunctionScoreQuery; Monitor ExplainingMatch) | low | IndexSearcher.explain throws NullPointerException (AssertionError with -ea) for a span query inside a BooleanQuery that Lucene weights without scores (a FILTER or MUST_NOT clause, or the query of a FunctionScoreQuery whose source does not need scores), because BooleanWeight.explain calls score() on scorers built with COMPLETE_NO_SCORES | 4 |
| LFV-167 | join / block join (ParentsChildrenBlockJoinQuery: ParentsChildrenBlockJoinWeight#scorerSupplier intra-segment guard) | low | ParentsChildrenBlockJoinQuery throws IllegalStateException ('does not support intraSegment concurrency') when a scorer is requested twice for the same leaf, so IndexSearcher.explain of a BooleanQuery that contains it fails, even on a plain single-threaded searcher | 1 |
| LFV-864 | core / search: vector-similarity queries (AbstractVectorSimilarityQuery Weight.explain vs scorerSupplier), with consequences in BooleanWeight.explain and FunctionScoreQuery.explain | low | Vector-similarity threshold queries (Float/Byte/Float16VectorSimilarityQuery at the default decay) explain every document whose exact similarity clears the threshold as a match, but return only what the approximate graph search collected, so explain calls documents the query does not return matches; inside a BooleanQuery or FunctionScoreQuery that explain then reports another document's score, fails an assertion or throws NullPointerException | 1 |
| LFV-875 | search / IndriAndQuery (IndriAndWeight.explain) | low | IndriAndWeight.explain does not check that its scorer landed on the requested document, so a document that matches no clause is explained as a match with another document's score, or explain throws (EOFException or IndexOutOfBoundsException from a norms read past the clause scorer's last match; AssertionError with -ea) | 1 |
| LFV-833 | queries / payloads (SpanPayloadCheckQuery.toString, reached from SpanWeight.explain) | low | SpanPayloadCheckQuery.toString() and IndexSearcher.explain() throw NullPointerException when payloadToMatch contains a null entry, although the matcher accepts null as 'no payload at this position' and the query searches and counts correctly (since 5.4.0, LUCENE-6716) | 1 |
| LFV-1190 | index / merged multi-segment postings (MultiPostingsEnum.toString, MultiTermsEnum.postings) | low | MultiPostingsEnum.toString() throws NullPointerException for the merged postings of a term that is missing from some segment (for example MultiTerms.getTermPostingsEnum on a two-segment index), because it prints every sub-reader slot and the unfilled slots have a null slice (since 4.10.0, LUCENE-5798) | 1 |
| LFV-963 | core / search (MultiPhraseQuery.Builder input validation and MultiPhraseQuery.toString) | low | MultiPhraseQuery.Builder does not validate an empty Term[]: it throws ArrayIndexOutOfBoundsException at the first position but accepts one at later positions, and toString() of the accepted query then throws, which also breaks explain and the 'indexed without position data' error | 2 |
| LFV-1177 | core / search: conjunction iterators (ConjunctionUtils.createConjunction, ConjunctionDISI.ConjunctionTwoPhaseIterator) | low | ConjunctionUtils.createConjunction sorts the caller's list of TwoPhaseIterators in place, so an immutable list such as List.of(a, b) whose match costs are not in ascending order throws UnsupportedOperationException, and a LinkedList throws IllegalArgumentException (since 9.0.0) | 1 |
| LFV-154 | search / CachingCollector replay (CachingCollector, CachingCollectorManager) | low | CachingCollector#replay (and CachingCollectorManager#replay) lets a CollectionTerminatedException from the second-pass collector escape to the caller instead of ending only that leaf as IndexSearcher does, so replaying into an early-terminating collector, such as a TopFieldCollector sorted by the index sort, throws | 1 |
| LFV-1068 | grouping / GroupingSearch second-pass cache (score-less CachingCollector / CachingCollectorManager replay into the TopGroups second pass) | low | GroupingSearch.setCaching(n, false) and setCachingInMB(mb, false) throw NullPointerException with the default within-group sort or the default includeMaxScore, because the score-less cache is replayed into a second pass that needs scores | 1 |
| LFV-116 | index / IndexingChain per-field schema validation (FieldSchema) | low | A rejected document leaves its doc-values skip index type in the field's per-document schema state, so later valid documents with that field are rejected until the in-memory segment is flushed | 1 |
| LFV-127 | index / IndexingChain per-field schema validation (frozen-FieldType cache) x columnar addBatch | low | IndexWriter#addBatch marks the frozen FieldType of an earlier rejected document as validated, so later documents with that type skip the per-field schema check (a wrong-dimension vector is stored truncated) | 1 |
| LFV-379 | core / document: LatLonPoint distance feature query (dynamic pruning through setMinCompetitiveScore) | low | LatLonPoint.newDistanceFeatureQuery can skip a competitive document under top-k pruning: computeMaxDistance returns the lower end of its 1 m binary search, and the pruning box built from that radius adds only a 7 cm pad | 1 |
| LFV-203 | queries / FunctionScoreQuery block-max pruning (#16431) | low | FunctionScoreQuery scores negative values as 0, but its block-max bound stays negative, so top-k search skips competitive documents | 1 |
| LFV-406 | queries / function queries (ValueSourceScorer behind FunctionRangeQuery, LUCENE-7996 non-negative score rule; the hit loss surfaces in core WANDScorer) | low | FunctionRangeQuery scores a document with its raw, possibly negative, function value although LUCENE-7996 forbids negative scores and FunctionQuery over the same source clamps them to 0; since 10.1.0 a matching document whose value is -Infinity can then disappear from the top-k results of a minimumShouldMatch >= 2 BooleanQuery | 1 |
| LFV-189 | search / function scoring (DoubleValuesSource skip-index score bounds for FunctionScoreQuery block-max pruning) | low | DoubleValuesSource.fromDoubleField/fromFloatField declare their raw IEEE-bit decoders INCREASING, so on a skip-indexed raw-bits field one NaN makes a block's score bound NaN (FunctionScoreQuery under TOP_SCORES then silently drops the true top hit) and all-negative blocks get inverted bounds | 1 |
| LFV-214 | search / function scoring (DoubleValues.withDefault score bound for FunctionScoreQuery block-max pruning, #16431) | low | DoubleValues.withDefault's getMaxScore returns the wrapped source's bound, which does not cover missingValue, so a FunctionScoreQuery over such a source can silently drop the true top hit under TOP_SCORES | 1 |
| LFV-221 | search / function scoring (DoubleValuesSource skip-index score bounds for FunctionScoreQuery block-max pruning) | low | DoubleValuesSource rounds the skip-index block bound to the nearest float, so with a boost FunctionScoreQuery's max score can be one ulp below a real score and top-k search returns the wrong top hit | 1 |
| LFV-841 | codecs / legacy scalar-quantized vectors (util/quantization ScalarQuantizer, backward-codecs Lucene99ScalarQuantizedVectorsReader) | low | On main, a 9.x/10.x int7/int4 scalar-quantized segment whose vectors are all identical (stored quantiles equal) is decoded with the min == max widening that #14049 added, not the quantizer that wrote it, so its vectors read 127 (int7) or 15 (int4) units lower in every dimension and exact matches score about 0 and rank last (unreleased, 11.0 only) | 2 |
| LFV-902 | search / similarities (LMDirichletSimilarity) | low | LMDirichletSimilarity accepts mu = 0, but then every document scores 0: log(1 + tf/(mu*P)) + log(mu/(dl+mu)) becomes +Infinity + -Infinity = NaN, and the 'score > 0' clamp turns NaN into 0 | 1 |
| LFV-750 | misc / similarities (SweetSpotSimilarity hyperbolicTf helper) | low | SweetSpotSimilarity.hyperbolicTf returns max instead of about min for frequencies far below xoffset, because its NaN fallback is right only for the Math.pow overflow above the midpoint, so a hyperbolic-tf subclass is not monotone in freq and ranks a document with one occurrence above one with hundreds | 1 |
| LFV-258 | document / FeatureField sigmoid scoring (FeatureField.SigmoidFunction behind newSigmoidQuery; the same arithmetic is copied in queries / intervals IntervalScoreFunction.SigmoidFunction behind the 4-argument IntervalQuery constructor) | low | FeatureField.newSigmoidQuery (and the IntervalQuery sigmoid) return NaN scores when pivot^exp overflows or underflows a double, for pivot and exp values the factories accept | 1 |
| LFV-898 | document / FeatureField score functions (SaturationFunction and SigmoidFunction behind newSaturationQuery and newSigmoidQuery); queries / intervals IntervalScoreFunction (IntervalQuery's default saturation scoring and its pivot and pivot-plus-exponent constructors) | low | FeatureField saturation and sigmoid queries and IntervalQuery scoring compute w*(1 - k/(S+k)) instead of the documented w*S/(S+k) (and the same rewrite for the sigmoid), so documents whose value is far below the pivot score exactly 0.0 or tie with documents that have different values | 1 |
| LFV-259 | search / similarities (PerFieldSimilarityWrapper, Similarity#computeQueryTermWeight) and BooleanQuery duplicate-clause rewrite | low | PerFieldSimilarityWrapper does not forward Similarity#computeQueryTermWeight, so a BM25Similarity or StableTflSimilarity k3 (query-term saturation) setting silently has no effect behind a per-field wrapper | 1 |
| LFV-103 | search / BooleanQuery rewrite and similarities | low | BM25Similarity/StableTflSimilarity k3 query-term saturation is skipped for duplicate SHOULD clauses when 2 <= minimumNumberShouldMatch < number of SHOULD clauses | 1 |
| LFV-608 | core index / DOCS_AND_CUSTOM_FREQS (termdoc) field length vs term statistics; search similarities (BM25, SimilarityBase) | low | DOCS_AND_CUSTOM_FREQS fields (10.5.0+): the norm length counts terms but sumTotalTermFreq and totalTermFreq sum the custom frequencies, contradicting the FieldInfo#isTermDocField, IndexOptions and FieldStats javadocs and putting BM25's dl and avgdl in different units | 1 |
| LFV-053 | search / concurrency | low | Reusing a TotalHitCountCollectorManager after a failed search silently returns count 0 or hangs | 1 |
| LFV-192 | search / AutomatonQuery RAM accounting (NFARunAutomaton lazily built DFA states; LRUQueryCache RAM budget) | low | AutomatonQuery.ramBytesUsed() is computed once at construction, so a query that runs on an NFA (WildcardQuery and RegexpQuery by default on main, opt-in NFA queries since 10.0.0) under-reports the DFA states it builds while searching, and an LRUQueryCache can hold far more heap than its RAM budget | 1 |
| LFV-400 | spatial3d / PointInGeo3DShapeQuery RAM accounting (Accountable#ramBytesUsed; core LRUQueryCache RAM budget) | low | Geo3DPoint polygon and path queries report a constant 592-byte ramBytesUsed() regardless of shape size, because PointInGeo3DShapeQuery prices its GeoShape as a 256-byte unknown object, so LRUQueryCache can hold many times its maxRamBytesUsed (since 8.2.0) | 1 |
| LFV-402 | join / JoinUtil numeric query-time join RAM accounting (PointInSetIncludingScoreQuery, Accountable#ramBytesUsed; core LRUQueryCache RAM budget) | low | PointInSetIncludingScoreQuery.ramBytesUsed() leaves out its per-value score list, so scoring numeric JoinUtil joins (ScoreMode Max, Min, Avg, Total) under-report their heap (1.5x-2.4x on 9.11.0 and later, 6.2x or more in 8.2.0-9.10.0) and LRUQueryCache under-charges them (since 8.2.0) | 1 |
| LFV-923 | queries / function queries (FunctionScoreQuery, FunctionMatchQuery, FunctionRangeQuery and FunctionQuery QueryVisitor traversal of DoubleValuesSource/ValueSource; consumer: IndexSearcher's cumulative clause limit) | low | IndexSearcher's cumulative maxClauseCount check never counts a query held by a values source (FunctionScoreQuery.boostByQuery's boost query, DoubleValuesSource.fromQuery, QueryValueSource): the function queries' visit() stops at the source and each embedded query is checked alone with a fresh budget, so the total number of executed clauses is unbounded | 1 |
| LFV-910 | grouping / GroupingSearch two-pass caching x search / CachingCollectorManager (new in 10.6.0) under a concurrent IndexSearcher | low | GroupingSearch.setCaching / setCachingInMB limit is applied per slice since #16247 (10.6.0 regression): with an IndexSearcher that has an executor, a query matching more documents than the limit is replayed from per-slice caches holding up to slices x limit instead of being purged and re-run (results unchanged) | 1 |
| LFV-348 | misc / memory-accounting bitset collector (MemoryAccountingBitsetCollector, MemoryAccountingBitsetCollectorManager, CollectorMemoryTracker) under IndexSearcher slicing | low | MemoryAccountingBitsetCollector sizes each collector's bitset to the doc-id span of its slice, so under concurrent search a slice whose segments are not adjacent in doc-id order allocates, and charges to the memory tracker, bits for the segments that other slices search | 1 |
| LFV-917 | facet / range queries (LongRange/DoubleRange ValueSourceQuery and MultiValueSourceQuery QueryVisitor traversal; consumers: IndexSearcher's cumulative clause limit, QueryVisitor.termCollector, RamUsageEstimator.sizeOf(Query)) | low | LongRange/DoubleRange#getQuery(fastMatchQuery, ...) range queries report themselves as a leaf in visit() and never visit their fast-match query, so IndexSearcher's maxClauseCount check never counts the fast-match query | 1 |
| LFV-916 | search / vector similarity queries (AbstractVectorSimilarityQuery QueryVisitor traversal; consumers: IndexSearcher's cumulative clause limit, QueryVisitor.termCollector, RamUsageEstimator.sizeOf(Query)) | low | Float/Byte/Float16VectorSimilarityQuery.visit() never visits the filter, so the filter's clauses escape IndexSearcher's cumulative maxClauseCount check and QueryVisitor term collection | 1 |
| LFV-951 | spatial-extras / composite: CompositeVerifyQuery (Query#visit; consumers: QueryVisitor.termCollector and other visit-based term extraction, IndexSearcher's cumulative clause limit) | low | CompositeVerifyQuery.visit reports the whole query as a leaf and never visits the index query it rewrites and executes, so QueryVisitor term collection misses the index query's terms and IndexSearcher's cumulative maxClauseCount check does not count its clauses | 1 |
| LFV-1107 | search / IndexSearcher clause-count limit (getNumClausesCheckVisitor) | low | IndexSearcher's nested clause check accepts maxClauseCount + 1 clauses because it compares before incrementing (known: #10339 / LUCENE-9299) (released since 9.0) | 1 |
| LFV-432 | facet / sampling (RandomSamplingFacetsCollector.createSample, cross-segment bin carry-over) | low | RandomSamplingFacetsCollector never samples the first hit of a segment that starts mid-bin: createSample does not handle randomIndex == counter at the end of a segment, so a sampling bin that crosses a segment boundary loses its sample (or samples at a stale offset) | 1 |
| LFV-089 | index / CheckIndex vectors | low | CheckIndex silently skips FLOAT16 vector fields: it reports 'OK [0 fields, 0 vectors]' and never runs checkFloat16VectorValues | 1 |
| LFV-543 | index / CheckIndex HNSW graph check | low | On main, CheckIndex's HNSW graph test reports valid segments written by Lucene 9.12.0-9.12.1 and 10.0.0-10.1.0 as broken ('has repeated neighbors'), because the check has no version gate | 1 |
| LFV-561 | index / CheckIndex HNSW graph check | low | With failFast off (the default), CheckIndex reports an index clean ('No problems were detected', Status.clean true, exit code 0) although its HNSW graph test printed ERROR, because testSegment never rethrows hnswGraphsStatus.error | 1 |
| LFV-640 | index / CheckIndex concurrent segment check and exorcise | low | CheckIndex -exorcise with more than one thread (threadCount > 1, the default on multi-core machines, or checkIndex(onlySegments, executor)) writes the surviving segments in ascending file-size order instead of commit order, so the repaired index's segment order and relative document order depend on the thread count | 1 |
| LFV-1060 | index / IndexWriter (hasUncommittedChanges: changeCount vs. buffered deletes in flight) | low | IndexWriter.hasUncommittedChanges() can return false for an acknowledged, uncommitted delete while another thread flushes or refreshes an NRT reader, because it reads changeCount before the in-RAM state (every release since 4.5.1) | 1 |
| LFV-1043 | index / IndexWriter NRT (DocumentsWriterFlushQueue flush-ticket count, DocumentsWriter.anyChanges) | low | IndexWriter on main: a push of the buffered deletes that finds nothing left to freeze leaks one flush-ticket count, so for the rest of the writer's life every NRT reader reports isCurrent() == false, even right after commit(), while openIfChanged() returns null | 1 |
| LFV-054 | search / query cache | low | LRUQueryCache's 16 hard partitions give a 0% hit rate with the class-javadoc configuration (main only) | 1 |
| LFV-991 | search / query cache (LRUQueryCache.clear() and the onClear statistics callback) | low | On main, LRUQueryCache.clear() empties its partitions one at a time and then calls onClear() with no lock held, so an entry cached during clear() survives while a subclass that resets its statistics in onClear() drops it (it reports 0 entries for a cache holding 1, and -1 once that entry is evicted); regression from #15558, main only | 1 |
| LFV-1070 | misc / index: BpVectorReorderer (BP doc-id reordering over a vector field, through BPReorderingMergePolicy, computeDocMap and the command line) | low | BpVectorReorderer never calls the Executor it is given; any non-null executor makes it fork its work onto ForkJoinPool.commonPool() | 1 |
| LFV-023 | util / automaton | low | RegExp CASE_INSENSITIVE matching is asymmetric for U+0130 and U+0131 (dotted and dotless i) | 1 |
| LFV-238 | grouping / collector managers (FirstPassGroupingCollectorManager, TopGroupsCollectorManager and BlockGroupingCollectorManager reduce through the cross-shard merges SearchGroup.merge, TopGroups.merge and TopGroups.mergeBlockGroups; GroupingSearch) | low | With an executor, grouped search breaks ties by slice number instead of doc ID, so tied groups and tied documents differ from sequential search | 2 |
| LFV-239 | grouping / block grouping (TopGroups.mergeBlockGroups and BlockGroupingCollectorManager.reduce; GroupingSearch(Query groupEndDocs) on a searcher with an executor) | low | With an executor, block grouping's TopGroups.maxScore includes groups that are not returned, so it changes with the index slicing (and with groupOffset > 0 it counts the skipped groups); regression in 10.5.0 | 1 |
| LFV-272 | search / SynonymQuery scoring (SynonymScorer.freq float sum) and its merged-impacts max-score bound | low | SynonymQuery adds up boosted term frequencies in float in heap order, so identical documents can score differently and explain() can differ from the hit score; with more than 2^24 occurrences in one field a score can exceed getMaxScore() | 1 |
| LFV-831 | suggest / document (NRT) suggester (NRTSuggesterBuilder.finishTerm dedup bytes; NRTSuggester top-n search through Util.TopNSearcher; TopSuggestDocsCollector tie order) | low | Document suggester: which equal-score copies of one suggestion are returned depends on n (top-2 [2, 1] is not a prefix of top-3 [2, 0, 1]), because NRTSuggesterBuilder numbers the copies in java.util.PriorityQueue heap order instead of doc-id order | 1 |
| LFV-273 | queries / function scoring (FunctionScoreQuery and FunctionQuery negative-value clamps, LUCENE-7996; visible through core TopScoreDocCollector tie handling) | low | FunctionScoreQuery and FunctionQuery score a function value of -0.0 as -0.0f instead of 0, because their LUCENE-7996 negative-value clamps test value >= 0; since 10.2.0 the top-1 hit can then differ from the first of the top-2 hits | 1 |
| LFV-835 | queries / payloads (PayloadScoreQuery payload-score clamp, LUCENE-7996; visible through core TopScoreDocCollector tie handling; sibling of LFV-273's function-query clamps) | low | PayloadScoreQuery scores a payload value of -0.0 as -0.0 instead of 0 (MinPayloadFunction, MaxPayloadFunction or a custom PayloadFunction with a decoder that reads IEEE floats), because its LUCENE-7996 negative-score clamp tests 'score >= 0 == false' and its explain truncation 'value < 0'; since 10.2.0 the top-1 hit is then not the head of the top-2 hits | 1 |
| LFV-077 | search / IndexSearcher timeout | low | A timed-out search reports its partial hit count as TotalHits.Relation.EQUAL_TO | 1 |
| LFV-050 | queryparser / flexible | low | Flexible StandardQueryParser: an exclusive int/long point bound at MAX/MIN wraps around, so the query matches every document with the field instead of none | 1 |
| LFV-059 | queryparser / flexible | low | Flexible StandardQueryParser misses -0.0 documents for exclusive float/double bounds | 1 |
| LFV-356 | queryparser / flexible parser node serialization (QueryNode#toQueryString of FieldQueryNode, QuotedFieldQueryNode, FuzzyQueryNode, AbstractRangeQueryNode and the other field-printing nodes) | low | Flexible query parser: QueryNode#toQueryString prints field names without escaping, so nodes for escaped field names such as 'my field' or 'a:b' print strings that parse to a different query or do not parse | 1 |
| LFV-748 | queryparser / flexible StandardQueryParser interval function nodes (IntervalQueryNode#toQueryString; intervalfn FuzzyTerm, Wildcard and AnalyzedText toString) | low | Flexible query parser: IntervalQueryNode#toQueryString prints some fn: interval functions in a form the parser rejects or reads as a different query (fn:fuzzyTerm(abc) prints as fn:fuzzyTerm(abc 2128)) | 1 |
| LFV-975 | queryparser / flexible parser node serialization (BoostQueryNode toQueryString/toString) | low | Flexible query parser: BoostQueryNode#toQueryString prints a boost below 0.001 (or above 2^63) in E-notation, e.g. ab^0.0009 prints ab^9.0E-4, which StandardSyntaxParser cannot parse back | 1 |
| LFV-892 | queryparser / flexible parser node serialization (SlopQueryNode and PhraseSlopQueryNode toQueryString/toString) | low | Flexible query parser: SlopQueryNode and PhraseSlopQueryNode print their int slop through a float, so toQueryString changes every slop above 2^24 (~16777217 prints ~16777216, ~2147483647 prints ~2147483648, which the parser rejects) | 1 |
| LFV-610 | spatial-extras / prefix trees (DateRangePrefixTree / NumberRangePrefixTree range-shape string form: SpanUnitsNRShape.toString of a range whose end normalizes to a thousand- or million-year cell; also shown in the 'queryShape=' part of the prefix-tree queries' toString) | low | DateRangePrefixTree prints a date range whose end is the last year of a thousand- or million-year block (a year X999, or 2 BC) with that end shown as the block's FIRST year, e.g. [1990 TO 1999] prints as "[1990 TO 1000]", so parseShape rejects the printed string ('Wrong order') or reads it as a much shorter range ([* TO 1999-12-31] prints as "[* TO 1000]") | 1 |
| LFV-132 | analysis / StandardTokenizer and UAX29URLEmailTokenizer (JFlex no-buffer-expansion scanner) | low | StandardTokenizer and UAX29URLEmailTokenizer with setMaxTokenLength(1) end the token stream at the first supplementary character (for example an emoji), so all later text of the field value is silently left out of the index | 1 |
| LFV-289 | analysis / HTMLStripCharFilter (JFlex grammar, numeric character references; also the 'htmlStrip' char filter SPI) | low | HTMLStripCharFilter leaves hexadecimal character references with six hex digits (􏿽 􀀀 the zero-padded é) undecoded, because its length check counts the leading 'x' and so lets only five hex digits through | 1 |
| LFV-1202 | analysis / StandardTokenizer (JFlex scanner buffer resize: StandardTokenizer.setMaxTokenLength, StandardTokenizerImpl.setBufferSize) | low | StandardTokenizer.setMaxTokenLength lowered between two incrementToken() calls shrinks the scanner buffer under the scanner's read positions, so the next incrementToken() throws ArrayIndexOutOfBoundsException or IndexOutOfBoundsException instead of continuing (UAX29URLEmailTokenizer the same; since 4.10.0, LUCENE-5897) | 1 |
| LFV-120 | index / SegmentInfos commit read (forward version check) | low | Opening an index created by a newer Lucene major throws IllegalArgumentException ('indexCreatedVersionMajor is in the future') instead of IndexFormatTooNewException | 1 |
| LFV-1095 | index / DirectoryReader.listCommits (commit enumeration) | low | DirectoryReader.listCommits throws CorruptIndexException (CorruptSegmentInfoException on main) on a healthy index when the deletion policy deletes an older commit while listCommits is reading it (known: #8894 / LUCENE-7843) (released since 6.5.0) | 1 |
| LFV-152 | index / IndexWriter open from a reader commit (version gate) | low | IndexWriter opened from a reader's IndexCommit still rejects an index by its created major ('createdVersionMajor must be >= 9, got: 8'), although DirectoryReader.open, OpenMode.APPEND and a listCommits() commit accept the same commit under the per-segment version check of GITHUB#14607 | 1 |
| LFV-131 | index / DirectoryReader reopen and isCurrent (expert old-index open) | low | A DirectoryReader opened with open(commit, minSupportedMajorVersion, leafSorter) forgets that minimum: isCurrent(), openIfChanged() and SearcherManager.maybeRefresh() throw IndexFormatTooOldException even on an unchanged index | 1 |
| LFV-202 | search / IndexSearcher slicing (LeafSlice, LeafReaderContextPartition) | low | IndexSearcher throws IllegalArgumentException for any reader that contains a leaf with maxDoc() == 0 (for example a ParallelLeafReader with no sub-readers): the whole-segment LeafReaderContextPartition of that leaf fails a bounds check added for partition ranges (regression in 10.0.0) | 1 |
| LFV-1215 | core / util (DocIdSetBuilder sparse build; reached from facet / FacetsCollector) | low | DocIdSetBuilder.build() on an empty builder with maxDoc 0 throws IllegalArgumentException 'maxValue must be non-negative (got: -1)' instead of returning the empty set, because the sparse path always evaluates PackedInts.bitsRequired(maxDoc - 1), so FacetsCollector fails on a zero-document leaf (regression in 6.1.0) | 1 |
| LFV-625 | index / IndexFileDeleter start-up (inflateGens) with FSDirectory pending deletions | low | A new IndexWriter cannot open while a non-index file in the index directory is pending deletion, because IndexFileDeleter parses that file's name as a segment name (AssertionError 'wtf? file=...' with -ea; NumberFormatException with -da for names such as app-notes.txt) | 1 |
| LFV-1205 | search / doc-values range queries, index-sort primary-sort shortcut (SortedSetDocValuesRangeQuery, SortedNumericDocValuesRangeQuery, IndexSortSortedNumericDocValuesRangeQuery, Sort.getPrimarySortField) | low | Doc-values range queries throw NullPointerException on a leaf whose index sort starts with a DOC or SCORE sort field (for example a custom reader that reports Sort.INDEXORDER), because the primary-sort shortcut calls getField().equals(field) on the null-field SortField that Sort.getPrimarySortField returns (SortedSetDocValuesRangeQuery and SortedNumericDocValuesRangeQuery since 10.0.0, IndexSortSortedNumericDocValuesRangeQuery since 9.5.0) | 1 |
| LFV-1209 | search / kNN vector queries (AbstractKnnVectorQuery optimistic per-leaf top-k) | low | kNN vector query rewrite throws (AssertionError with -ea, IllegalArgumentException 'initialCapacity must be > 0' with -da) instead of matching nothing when a leaf's parent reader has maxDoc 0, because the per-leaf share 0/0 is NaN and the per-leaf top-k becomes 0 (regression in 10.3.0) | 1 |
| LFV-587 | index / IndexWriter merge waiting (close/shutdown waitForMerges, forceMerge, forceMergeDeletes) with NoMergeScheduler | low | With NoMergeScheduler and a merge policy that selects merges (for example the default TieredMergePolicy), IndexWriter.close() (default commit-on-close), forceMerge(1) and a blocking forceMergeDeletes() never return: IndexWriter registers the policy's merges as pending, NoMergeScheduler never runs or removes them, and all three calls wait until no merge is pending | 2 |
| LFV-1153 | index / ConcurrentMergeScheduler merge limits (setMaxMergesAndThreads reset to AUTO_DETECT_MERGES_AND_THREADS, initialize, maybeStall) | low | After an IndexWriter has started using a ConcurrentMergeScheduler, setMaxMergesAndThreads(AUTO_DETECT_MERGES_AND_THREADS, AUTO_DETECT_MERGES_AND_THREADS) leaves both limits at -1, so the next commit, close or forceMerge that registers a merge waits in maybeStall forever and no merge thread is ever started | 1 |
| LFV-1001 | search / query cache (LRUQueryCache.cleanUp() locking vs the statistics callbacks) | low | On main, LRUQueryCache.cleanUp() is synchronized on the cache object and takes partition locks while it holds that monitor, so a subclass whose statistics callbacks synchronize on the cache (synchronized methods or synchronized (this)) deadlocks the cleanup thread against a search, and every later search whose callback needs the monitor hangs too; regression from #15558, main only | 1 |
| LFV-581 | index / IndexWriter commit (merge-on-commit under commitLock, SerialMergeScheduler, tragic-event rollback) | low | With SerialMergeScheduler, a merge that fails while another thread's commit() waits to run its merge-on-commit merges deadlocks both threads forever (commit() holds commitLock and waits for the scheduler's monitor; the failing merge holds that monitor and its tragic rollback waits for commitLock), and the writer can no longer be closed (since 8.6.0; with default merge-on-commit settings since 9.3.0) | 1 |
| LFV-648 | index / IndexWriter close (waitForMerges, ConcurrentMergeScheduler, tragic merge failure) | low | IndexWriter.close() never returns when a background merge fails while a forced-merge cascade merge is still pending (forceMerge(n, false), then close()): the tragic rollback is skipped because close() is already closing, getNextMerge() refuses the pending merge once the tragedy is set, and waitForMerges() never checks the tragedy (since 9.3.0) | 3 |
| LFV-846 | index / IndexWriter flush hand-off (DocumentsWriterFlushControl.checkOutForFlush, updateStallState, waitForFlush) | low | If IndexWriter's InfoStream throws while a full in-memory buffer is handed over for flushing, that buffer stays registered as flushing forever, so the writer hangs in its own self-close after an Error, or in close() and rollback() after an exception (every release since 6.2.0) | 1 |
| LFV-1174 | index / IndexWriter full-flush abort (DocumentsWriterFlushControl.abortPendingFlushes, doAfterFlush, waitForFlush) | low | An Error while IndexWriter aborts the queued in-memory segments of a failed full flush leaves the unvisited segments registered as flushing, so DirectoryReader.open(writer) and the writer's own self-close after the Error wait forever in waitForFlush (every release since 7.4.0) | 1 |
| LFV-586 | index / IndexWriter addIndexes(CodecReader...) (merge-scheduler hand-off, NoMergeScheduler) | low | Since 9.4.0, IndexWriter.addIndexes(CodecReader...) blocks indefinitely (until another thread interrupts it or rolls the writer back) when the writer uses NoMergeScheduler, also together with NoMergePolicy as the NoMergeScheduler javadoc recommends: the reader merge is handed to the merge scheduler, which never runs it, and is then awaited with no time limit | 1 |
| LFV-208 | index / ConcurrentMergeScheduler merge spawn (CMS.merge hand-back, IndexWriterMergeSource.onMergeFinished, IndexWriter.mergeFinish) | low | ConcurrentMergeScheduler.merge hands a checked-out merge back with onMergeFinished on any failure in its spawn block, so a merge whose thread already started is unregistered while still running, and a merge whose thread never started is never completed | 2 |
| LFV-844 | index / IndexWriter merge hand-off to the merge scheduler (IndexWriterMergeSource.getNextMerge, runningMerges) | low | If the merge scheduler's InfoStream throws on the log line right after IndexWriter hands out a merge, that merge stays marked as running with no thread to run it, so the writer hangs in its own tragic rollback after an Error, or in close() after an exception (8.6.0 to main) | 1 |
| LFV-1210 | index / ConcurrentMergeScheduler (updateMergeThreads infoStream logging; IO-throttle setters, merge start and finish) | low | ConcurrentMergeScheduler.updateMergeThreads throws NullPointerException when merge logging is switched on during the call, because it allocates its log buffer only if its first verbose() check is true and then checks verbose() again before using the buffer | 1 |
| LFV-1084 | index / IndexWriter full flush (DocumentsWriter.finishFullFlush, DocumentsWriterFlushControl blocked flushes and stall control) | low | If IndexWriter's InfoStream throws on the 'finishFullFlush' log line of a commit, flush or NRT open, the still-open writer never leaves full-flush mode, so it stops flushing in-memory segments (maxBufferedDocs is ignored) and, with RAM-based flushing, a lone indexing thread later blocks forever in addDocument (every release since 4.0.0) | 1 |
| LFV-447 | index / TieredMergePolicy parameter validation (findMerges allowed-segment-count loop, IndexWriter.updatePendingMerges) | low | TieredMergePolicy.setSegmentsPerTier accepts NaN, and the next IndexWriter flush, commit or NRT reopen then never returns: findMerges spins forever inside the synchronized IndexWriter.updatePendingMerges, blocking every other use of the writer (the other four double setters accept NaN too; with forceMergeDeletesPctAllowed = NaN, forceMergeDeletes() expunges nothing) | 1 |
| LFV-207 | index / IndexWriter forceMergeDeletes MergeObserver (registerMerge, MergePolicy.MergeObserver) | low | IndexWriter.forceMergeDeletes returns a MergeObserver that also tracks merges IndexWriter refused to register, so the observer never completes and await() blocks forever | 1 |
| LFV-637 | monitor / ParallelMatcher worker lifecycle (Monitor#match) | low | Monitor's ParallelMatcher starts blocking worker tasks in its constructor that only finish() releases: a Monitor#match that fails before finish() (an exception such as TooManyClauses from the presearcher, or a rejected submit) leaves its workers parked on the executor forever, and an executor that runs a worker on the calling thread (CallerRunsPolicy on a saturated pool) makes Monitor#match hang | 1 |
| LFV-485 | analysis / CharArraySet and CharArrayMap unmodifiable views (stop-word, keyword and protected-word sets) | low | CharArraySet.unmodifiableSet / CharArrayMap.unmodifiableMap share the backing table but copy its size, so after the backing set grows the view reports a stale size, sees only some additions, and can loop forever on an absent key | 1 |
| LFV-326 | monitor / concurrent candidate matchers (ParallelMatcher, PartitionMatcher) | low | Monitor's ParallelMatcher and PartitionMatcher catch only IOException per query: one registered query that throws an unchecked exception at match time makes Monitor.match throw and lose every match of the batch, and ParallelMatcher blocks forever once all its workers have died | 1 |
| LFV-513 | monitor / bulk query loading (ConcurrentQueryLoader worker error handling) | low | ConcurrentQueryLoader workers exit at the first exception from Monitor.register and are never replaced, so once every worker is gone add() blocks forever and close() never gets to report the IOException | 1 |
| LFV-552 | monitor / read-only query index (ReadonlyQueryIndex background refresh) | low | A read-only Monitor's background refresh stops for good after one run throws an unchecked exception, and no error is reported | 1 |
| LFV-1025 | replicator / NRT segment replication (PrimaryNode.releaseCopyState, PrimaryNode.close) | low | PrimaryNode.releaseCopyState leaks the pending-copy count when IndexWriter.decRefDeleter throws (for example after an I/O error closed the IndexWriter while a replica was copying), so PrimaryNode.close() then waits forever under the default remote-close timeout | 1 |
| LFV-250 | facet / taxonomy (SearcherTaxonomyManager.getRefCount and tryIncRef; the misuse guard in core ReferenceManager.acquire) | low | SearcherTaxonomyManager.acquire() spins forever at 100% CPU, instead of throwing the LUCENE-5436 IllegalStateException, when the current pair's taxonomy reader was closed outside the manager | 2 |
| LFV-384 | util / OfflineSorter concurrent sort (partitionsInRAM permits on a rejected submit) | low | OfflineSorter loses a partitionsInRAM permit whenever its ExecutorService rejects a partition-sort task, so a later sort() on the same sorter waits forever even though the executor is idle (released since 6.6.0) | 1 |
| LFV-633 | classification / ConfusionMatrixGenerator (classifier evaluation utility) | low | ConfusionMatrixGenerator never cancels a classification that exceeded its 5 s limit, so later documents queue behind it on the single worker thread and are also counted as timed out | 1 |
| LFV-252 | search / ControlledRealTimeReopenThread (NRT generation tracking: close(), the HandleRefresh refresh listener, waitForGeneration) | low | ControlledRealTimeReopenThread.close() never unregisters its refresh listener, so one later refresh of the still-open ReferenceManager overwrites the Long.MAX_VALUE 'closed' generation and an untimed waitForGeneration on the closed instance can block forever | 1 |
| LFV-364 | util / automaton (RegExp, Operations.repeat; reached from RegexpQuery and the classic and flexible query parsers) | low | RegExp builds an automaton that doubles with every stacked '+' ('ab' followed by n '+' gives 2^n+2 states for the 3-state language ab+), a 10.0 regression that exhausts a 1 GB heap at about 20 '+' | 2 |
| LFV-962 | util / automaton (RegExp, Operations.concatenate; reached from RegexpQuery and the classic and flexible query parsers) | low | RegExp builds about n^2/2 transitions for a run of n repeated nullable atoms (a.*.*...b, a(x?)^n b, [a-z]*, (bc)?), and on main RegexpQuery keeps that automaton: a 2,002-character regexp of language a.*b holds 502,502 transitions and 170 MB (10.5.2: 4 states, 7 KB) | 3 |
| LFV-926 | queryparser / classic (generated JavaCC parser QueryParser.jj and QueryParserBase.parse) | low | Classic QueryParser.parse (and its MultiFieldQueryParser, ComplexPhraseQueryParser and ExtendableQueryParser subclasses) throws StackOverflowError instead of the documented ParseException on deeply nested groups (about 2,650-3,700 levels, 5-7 KB of query text, on a 1 MB thread stack) | 1 |
| LFV-924 | queryparser / simple (SimpleQueryParser.parseSubQuery / consumeSubQuery recursion) | low | SimpleQueryParser.parse throws StackOverflowError on deeply nested parentheses, because parseSubQuery and consumeSubQuery recurse once per '(' with no depth bound, although the parser is meant to do its best with any human-entered text | 1 |
| LFV-965 | queryparser / xml (CoreParser, QueryBuilderFactory and SpanQueryBuilderFactory with the compound and span builders, DOMUtils) | low | XML query parser: CoreParser.getQuery(Element) and getSpanQuery(Element) on any JDK, and plain CoreParser.parse(InputStream) on JDK 21 (the 10.x minimum, including the 10.6.0 RC), throw StackOverflowError instead of the declared ParserException on deeply nested queries (on a 1 MB thread stack about 3,000 nesting levels: about 180 KB of nested BooleanQuery XML or 51 KB of nested SpanOr; every release since 1.9.1) | 1 |
| LFV-919 | queryparser / surround (generated JavaCC parser, QueryParser.jj) | low | Surround QueryParser.parse throws StackOverflowError instead of its declared ParseException on deeply nested groups (as few as about 740 levels, about 1.5 KB of query text, on a 1 MB thread stack) | 1 |
| LFV-949 | core / geo GeoJSON parsing (Polygon.fromGeoJSON, SimpleGeoJSONPolygonParser) | low | Polygon.fromGeoJSON throws StackOverflowError instead of returning the polygon or its declared ParseException when JSON arrays or objects nest thousands of levels deep, even inside a valid Feature's properties (10,000 levels, about 20 KB of text, on the default thread stack of the test machine; every release since 6.2.0) | 1 |
| LFV-954 | core / geo WKT parsing (SimpleWKTShapeParser) | low | SimpleWKTShapeParser.parse throws StackOverflowError instead of a result or its declared ParseException when GEOMETRYCOLLECTIONs nest a few thousand levels deep, valid or unterminated (10,000 levels, about 210 KB of text, on the default thread stack of the test machine; every release since 7.6.0) | 1 |
| LFV-952 | core / geo GeoJSON parsing (Polygon.fromGeoJSON, SimpleGeoJSONPolygonParser) | low | Polygon.fromGeoJSON keeps a full key-path String alive at every nesting level, so its heap use grows with nesting depth times key length: a valid 750 KB GeoJSON Feature (900 nested arrays under one long property key), or a 1 MB one (1,000 nested objects with 1,000-char keys), runs out of a 512 MiB heap (every release since 6.2.0) | 1 |
| LFV-030 | util / automaton | low | CompiledAutomaton.floor never terminates on some infinite languages and runs until OutOfMemoryError | 1 |
| LFV-891 | util / automaton | low | CompiledAutomaton.floor throws NullPointerException for NONE, ALL and SINGLE automata (what the documented one-argument constructor builds from an empty, any-string or single-string automaton) and, since 10.0.0, for NFA-backed NORMAL automata | 1 |
| LFV-1214 | util / automaton (Automaton.Builder.addEpsilon) | low | Automaton.Builder.addEpsilon(s, s) never returns and exhausts the heap when state s already has a transition, because its loop re-reads nextTransition while it appends copies that leave s again | 1 |
| LFV-422 | util / BytesRefHash (initial capacity 1: rehash trigger, linear probe and slot word) | low | BytesRefHash accepts initial capacity 1 but never grows the table, so add() or find() of any second distinct key spins forever; since 10.3.0 the same capacity also stores a key whose hashcode is -1 as an empty slot | 1 |
| LFV-888 | search / query caching policy (UsageTrackingQueryCachingPolicy over util FrequencyTrackingRingBuffer) | low | UsageTrackingQueryCachingPolicy(historySize) with historySize 715,827,883 to 1,431,655,767: FrequencyTrackingRingBuffer's IntBag sizes its hash table as maxSize * 3 / 2 in int, the product overflows to a 2-slot table, and the second distinct query recorded by onUse loops forever while holding the policy's monitor (larger sizes overflow too, to a table no larger than the history; assertions disabled; with -ea the constructor throws AssertionError instead) (since 5.0.0) | 1 |
| LFV-056 | search / concurrency | low | TaskExecutor#invokeAll returns while a task is still running if the caller is interrupted | 1 |
| LFV-636 | facet / DrillSideways concurrent mode (ExecutorService constructor, searchConcurrently) | low | DrillSideways with an ExecutorService reports every failure of its drill-down and drill-sideways searches as RuntimeException(ExecutionException(cause)), while sequential DrillSideways, and IndexSearcher with an executor since 9.8.0, throw the cause itself (for example IndexSearcher.TooManyClauses, ExitableDirectoryReader.ExitingReaderException or the declared IOException) | 1 |
| LFV-631 | index / CheckIndex concurrent segment check | low | CheckIndex with more than one thread (the default checkIndex() on a multi-core machine, or checkIndex(onlySegments, executor)) throws NullPointerException when the checking thread is interrupted while it waits for a segment result: the InterruptedException handler logs the interrupt and then processes the still-null segment status | 1 |
| LFV-564 | core / search TaskExecutor (concurrent task failure path; util IOUtils.useOrSuppress) | low | TaskExecutor.invokeAll, which runs concurrent IndexSearcher searches, throws IllegalArgumentException 'Self-suppression not permitted' instead of the tasks' exception, and can return while a started task is still running, when two tasks fail with the same exception object, because IOUtils.useOrSuppress calls addSuppressed without an identity check | 1 |
| LFV-1224 | core / util (IOUtils failure-path cleanup helper closeWhileSuppressingExceptions; reached from StandardDirectoryReader.open, the IndexWriter constructor and codec readers and writers) | low | IOUtils.closeWhileSuppressingExceptions throws IllegalArgumentException 'Self-suppression not permitted' and skips the remaining closeables when a close() throws the very Throwable being handled (for example the JVM's shared OutOfMemoryError), because it calls ex.addSuppressed(e) without an identity check | 1 |
| LFV-1222 | core / search: disjunction scoring (DisjunctionScoreBlockBoundaryPropagator, built by DisjunctionMaxScorer and LogOddsFusionScorer for top-k searches) | low | A top-k search of a DisjunctionMaxQuery or LogOddsFusionQuery throws a plain RuntimeException instead of the declared IOException when a clause's Scorer.getMaxScore throws IOException, because DisjunctionScoreBlockBoundaryPropagator's sort comparator wraps it (since 8.3.0) | 1 |
| LFV-124 | index / IndexWriter addIndexes(Directory...) and the writer-wide field registry (FieldInfos.FieldNumbers) | low | A failed addIndexes(Directory...) leaves the incoming fields registered in the writer's field schema, so getFieldNames() lists them and later valid documents that use those names differently are rejected until the writer is reopened | 1 |
| LFV-1081 | index / IndexWriter addIndexes(CodecReader...) merge (SegmentMerger) and the writer-wide field registry (FieldInfos.FieldNumbers) | low | A failed addIndexes(CodecReader...) leaves the incoming fields registered in the writer's field schema, so later valid documents that use those names differently are rejected until the writer is reopened | 1 |
| LFV-134 | index / IndexWriter doc-values updates and the writer-wide field registry (FieldInfos.FieldNumbers) | low | A rejected IndexWriter#updateDocValues call (an index-sort field, SORTED or SORTED_SET doc values, or a bad later field in the same call) first registers a never-seen field as doc-values-only, so later legal documents that index that field are rejected until the writer is reopened | 1 |
| LFV-436 | index / IndexWriter addIndexes(CodecReader...) failure path (AddIndexesMergeSource queue, SerialMergeScheduler) | low | A failed addIndexes(CodecReader...) leaves its unstarted merges in the writer-wide addIndexes queue, so the next addIndexes call runs them on the earlier call's readers and fails with AlreadyClosedException if those readers were closed | 1 |
| LFV-629 | index / IndexWriter addIndexes(CodecReader...) (writer-wide AddIndexesMergeSource queue, SerialMergeScheduler) | low | With SerialMergeScheduler, a valid addIndexes(CodecReader...) call can run a concurrent call's queued merge on its own thread and fail with that merge's exception, discarding its own completed merge | 1 |
| LFV-632 | index / IndexWriter addIndexes(CodecReader...) entry check vs deleteAll (abortMerges) | low | addIndexes(CodecReader...) throws AlreadyClosedException 'this IndexWriter is closed' on an open writer when it overlaps a deleteAll() that is waiting for a running merge to abort, although deleteAll's javadoc says such callers may receive MergeAbortedException | 1 |
| LFV-321 | core / search: TermInSetQuery equality (MultiTermQuery rewrite methods); consequence in index / IndexWriter delete-by-query buffering | low | TermInSetQuery.equals/hashCode ignore the rewrite method, so set queries that match different documents compare equal, and IndexWriter's delete-by-query buffer then applies only one of them | 1 |
| LFV-946 | queries / spans: SpanMultiTermQueryWrapper equality (span rewrite methods); consequence in index / IndexWriter delete-by-query buffering | low | SpanMultiTermQueryWrapper.equals/hashCode ignore the span rewrite method (since 5.5.0), so wrappers that match different documents compare equal and IndexWriter's delete-by-query buffer keeps only one of two such deletes | 3 |
| LFV-295 | queries / intervals (PayloadFilteredTermIntervalsSource equality; IntervalQuery dedup and cache keys) | low | Intervals.term(term, payloadFilter) sources compare equal whatever their payload filter, so Intervals.or/ordered/unordered, BooleanQuery rewrite and the query cache merge sources that match different positions | 1 |
| LFV-464 | queries / intervals (PayloadFilteredTermIntervalsSource Matches API; Weight#matches consumers) | low | Intervals.term(term, payloadFilter) returns non-null Weight#matches for documents in which the filter rejects every position of the term (documents the query does not match), so a BooleanQuery that excludes such a clause has no Matches for its own hits | 1 |
| LFV-292 | queries / intervals (IntervalQuery equality, consumed by BooleanQuery and DisjunctionMaxQuery duplicate-clause handling) | low | IntervalQuery equals/hashCode ignore the score function (pivot/exp), so BooleanQuery merges two differently scored IntervalQuery clauses into one and returns wrong, clause-order-dependent scores | 1 |
| LFV-403 | join / JoinUtil numeric score join (PointInSetIncludingScoreQuery equals/hashCode) | low | Numeric score joins (JoinUtil numeric overload, PointInSetIncludingScoreQuery) compare equal when only their per-value join scores differ, so DisjunctionMaxQuery keeps only one of two such joins and BooleanQuery merges them, returning wrong, clause-order-dependent scores | 1 |
| LFV-302 | spatial-extras / value sources (ShapeAreaValueSource equality, consumed by FunctionScoreQuery, area filters and BooleanQuery duplicate-clause handling) | low | ShapeAreaValueSource leaves its multiplier out of equals/hashCode, so area sources with different multipliers compare equal and BooleanQuery merges or drops their clauses: wrong, clause-order-dependent scores, and wrong hits for area filters | 1 |
| LFV-216 | expressions / ExpressionValueSource equality (cache keys of FunctionMatchQuery and facet DoubleRange drill-down queries built on expressions) | low | Expressions: ExpressionValueSource.equals/hashCode ignore the functions an expression was compiled with, so the same expression text compiled with different custom functions compares equal and the query cache can return one query's matches for the other | 1 |
| LFV-506 | analysis / CharArraySet and CharArrayMap (stop-word, keyword and stem-override sets and maps) | low | CharArrayMap.hashCode() and CharArraySet.hashCode() change on every call and differ for equal instances, because the inherited AbstractMap/AbstractSet hashCode sums identity hash codes of a fresh entry object and a fresh char[] key clone made on every iteration | 1 |
| LFV-1079 | queries / function queries: valuesource.VectorSimilarityFunction equality (base of Float/Byte/Float16VectorSimilarityFunction, and so of the FunctionQuery, FunctionRangeQuery and FunctionScoreQuery that wrap them) | low | Function-query vector similarity value sources (Float/Byte/Float16VectorSimilarityFunction) leave the similarity function out of equals but hash it, so EUCLIDEAN and COSINE sources over the same vectors compare equal with different hash codes | 1 |
| LFV-448 | analysis-opennlp / model cache (OpenNLPOpsFactory and the OpenNLP factories' inform/create) | low | OpenNLP analysis factories cache models and lemma dictionaries JVM-wide by bare file name, so an analyzer built from a second configuration directory silently uses another directory's same-named model (and builds even when its own directory lacks the file); the name namespace and its scope are undocumented (documentation defect of a deliberate design) | 1 |
| LFV-1089 | suggest / FST completion (FSTCompletion.lookup empty result) | low | FSTCompletion.lookup returns one shared, mutable static ArrayList for an empty key or an instance with no entries, so modifying that result leaks into every other FSTCompletion in the JVM | 1 |
| LFV-198 | search / MultiCollectorManager (composition of CollectorManagers) | low | MultiCollectorManager wrapping exactly one manager whose collectors are MultiCollectors (for example a nested MultiCollectorManager) hands that manager the wrong collectors in reduce, so its second and later sub-managers return silently wrong results or throw ClassCastException | 1 |
| LFV-834 | queries / payloads (PayloadScoreQuery.PayloadSpanWeight SimScorer source; SpanScorer null-SimScorer early return) | low | A PayloadScoreQuery that wraps another PayloadScoreQuery (directly or through a same-field FieldMaskingSpanQuery) ignores every payload and scores each hit 1.0 with includeSpanScore=false, and with includeSpanScore=true (the 3-argument constructor's default) fails every search with an AssertionError (-ea) or NullPointerException (-da), because the outer weight borrows the inner PayloadSpanWeight's SimScorer, which is null (since 5.3.0, LUCENE-6706) | 1 |
| LFV-181 | expressions / JavascriptCompiler code generation (boolean operators on long-typed operands: bitwise and shift results, hex and octal literals) | low | Expressions: !, &&, || and ?: keep only the low 32 bits of a bitwise/shift result or hex/octal literal, so a non-zero value such as 1 << 32 or 0x100000000 counts as false | 1 |
| LFV-327 | util / MathUtil inverse hyperbolic functions (asinh, acosh, atanh), reached through the expressions module's default functions asinh, acosh and atanh | low | MathUtil.asinh, acosh and atanh use the textbook log formulas without range reduction: asinh and acosh return Infinity for every finite |x| >= 2^512, asinh and atanh return 0 for tiny nonzero x, and acosh of a large negative x returns an infinity instead of the documented NaN, also through the expression functions asinh, acosh and atanh | 1 |
| LFV-141 | document / range-field doc-values queries (Int/Long/Float/DoubleRangeSlowRangeQuery) | low | Doc-values range queries from *RangeDocValuesField.newSlowIntersectsQuery base equals/hashCode on the caller's min/max arrays but match the bounds copied at construction, so queries built from reused arrays compare equal while matching different ranges | 1 |
| LFV-955 | search / kNN query execution (DocAndScoreQuery public factory, new in 11.0 via #16686; Weight#count and DocIdSetIterator contracts) | low | DocAndScoreQuery.createDocAndScoreQuery (public on main since #16686) keeps repeated doc ids: a document listed twice is counted and returned twice, and a repeated first document of a segment is iterated by the previous segment as doc id == maxDoc (a deleted or MUST_NOT-excluded document comes back, or a search with deletions or a doc-values sort throws) | 1 |
| LFV-123 | search / kNN query rewrite (AbstractKnnVectorQuery#mergeLeafResults extension point, optimistic re-entry pass) and DocAndScoreQuery max score | low | AbstractKnnVectorQuery#mergeLeafResults is documented to return hits in any order, but rewrite() reads the k-th score from the last entry and DocAndScoreQuery the max score from the first, so an override that only reorders the hits changes the results | 1 |
| LFV-460 | index / IndexWriter statistics (soft deletes) | low | IndexWriter#hasDeletions ignores committed soft deletes in segments the writer has not pooled, so a writer reopened on an index whose only deletions are soft deletes (or one that took such segments through addIndexes(Directory)) answers false, and true once an NRT reader is opened | 1 |
| LFV-288 | highlighter / UnifiedHighlighter builder and highlight flags (UnifiedHighlighter.evaluateFlags(Builder) never reads Builder.flags) | low | UnifiedHighlighter.Builder#withFlags is silently ignored: the highlighter always takes its flags from the four boolean builder options | 1 |
| LFV-341 | analysis / kuromoji (KatakanaRomanizer in org.apache.lucene.analysis.ja.completion, the romaji helper of JapaneseCompletionFilter) | low | KatakanaRomanizer.romanize(CharsRef) ignores CharsRef.offset, so a CharsRef that is a slice of a larger char[] is romanized from chars[0, length) instead of the slice (latent: Lucene's own JapaneseCompletionFilter always passes offset 0) | 1 |
| LFV-896 | analysis-common / util OpenStringBuilder (public char-buffer helper; in-tree users KStemmer and HTMLStripCharFilter) | low | OpenStringBuilder.write(OpenStringBuilder arr) copies as many chars as this builder's own length instead of arr's length, so it appends nothing, appends chars from arr's buffer past arr's end (NULs or stale earlier content), or throws ArrayIndexOutOfBoundsException | 1 |
| LFV-1117 | core / util.graph (GraphTokenStreamFiniteStrings.getFiniteStrings: per-path TokenStreams over FiniteStringsIterator's reused IntsRef) | low | GraphTokenStreamFiniteStrings.getFiniteStrings returns TokenStreams that all read the iterator's one reused IntsRef, so a stream read after the next hasNext() or next() call replays another path's tokens, or a mix that is no path of the graph (regression of LUCENE-7638, since 6.5.0) | 1 |
| LFV-1146 | core / document: range and shape doc-values fields (Long/Int/Float/DoubleRangeDocValuesField getMin/getMax over BinaryRangeDocValuesField; LatLon/XYShapeDocValuesField getCentroid, getBoundingBox, numberOfTerms, getHighestDimensionType over ShapeDocValuesField; the inherited Field.setBytesValue) | low | Long/Int/Float/DoubleRangeDocValuesField getMin/getMax (and LatLon/XYShapeDocValuesField getCentroid, getBoundingBox, numberOfTerms, getHighestDimensionType) keep returning the constructor's value after Field.setBytesValue gives the field a new value, while the index gets the new value | 1 |
| LFV-674 | spatial-extras / spatial4j bridge to spatial3d (Geo3dDistanceCalculator.within, the default DistanceCalculator that Geo3dSpatialContextFactory installs) | low | Geo3dDistanceCalculator.within returns the opposite of 'distance <= limit' for every finite distance, so the default distance calculator of the Geo3d spatial context answers every within() call backwards | 1 |
| LFV-740 | spatial3d / geom distance styles (Vector.normalDistance[Squared]; DistanceStyle.NORMAL and NORMAL_SQUARED point-to-point distances in GeoCircle and GeoPath) | low | geo3d NORMAL and NORMAL_SQUARED point distances are wrong on WGS84 and other ellipsoids because Vector.normalDistance assumes a unit-length vector, so the NORMAL distance from a point to itself is up to about 0.0045 planet units (0.00165, about 10.5 km, at latitude 0.3 rad) instead of 0 | 1 |
| LFV-271 | spatial3d / geom path distances (GeoStandardPath component tree: PathSegment, BaseSegmentEndpoint, PathNode; DistanceStyle aggregation forms) | low | GeoPath.computeDistance with DistanceStyle.LINEAR_SQUARED or NORMAL_SQUARED on a path of width > 0 (GeoStandardPath) returns the fourth power of the distance instead of its square for points inside a path segment, because the segment's result is converted back from aggregation form twice (regression since 9.5.0) | 1 |
| LFV-741 | spatial3d / geom path distances (GeoDegeneratePath, the zero-width path; DistanceStyle aggregation forms) | low | On a zero-width geo3d path (GeoDegeneratePath), computePathCenterDistance with DistanceStyle.LINEAR_SQUARED or NORMAL_SQUARED returns the unsquared distance and computeOutsideDistance returns the fourth power, instead of the squared distance, because the 2022 path refactor converted the path components to aggregation form but not the two places that combine them (regression since 9.5.0) | 1 |
| LFV-802 | index / IndexWriter tryUpdateDocValue (tryModifyDocument doc-id validation, doc-values update buffer) | low | IndexWriter#tryUpdateDocValue does not validate the doc id: an id outside [0, maxDoc) returns success and silently updates or soft-deletes a different document, or commits a doc-values entry for a nonexistent document that a merge shifts onto other documents | 1 |
| LFV-098 | index / columnar addBatch (column pass: DictionaryColumn, SORTED_NUMERIC and SORTED_SET doc-values writers) | low | IndexWriter#addBatch does not validate tuple doc-ids on some doc-values column paths: a doc-values-only SORTED/SORTED_SET DictionaryColumn accepts a doc-id outside [0, numDocs) and writes the value onto a neighbouring document, and SORTED_NUMERIC/SORTED_SET columns check doc-id order only with a Java assert, so decreasing doc-ids close the writer (-ea) or are accepted and break later documents and commits (-da) | 1 |
| LFV-1125 | codecs / per-field postings format (PerFieldPostingsFormat field-to-group mapping) | low | PerFieldPostingsFormat's 'no suffix for format name' check misses equal formats with different names when another field already used the second name, so the commit succeeds and that field's postings cannot be read | 1 |
| LFV-1226 | core / document: BinaryPoint range query factory (n-dimensional BinaryPoint.newRangeQuery, PointRangeQuery constructor checks) | low | BinaryPoint.newRangeQuery(String, byte[][], byte[][]) does not throw the IllegalArgumentException its javadoc promises when lowerValue.length != upperValue.length if both bounds pack to the same number of bytes (for example 2 dimensions x 2 bytes against 1 x 4), and instead builds a query that reads the upper bound's bytes in the lower bound's dimension layout, because only the packed byte lengths are compared (since 6.0.0, LUCENE-7117/LUCENE-7118) | 1 |
| LFV-428 | facet / dynamic range facets (DynamicRangeUtil.computeDynamicRanges and computeDynamicNumericRanges, DynamicRangeInfo.centroid) | low | DynamicRangeUtil computes DynamicRangeInfo.centroid ('the average value in the range') from an unchecked long sum of the range's values, so when one range's values sum past Long.MAX_VALUE (for example six epoch-nanosecond timestamps of today) it silently returns a centroid outside [min, max], typically negative for positive values | 1 |
| LFV-027 | queryparser / flexible | low | Flexible StandardQueryParser throws NumberFormatException on a fractional phrase slop | 1 |
| LFV-732 | queryparser / flexible: standard query builders (MinShouldMatchNodeBuilder for the @N min-should-match operator, composed with the grammar's group boost and the single-child Boolean optimization) | low | Flexible StandardQueryParser: the (...)@N min-should-match operator throws ClassCastException when the group does not build a BooleanQuery, e.g. (the fox)@1 with a stop-word analyzer or the boosted group (fox dog)^2@1 | 1 |
| LFV-398 | queryparser / flexible parser term escaping (EscapeQuerySyntaxImpl, as used by QueryNode#toQueryString) | low | Flexible query parser: EscapeQuerySyntaxImpl does not escape '@' after the first character of a term or a term that is exactly && or ||, so QueryNode#toQueryString output for such terms does not parse | 1 |
| LFV-906 | expressions / JavascriptCompiler code generation (compileExpression exception translation for class-file size limits) | low | JavascriptCompiler.compile lets the bytecode generator's method-size failure escape untranslated: a well-formed, shallowly nested expression that is too big for one JVM method throws ASM's MethodTooLargeException (or an ArrayIndexOutOfBoundsException from ASM's frame computation) on 8.5.0 to 10.5.2 and the 10.6.0 release line, and the class-file API's IllegalArgumentException on main, instead of the documented ParseException / IllegalStateException | 2 |
| LFV-197 | expressions / JavascriptCompiler literal parsing (hex and octal literals in visitNumeric) | low | JavascriptCompiler.compile throws NumberFormatException instead of the documented ParseException for a hex or octal literal above Long.MAX_VALUE, such as 0x8000000000000000 | 1 |
| LFV-182 | expressions / JavascriptCompiler nesting-depth guard (compile(String, Map, int maxNestingDepth), new in #16423, released in 10.6.0) | low | JavascriptCompiler.compile(source, functions, Integer.MAX_VALUE) rejects every expression, even '1', because maxNestingDepth + 1 overflows to Integer.MIN_VALUE | 1 |
| LFV-866 | analysis-common / synonym.word2vec (Word2VecSynonymProvider.getSynonyms search size; Word2VecSynonymFilterFactory validation) | low | Word2VecSynonymFilterFactory accepts any positive maxSynonymsPerTerm, but Word2VecSynonymProvider sizes its HNSW search as maxSynonymsPerTerm + 1 with no clamp to the model size, so very large values (Integer.MAX_VALUE, where the + 1 overflows) make every in-model token throw IllegalArgumentException or OutOfMemoryError | 1 |
| LFV-262 | core / search: TopDocs.merge paging window (mergeAux; score, Sort and tie-breaker overloads) | low | TopDocs.merge(start, topN, ...) returns a page of null ScoreDocs, with no error, when start + topN overflows int (for example start = 1 and topN = Integer.MAX_VALUE meaning 'no limit') | 1 |
| LFV-960 | grouping / TopGroups.merge (merging second-pass grouped results across shards or slices) | low | TopGroups.merge throws NegativeArraySizeException when docOffset + docTopN overflows int, for example docOffset = 1 with docTopN = Integer.MAX_VALUE ('all remaining documents'), although docOffset 0 with the same docTopN works | 1 |
| LFV-387 | highlighter / matchhighlight PassageSelector (MatchHighlighter, FieldValueHighlighters) | low | PassageSelector.pickBest (MatchHighlighter) silently drops the highlight passages of permitted ranges that start after offset 0 when maxPassageWindow is Integer.MAX_VALUE: the int window shift 'to += range.from - from' wraps negative, so the second and later values of a multi-valued field lose their snippets (the residue of the LUCENE-10135 overflow fix) | 1 |
| LFV-1003 | suggest / analyzing: AnalyzingSuggester and FuzzySuggester lookup (FST top-N queue depth) | low | AnalyzingSuggester and FuzzySuggester compute the top-N queue depth num * maxAnalyzedPathsForOneInput in int, so with a synonym (token graph) analyzer a large num wraps it: lookup silently returns too few suggestions and skips higher-weighted ones, or throws NoSuchElementException, and with assertions on lookup(key, false, Integer.MAX_VALUE) typically fails 'assert completions.isComplete' | 1 |
| LFV-061 | search / HNSW | low | Concurrent HNSW build retries a lost entry-node promotion with the wrong query vector | 1 |
| LFV-004 | codecs / merge instances | low | Merge instances re-open segment files by name, so merging an old reader after a name reuse can copy another segment's data | 1 |
| LFV-331 | store / FSDirectory pending deletes (delete retry vs. the createOutput/rename revive, thread safety) | low | FSDirectory: a pending-delete retry running on one thread can delete a file that another thread has just re-created (createOutput) or renamed onto the same name, so a file that was written and closed successfully silently disappears | 1 |
| LFV-343 | store / NativeFSLockFactory (write.lock: in-JVM LOCK_HELD guard and cross-process mutual exclusion) | low | NativeFSLockFactory tracks the write locks this JVM holds by real-path string instead of by file, so obtaining write.lock through a second path to the same file (a hard link, or a bind mount of the index directory) opens and closes a second channel on it, which silently drops the holder's OS lock while its ensureValid() keeps passing and lets an IndexWriter in another process open and commit to the same index | 1 |
| LFV-912 | misc / store: HardlinkCopyDirectoryWrapper#copyFrom hard-link path (against the core/store Directory#copyFrom and FilterDirectory#copyFrom contracts; reached through core/index IndexWriter.addIndexes(Directory...)) | low | HardlinkCopyDirectoryWrapper.copyFrom unwraps both directory chains to the innermost FSDirectory and hard-links there, so every FilterDirectory in between is skipped for the copied file: an inner TrackingDirectoryWrapper does not record it, an inner LockValidatingDirectoryWrapper does not check its lock, and a one-sided byte-transforming or namespace-owning layer is bypassed | 2 |
| LFV-365 | store / NRTCachingDirectory (Directory write-once contract) | low | NRTCachingDirectory.createOutput does not throw FileAlreadyExistsException when the name already exists in its other home (RAM cache vs wrapped directory), so the file ends up in both homes: deleteFile then leaves the other copy listed and readable, and close() fails and, with assertions disabled, loses the file | 1 |
| LFV-836 | store / ByteBuffersDirectory (rename vs. a concurrent createOutput or rename onto the source name) | low | ByteBuffersDirectory.rename ends with a leftover unconditional files.remove(source), so a file that another thread creates (createOutput) or renames onto the source name while the rename runs is silently deleted, although that thread's call returned normally | 1 |
| LFV-1158 | store / ByteBuffersDirectory (rename failure path: two concurrent renames of one source) | low | ByteBuffersDirectory.rename throws IllegalStateException without removing the dest it has already published, so two concurrent renames of one source leave the file listed under both new names | 1 |
| LFV-191 | misc / index tools (IndexSplitter.split, SegmentInfos.commit durability) | low | IndexSplitter.split publishes a durable commit in the destination index without fsyncing the segment files it copied, so an OS crash or power loss soon after a split can leave a destination whose newest commit references empty files and cannot be opened | 1 |
| LFV-201 | index / IndexFileDeleter and util/FileDeleter (deletion of expired commits, crash durability) | low | After a commit, IndexFileDeleter deletes the old segments_N and then the files only it referenced with no directory fsync in between, so an OS crash that persists those unlinks out of order can leave a stale older commit that blocks IndexWriter | 1 |
| LFV-194 | index / deletion policies (PersistentSnapshotDeletionPolicy persistence, directory fsync) | low | PersistentSnapshotDeletionPolicy.snapshot() and release() return before the new save file's name is durable: persist() fsyncs snapshots_N but never calls Directory.syncMetaData(), so an OS crash or power loss can lose an acknowledged snapshot | 1 |
| LFV-1092 | index / SegmentInfos.FindSegmentsFile (commit discovery) | low | SegmentInfos.FindSegmentsFile's double listAll() check misses a weakly consistent listing when each of its two listings overlaps one complete commit, so opening a healthy index can throw IndexNotFoundException (residual of open #3659 / LUCENE-2585; shown only with a simulated weakly consistent listing) | 1 |
| LFV-1142 | util / FST (FSTCompiler.Builder.build: the default on-heap DataOutput) | low | FSTCompiler.Builder.build() stores its lazily created default on-heap DataOutput in the Builder, so a second build() from the same Builder shares the first compiler's output and the second FST silently misses its own keys | 1 |
| LFV-1159 | util / FST (Util.readCeilArc: follow overwritten by readFirstTargetArc before the list-node scan re-reads follow.target()) | low | Util.readCeilArc returns a wrong arc or null, with no error, when one Arc object is passed as both follow and arc and the target node is list-encoded, and reads FST address -1 when follow is final (since 4.1.0) | 1 |
| LFV-052 | util / FST | low | FSTMetadata.save always writes the current version, so re-saving a pre-9.0 BYTE2 FST breaks its lookups | 1 |
| LFV-024 | search / multi-term queries | low | FuzzyQuery on the empty term matches only the empty term | 1 |
| LFV-020 | util / automaton | low | The Kleene star of the empty language returns the empty language instead of {""} | 1 |
| LFV-1167 | util / automaton (Operations.totalize, used by Operations.complement and Operations.minus) | low | Operations.complement and minus give a wrong, non-deterministic result for an automaton with an arc ending at Integer.MAX_VALUE, because totalize computes t.max + 1 in int and the wrap adds a dead-state arc that overlaps the real arc | 1 |
| LFV-813 | util / automaton | low | RegExp numeric interval <n-m> accepts a leading '+' on a bound and counts it as a digit, so <+1-+9> matches 01..09 instead of 1..9 and <+100-999> loses its fixed width | 1 |
| LFV-441 | util / automaton | low | Automata.makeDecimalInterval accepts a negative min without error and returns an automaton with the wrong language (for [-1, 5] it rejects "0" to "4" and accepts "12" and "-1"), or for some inputs throws StringIndexOutOfBoundsException | 1 |
| LFV-869 | core / analysis: AutomatonToTokenStream (automaton to token-graph conversion) | low | AutomatonToTokenStream casts each transition label to char, so a label above U+FFFF becomes a different character (U+10400 comes out as U+0400, U+1F600 as U+F600, U+10000 as a NUL char) | 1 |
| LFV-1166 | util / FST (Outputs.skipFinalOutput default; FST.findTargetArc list-node scan) | low | Outputs.skipFinalOutput's default calls skipOutput, not readFinalOutput as its javadoc says, so an Outputs subclass with its own final-output encoding makes Util.get and FSTEnum.seekExact silently miss keys that are in the FST | 1 |
| LFV-1147 | util / FST (FSTEnum.rewindPrefix label compare; IntsRefFSTEnum seekCeil/seekFloor) | low | A reused IntsRefFSTEnum gives wrong seekCeil/seekFloor results after visiting a term with label Integer.MAX_VALUE, because FSTEnum.rewindPrefix compares labels by subtraction and it overflows | 1 |
| LFV-1163 | util / FST (IntsRefFSTEnum seek targets vs. FSTEnum's virtual END_LABEL arc) | low | IntsRefFSTEnum.seekCeil returns a term below the target (and seekFloor and seekExact answer wrongly) when a negative target int follows a prefix that is itself a term, because the seek compares it with the virtual end-of-term arc whose label is FST.END_LABEL = -1 | 1 |
| LFV-1204 | util / FST (FSTCompiler fixed-length node encoding: binary search vs direct addressing) | low | FSTCompiler.Builder#directAddressingMaxOversizingFactor is documented so that any negative factor disables direct addressing, but a very negative one (Float.NEGATIVE_INFINITY, -Float.MAX_VALUE, or about -1e8 and below) saturates the int cost arithmetic in shouldExpandNodeWithDirectAddressing and turns direct addressing on, so five sparse BYTE4 keys give a 33.5 MB FST instead of 34 bytes (since 8.4.0) | 1 |
| LFV-482 | facet / taxonomy NRT reopen (DirectoryTaxonomyWriter.replaceTaxonomy and deleteAll epoch vs DirectoryTaxonomyReader.doOpenIfChanged) | low | An NRT DirectoryTaxonomyReader reopened during DirectoryTaxonomyWriter.replaceTaxonomy keeps the replaced taxonomy's ordinal/label caches and parent arrays, because the epoch is incremented only after the content change (wrong labels that persist, or ArrayIndexOutOfBoundsException from openIfChanged) | 2 |
| LFV-012 | index / IndexWriter NRT | low | An orphaned NRT reader can report isCurrent() true for different index content after a new writer session | 1 |
| LFV-591 | index / IndexWriter construction from a reader's IndexCommit (SegmentInfos.version; DirectoryReader.isCurrent and openIfChanged) | low | IndexWriter opened from an older reader's IndexCommit takes SegmentInfos.version from that reader, not from the newest commit, so its commits can reuse the version of a newer commit and a reader still open on that commit reports isCurrent()=true and openIfChanged returns null | 1 |
| LFV-017 | index / IndexWriter NRT | low | Data race on SegmentInfos.version between newSegmentName and checkpoint | 3 |
| LFV-1127 | index / IndexWriter two-phase commit (sequence numbers) | low | IndexWriter.prepareCommit() re-reads the shared pendingSeqNo field after its post-commit maybeMerge, so if another thread finishes that commit and prepares the next one meanwhile, prepareCommit() returns the next commit's sequence number | 1 |
| LFV-184 | index / IndexWriter addIndexes(CodecReader...) vs rollback (AddIndexesMergeSource, ConcurrentMergeScheduler) | low | addIndexes(CodecReader...) can register a merge and start a merge thread after a concurrent rollback() has returned, because AddIndexesMergeSource.registerMerge does not re-check that merges are enabled | 1 |
| LFV-188 | index / IndexWriter forceMergeDeletes MergeObserver (MergePolicy.MergeObserver, MergeSpecification.await) | low | MergeObserver.await() and await(timeout) return true after a failed or aborted merge, although their javadoc says they return false on error | 1 |
| LFV-312 | search / ReferenceManager refresh listeners (ControlledRealTimeReopenThread, LiveFieldValues) | low | A ReferenceManager refresh that throws is reported to its refresh listeners as afterRefresh(false), the same signal as 'nothing changed', so ControlledRealTimeReopenThread.waitForGeneration returns true for a change the current searcher does not contain and LiveFieldValues drops the values it buffered | 3 |
| LFV-1024 | replicator / NRT segment replication (PrimaryNode.flushAndRefresh, setCurrentInfos: NRT point publication) | low | NRT PrimaryNode: one I/O error during flushAndRefresh leaves the new point unpublished to replicas, and the retry reports no changes | 1 |
| LFV-260 | replicator / NRT segment replication (ReplicaNode.commit commit user data, PrimaryNode.getLastCommitVersion) | low | An NRT replica's commit() can store in VERSION_KEY the version of a newer NRT point installed during its fsync, so the commit claims a version ahead of the SegmentInfos it holds | 1 |
| LFV-270 | replicator / NRT segment replication (ReplicaNode.newNRTPoint, maybeNewPrimary, launchPreCopyMerge: primaryGen fencing) | low | An NRT replica acts on a late notification from an older primary generation: ReplicaNode.maybeNewPrimary deletes the current primary's pre-copied merged segment before its only check, an assert, so the replica's cut-over to the merged point fails or the segment is copied again (with or without assertions), and with assertions off lastPrimaryGen also moves back | 1 |
| LFV-245 | replicator / NRT segment replication (ReplicaNode.launchPreCopyMerge merge pre-copy, ReplicaNode.newNRTPoint) | low | An NRT replica's merge pre-copy callback (ReplicaNode.launchPreCopyMerge) synchronizes on itself instead of the ReplicaNode, so a primary change that lands while it installs the merged files leaves the old primary's pre-copied merged files pending and on disk | 1 |
| LFV-1066 | core / search: SearcherLifetimeManager (keeping old searchers for follow-up requests such as paging) | low | SearcherLifetimeManager.prune orders searchers by the time each was first recorded instead of newest to oldest, so when an older searcher is first recorded after the current one, PruneByAge drops the current searcher (even right after record() returned a token for it) and keeps the older one | 1 |
| LFV-1221 | core / search: ReferenceManager (SearcherManager, ReaderManager and other subclasses) | low | ReferenceManager.maybeRefresh releases the new reference it has just made current when releasing the old one throws, so every later acquire() throws IllegalStateException (since 3.5.0) | 1 |
| LFV-015 | index / IndexWriter NRT | low | After rolled-back segment names are reused, reopening an old NRT reader throws a misleading IllegalStateException | 1 |
| LFV-164 | search / top-k dynamic pruning (BayesianScoreQuery: BayesianScoreScorer#setMinCompetitiveScore) | low | BayesianScoreQuery raises the minimum competitive score to at least 1e-7 before passing it to its inner query, so default top-k search silently drops the best hits when every competitive calibrated score is below 1e-7 | 1 |
| LFV-450 | search / top-k dynamic pruning (BayesianScoreQuery: BayesianScoreScorer#setMinCompetitiveScore) | low | BayesianScoreQuery turns the minimum competitive probability into an inner-score threshold that lies inside the range of inner scores with exactly that probability, so default top-k search can skip a hit that is still competitive | 1 |
| LFV-104 | search / top-k dynamic pruning (block-max conjunction and MaxScore bulk scorers) | low | ScorerUtil.minRequiredScore returns NaN when the minimum competitive score is +Infinity, so block-max conjunctions and MaxScore disjunctions drop documents that score +Infinity | 1 |
| LFV-113 | search / top-k dynamic pruning (WANDScorer) | low | WANDScorer mishandles a minimum competitive score of +Infinity: an assertion fails with -ea, and with -da it prunes documents that score +Infinity | 1 |
| LFV-1124 | core / search (DisjunctionMaxQuery: DisjunctionMaxScorer.score and DisjunctionMaxWeight.explain) | low | DisjunctionMaxQuery with tie-breaker 0 scores NaN instead of +Infinity when two matching disjuncts score +Infinity (Infinity + Infinity * 0), so COMPLETE-mode collection, some BooleanQuery nestings and explain() disagree with the default top-k search (since 1.9) | 1 |
| LFV-304 | core / search and document: query parameter validation (DisjunctionMaxQuery, LatLonPoint distance feature query) | low | DisjunctionMaxQuery and LatLonPoint.newDistanceFeatureQuery accept a NaN tie-breaker or pivot distance (the pivot also +Infinity) because their range checks are false for NaN, so hits score NaN and a NaN query is not equal to itself | 1 |
| LFV-426 | core / document: XY distance sort (XYDocValuesField.newDistanceSort, XYPointSortField, XYPointDistanceComparator) | low | XYDocValuesField.newDistanceSort accepts a NaN or infinite origin although its javadoc promises IllegalArgumentException for invalid coordinates (the LatLon twin and every other XY entry point reject such values); with a NaN origin, documents without a location sort first instead of last | 1 |
| LFV-1191 | core / store: SleepingLockWrapper (constructor pollInterval check, obtainLock) | low | SleepingLockWrapper's constructor accepts pollInterval 0 (it rejects only negative values: 'pollInterval must be a non-negative number'), and then every obtainLock on the wrapper, including the write-lock acquisition in IndexWriter's constructor, throws ArithmeticException '/ by zero' from 'lockWaitTimeout / pollInterval' instead of the constructor rejecting 0 up front (since 5.3.0) | 1 |
| LFV-083 | queries / function | low | FunctionRangeQuery over Int/Long/EnumFieldSource turns an exclusive bound at the type limit into an inclusive one | 1 |
| LFV-1100 | grouping / TopGroups.merge (sharded grouping) | low | TopGroups.merge adds each group's per-shard long hit counts into an int, so a group with more than Integer.MAX_VALUE hits over all shards makes the merge throw IllegalArgumentException (two shards) or return a wrong positive hit count and average score (three or more shards) (known: #10342 / LUCENE-9302) (released) | 1 |
| LFV-172 | core store + index / stored string fields (DataInput.readString decode, IndexWriter.MAX_STORED_STRING_LENGTH check) | low | IndexWriter accepts a stored string of 2^30 - 1 or more UTF-8 bytes of non-Latin-1 text (from about half of its own MAX_STORED_STRING_LENGTH up), but DataInput.readString can never decode it, so StoredFields#document, visitor-path merges and index-sorted flushes throw OutOfMemoryError | 1 |
| LFV-613 | util / BKD points (BKDWriter in-heap sort buffer sizing: HeapPointWriter and the BKDRadixSelector heap writers, reached through Lucene90PointsWriter's public maxMBSortInHeap constructor) | low | BKDWriter does not cap its in-heap point buffer at the Java array limit, so with maxMBSortInHeap >= 2048 MB a points merge of more than 2^31 bytes throws NegativeArraySizeException and closes the IndexWriter | 1 |
| LFV-385 | index / IndexingChain aborting-exception classification x util / UTF-16 to UTF-8 sizing (CharTermAttributeImpl.getBytesRef, BytesRefBuilder.copyChars, UnicodeUtil.maxUTF8Length) | low | A single indexed token of 715,827,878 or more UTF-16 units closes IndexWriter and drops uncommitted documents instead of being rejected as an immense term | 4 |
| LFV-1076 | index / IndexWriter delete buffer and stall control (DocumentsWriter.applyDeleteOrUpdate vs the #16867 delete-buffer hard limit) | low | During a commit or NRT refresh, deleteDocuments(Term...) and doc-values updates never wait on the delete-buffer stall added by #16867, so the shared delete buffer still grows past its hard limit and can overflow at 2 GiB (main and branch_11x only) | 1 |
| LFV-386 | index / in-RAM postings byte slices (ByteSliceReader, TermsHashPerField) | low | ByteSliceReader's final-slice test (nextIndex + newSize >= endIndex) overflows int when a postings stream's last slice ends exactly at the 2^31-byte end of the in-RAM byte pool, so IndexWriter silently commits up to 3 wrong postings bytes that CheckIndex accepts | 1 |
| LFV-458 | search / HNSW (merge-time graph reuse: old-to-new ordinal mapping in IncrementalHnswGraphMerger and ConcurrentHnswMerger) | low | HNSW merge with graph reuse throws BufferAllocationException when the reused graph has more than 805,306,368 vectors | 1 |
| LFV-048 | search / scoring | low | BooleanScorer loops forever on the last 4096-doc window of a segment of about 2^31 documents, and a query timeout cannot stop it | 1 |
| LFV-383 | facet / DrillSideways (sequential DrillSidewaysScorer, union and drill-down-advance strategies) | low | Sequential DrillSideways never returns on a segment of more than 2^31 - 2048 documents: DrillSidewaysScorer's int chunk start wraps to Integer.MIN_VALUE, so its union and drill-down-advance loops never exit (released since 4.2.0) | 1 |
| LFV-139 | search / BooleanQuery MUST_NOT bulk scoring (ReqExclBulkScorer) | low | ReqExclBulkScorer.WindowBits.applyMask adds offset + bitSet.length() in int, so FILTER/MUST + MUST_NOT queries silently drop every match in a 4096-doc window based at doc 2^31-4096 or above (up to the last 3,967 doc IDs of a segment near IndexWriter.MAX_DOCS) | 1 |
| LFV-185 | codecs / postings reader (Lucene104 BlockPostingsEnum position bookkeeping; also the Lucene101, Lucene103, Lucene99 and Lucene90 readers in backward-codecs) | low | Postings readers count skipped positions in an int, so once the skipped occurrences of one term within a postings block pass Integer.MAX_VALUE, nextPosition() returns an earlier document's positions and phrase queries silently miss matches | 1 |
| LFV-754 | misc / similarities (SweetSpotSimilarity lengthNorm; NaN effect on impacts-based top-k pruning in core search) | low | SweetSpotSimilarity.lengthNorm adds abs(x-min) + abs(x-max) in int, so a field of 1,073,741,848 or more terms (reachable with one custom term frequency) gets a NaN norm: the document is never collected, and default top-k search also skips competitive documents in the same postings block and skip range | 1 |
| LFV-661 | suggest / FreeTextSuggester (n-gram counts stored as long FST outputs; lookup-side decode) | low | FreeTextSuggester.decodeWeight casts n-gram counts to int, so a word or context seen more than Integer.MAX_VALUE times gets a negative or wrapped count: lookup returns scores outside the documented 0.0 to 1.0 range and can rank the most frequent word last | 2 |
| LFV-107 | store / ByteBuffersDataOutput | low | ByteBuffersDataOutput.copyBytes narrows its long length to a signed int, so a copy of 2 GiB or more (for example Directory.copyFrom into a ByteBuffersDirectory) silently copies nothing or only (int) numBytes bytes | 1 |
| LFV-186 | codecs / stored fields (Lucene90 compressing writer) | low | Stored fields writer: the int slice loop in flush() wraps once a chunk is larger than 2,147,450,880 bytes, so a ~2 GiB document within the documented per-document limit closes IndexWriter when smaller documents are still buffered in its chunk | 1 |
| LFV-1150 | codecs / compressing (Compressor.compress in CompressionMode FAST, FAST_DECOMPRESSION, HIGH_COMPRESSION and the Lucene90 preset-dict compressors) | low | Compressor.compress casts ByteBuffersDataInput.length() to int, so an input of 2^32 + k bytes is compressed as only its first k bytes and the call returns normally | 1 |
| LFV-163 | codecs / stored fields (Lucene90StoredFieldsFormat javadoc vs Lucene90CompressingStoredFieldsFormat) | low | Lucene90StoredFieldsFormat (the default codec's stored fields) documents a per-document limit of 2^31 - 2^14 bytes, but the format it delegates to documents and enforces 2^31 - chunkSize (chunks of 81,920 / 491,520 bytes), so a document just below the stated limit can fail with ArithmeticException and close IndexWriter (documentation defect: the javadoc value has been stale since the chunks grew past 16 KiB) | 1 |
| LFV-285 | index / IndexWriter addIndexes(CodecReader...) (addIndexesReaderMerge merged view: SlowCompositeCodecReaderWrapper over a MultiReader, BaseCompositeReader doc limit) | low | addIndexes(CodecReader...) with the default config rejects inputs whose maxDoc() sum, deleted documents included, exceeds MAX_DOCS although only their live documents are added, because it always builds a merged view of the inputs for OneMerge#reorder (regression since 9.9.0) | 1 |
| LFV-531 | misc / index tools (MultiPassIndexSplitter.split, round-robin mode) | low | MultiPassIndexSplitter's round-robin split loses or duplicates the last few documents of an index at about IndexWriter.MAX_DOCS for most part counts of 145 or more, because its int test (j + numParts - i) % numParts overflows | 1 |
| LFV-1140 | index / index sorting at merge: IndexSorter.StringSorter merge keys (MultiSorter), reached through IndexWriter.addIndexes(CodecReader...) | low | Index sorting by a STRING field with STRING_LAST: at merge, a document without a value gets the int key Integer.MAX_VALUE while documents with a value get long global ordinals, so when the inputs of one merge hold more than 2^31 - 1 distinct values (reachable through IndexWriter.addIndexes(CodecReader...)), the merged segment silently puts documents without a value ahead of documents with a value | 1 |
| LFV-147 | codecs / live docs (Lucene90LiveDocsFormat) and index / CheckIndex live-docs check | low | Lucene90LiveDocsFormat.writeLiveDocs and CheckIndex.bitsCardinality step an int offset by 1024 that wraps to Integer.MIN_VALUE for segments of more than 2,147,482,624 documents, so a deletion in such a segment can never be committed (10.4.0+) and CheckIndex at level 2 or higher reports its valid live docs as an error (10.3.0+) | 1 |
| LFV-170 | codecs / postings reader (Lucene104 BlockPostingsEnum#docIDRunEnd, also the Lucene101 and Lucene103 readers); index / CheckIndex | low | Postings docIDRunEnd() returns Integer.MIN_VALUE for dense blocks after a term's last level-1 skip block when doc IDs are within 8,192 (4,096 before 10.4) of 2^31, so CheckIndex at level 2 or higher reports a healthy segment of about 2^31 documents as corrupt | 1 |
| LFV-137 | util / FixedBitSet growth (ensureCapacity) and index / DocsWithFieldSet (doc-values and norms flush) | low | FixedBitSet.ensureCapacity computes the grown length as int arr.length << 6, which wraps negative once the requested bit reaches about 1.91 billion, so DocsWithFieldSet iterates no documents and a flushed segment silently drops every value of its sparse doc-values and norms fields | 1 |
| LFV-143 | util / VectorUtil byte DOT_PRODUCT score x internal/vectorization / Panama MemorySegment byte scorers | low | Byte DOT_PRODUCT scores (VectorUtil.dotProductScore and the two Panama byte scorers) compute len * 2^15 in int, so from 65,536 dimensions every score is mirrored around 0.5 (closer vectors score lower) and at 131,072 dimensions scores become +/-Infinity or NaN | 1 |
| LFV-138 | util / byte-vector similarity kernels (VectorUtil, both vectorization providers) | low | Byte-vector similarity kernels wrap their int accumulators from 33,026 dimensions (squareDistance and the uint8 kernels) and from 131,072 dimensions (dotProduct, cosine), below the 2^18 / 2^16 no-overflow bounds their code comments state | 2 |
| LFV-390 | core vectorization + misc native C / opt-in native int8 dot product (NativeVectorUtilSupport, lucene/misc/src/c/dotProduct.c vdot8s_sve) | low | The example native int8 dot product (lucene/misc/src/c/dotProduct.c, opt-in via -Dlucene.useNativeDotProduct=true) keeps its SVE loop index in int32, so VectorUtil.dotProduct(byte[], byte[]) on two arrays of at least 2^31 - 4*VL elements (2,147,483,520 at 256-bit SVE, 2,147,483,584 at 128-bit SVE) overflows the loop bound, reads past the end of both arrays and kills the JVM with SIGSEGV in vdot8s_sve | 1 |
| LFV-160 | search / HNSW (merge-time graph reuse: IncrementalHnswGraphMerger base-graph selection) | low | HNSW merge computes a graph's deleted percentage in int, so a graph with more than 21,474,836 deleted vectors (41-100% deleted) passes the 40% DELETE_PCT_THRESHOLD and is reused as the merge base; in 10.4.0-10.6.0 and branch_10x the opt-in concurrent merger then throws ArrayIndexOutOfBoundsException for an all-deleted base (main since #16794, 11.0 only, rebuilds the graph instead) | 1 |
| LFV-007 | util / FST | low | FSTCompiler silently writes a corrupt FST when a fixed-length-arc node would expand to 2^31 bytes or more | 1 |
| LFV-003 | codecs / doc values | low | Bulk BinaryDocValues#binaryValues (new in 10.6) sizes its buffer in int: it fails at 2 GiB and can return wrong bytes at 4 GiB | 1 |
| LFV-381 | codecs / doc values (Lucene90DocValuesProducer dense byte-aligned bulk decode, NumericDocValues#longValues) | low | Bulk NumericDocValues#longValues (new in 10.5.0) throws on a valid dense segment for one exact request size per byte-aligned width, because its size guard checks the unpadded byte count against Integer.MAX_VALUE and then adds the padding bytes in int (40/48-bit: wraps to Integer.MIN_VALUE, 'read past EOF'; 16/24/56-bit: a byte[] above the JVM limit) | 1 |
| LFV-1235 | util / compress (LZ4 fast compression hash table: LZ4.compress, LZ4.compressWithDictionary) | low | LZ4.compress throws ArrayIndexOutOfBoundsException when a reused LZ4.FastCompressionHashTable (documented as safe to reuse) compresses a slice whose start offset plus an offset left in the table by a longer earlier input exceeds Integer.MAX_VALUE (for example the last 2^20 bytes at offset 1,098,951,424 after a 1.1e9-byte input), because FastCompressionHashTable.get rebuilds the match position as base + stored in int and the wrapped negative position passes both of its stale-entry checks (since 8.5.0) | 1 |
| LFV-453 | index / IndexWriter flush-control RAM accounting (DocumentsWriterFlushControl.markForFullFlush drops a 0-document DocumentsWriterPerThread; reached through updateDocuments and softUpdateDocuments with an empty block) | low | IndexWriter.updateDocuments / softUpdateDocuments with an empty block leave about 33 KB of phantom RAM accounting at every refresh or commit that drops the empty per-thread writer, so ramBytesUsed grows without bound and, once it passes the RAM buffer, every later document is flushed into its own segment | 1 |
| LFV-837 | index / buffered doc-values updates (BufferedUpdates, FieldUpdatesBuffer, FrozenBufferedUpdates) | low | IndexWriter buffers the first doc-values update of each field twice in every buffered-updates packet (BufferedUpdates adds again the update that FieldUpdatesBuffer's constructor already recorded), so that update is RAM-accounted twice and, except on the all-same-value numeric path, applied twice to every matching document (since 7.7.0, LUCENE-8590) | 2 |
| LFV-1232 | codecs / term vectors (Lucene90 compressing term-vectors writer; IndexWriter per-thread RAM accounting) | low | Lucene90CompressingTermVectorsWriter.ramBytesUsed() counts its four int[] position and offset buffers at one byte per entry, so IndexWriter under-counts buffered term-vector heap (about 9.6 MB missing for one pending document with 2^20 term-vector positions and offsets) | 1 |
| LFV-1075 | index / IndexWriter tryUpdateDocValue (reader-pool doc-values update RAM) | low | IndexWriter.tryUpdateDocValue never checks the RAM buffer for the doc-values updates it adds, so they pile up on the heap without bound until the next refresh, flush() or commit | 1 |
| LFV-472 | index / IndexWriter NRT merge-on-refresh (getReader point-in-time merges) and IndexFileDeleter refcounts | low | Merge-on-refresh never releases the file references of a merged segment that is dropped because all its documents were deleted during the merge, so IndexWriter leaves that segment's files on disk until the next writer opens the index | 1 |
| LFV-630 | core / index IndexFileDeleter reference counting (non-commit checkpoint after a failed Directory.deleteFile; reached from IndexWriter flush, NRT flush and tryDeleteDocument) | low | A Directory.deleteFile failure during a non-commit IndexFileDeleter checkpoint (for example while a flush drops a fully deleted segment) leaves one extra reference on every file of the writer's current segments, so the still-open IndexWriter never deletes those files once they become unused, not even in deleteUnusedFiles(), rollback() or close() | 1 |
| LFV-037 | store / MMapDirectory | low | MMapDirectory loses shared-arena grouping when a closing arena removes a newer live arena | 1 |
| LFV-177 | index / TieredMergePolicy forced merges (findForcedMerges, IndexWriter.forceMerge with maxNumSegments > 1) | low | TieredMergePolicy forceMerge(n) with n > 1 can leave more than n segments, because segments too large to re-merge are not counted toward n | 1 |
| LFV-592 | index / IndexWriter forced merge (writer-wide forced-merge target shared by concurrent forceMerge calls) | low | Two overlapping IndexWriter.forceMerge calls with different maxNumSegments share one writer-wide target, so forceMerge(1) returns normally with 2 segments when a forceMerge(2) starts on another thread while its merges are still running | 1 |
| LFV-178 | index / merge policy (LogMergePolicy forced-deletes selection, IndexWriter.forceMergeDeletes) | low | LogMergePolicy.findForcedDeletesMerges does not skip segments that are already merging, so IndexWriter rejects the whole run and forceMergeDeletes(true) returns with deletes left in segments that were never merging | 1 |
| LFV-502 | index / IndexWriter point-in-time merges (merge-on-commit, merge-on-getReader: updatePendingMerges, registerMerge, preparePointInTimeMerge, MergeSpecification.await) | low | IndexWriter keeps a full-flush merge that registerMerge rejected: commit() does not throw the IllegalStateException that MergePolicy#findFullFlushMerges documents, the rejected merge's readers stay open after IndexWriter.close(), and commit/getReader wait the full maxFullFlushMergeWaitMillis for a merge that never runs | 1 |
| LFV-228 | index / merge policy (SoftDeletesRetentionMergePolicy.numDeletesToMerge, soft deletes) | low | SoftDeletesRetentionMergePolicy.numDeletesToMerge counts a soft-deleted-then-hard-deleted document as retained although merges drop it, so merge selection under-counts reclaimable deletes and forceMergeDeletes can leave the hard-deleted document in place | 1 |
| LFV-213 | index / merge policy (TemporalMergePolicy forced-deletes selection, IndexWriter.forceMergeDeletes) | low | TemporalMergePolicy.forceMergeDeletes never expunges deletes from a segment that is the only eligible one in its time window (or the odd one left after full batches) | 1 |
| LFV-1213 | index / merge policy (TemporalMergePolicy forced-deletes merges, IndexWriter.forceMergeDeletes) | low | TemporalMergePolicy with setMaxThreshold(Integer.MAX_VALUE), a value the setter accepts, makes IndexWriter.forceMergeDeletes() throw OutOfMemoryError ('Requested array size exceeds VM limit') and merge nothing, because buildSequentialMerges pre-sizes its batch list to maxThreshold | 1 |
| LFV-179 | index / merge policies (FilterMergePolicy size unit, compound-file threshold) | low | FilterMergePolicy.getSizeUnit() returns BYTES instead of the wrapped policy's unit, so a wrapped LogDocMergePolicy makes compound-file decisions against the byte threshold and forceMerge(1) rewrites an already merged segment every time | 2 |
| LFV-509 | index / merge policies (SoftDeletesRetentionMergePolicy OneMerge wrapping); misc / BP merge-time reordering (BPReorderingMergePolicy) | low | SoftDeletesRetentionMergePolicy's OneMerge wrapper forwards only wrapForMerge, so a reordering policy nested inside it (BPReorderingMergePolicy, or any OneMerge#reorder override) silently never reorders natural or forced merges, and BPReorderingMergePolicy's bp.reordered diagnostic is never written (since 9.9.0) | 1 |
| LFV-572 | index / merge policy compound-file check (MergePolicy.isMerged vs CompoundFormat settings) | low | MergePolicy.isMerged checks a segment read from disk against the codec instance it was loaded with (the shared Codec.forName instance, with default compound-file settings) instead of the writer's codec, so forceMerge(1) with a LogMergePolicy rewrites an already merged segment after every writer reopen | 1 |
| LFV-1017 | codecs / compound-file settings (CompoundFormat on the shared default codec; MIGRATE.md 11.0 recipe) | low | On main (11.0), the MIGRATE.md recipe for compound-file settings (iwc.getCodec().compoundFormat().setShouldUseCompoundFile / setMaxCFSSegmentSizeMB) changes the CompoundFormat of the single shared default codec, so one writer's settings silently become the compound-file settings of every other default-codec IndexWriter in the JVM | 1 |
| LFV-099 | index / IndexWriter NRT reader pool (readers shared with merges) | low | An NRT reader opened during a merge reuses the SegmentReaders the merge opened with a MERGE IOContext, so its searches read through merge-only inputs (direct I/O with DirectIODirectory, on-disk instead of RAM postings with DirectPostingsFormat, sequential read advice with ADVISE_BY_CONTEXT) | 1 |
| LFV-585 | misc / store: DirectIODirectory x core codecs merge-time re-open (the IndexInput#isEfficientFor gate in Lucene99FlatVectorsReader and Lucene90CompressingStoredFieldsReader, #16883/#16905) | low | DirectIODirectory's inputs never override IndexInput#isEfficientFor, so the #16883/#16905 input sharing lets merges of NRT-open segments skip direct I/O and lets later sequential search reads go through the merge's direct-I/O input | 1 |
| LFV-068 | search / HNSW | low | HNSW addConnections descends from the worst upper-level candidate instead of the best | 1 |
| LFV-1105 | codecs / backward-codecs Lucene99 scalar-quantized vectors (OffHeapQuantizedByteVectorValues) | low | The packed int4 Lucene99 scalar-quantized supplier scorer overwrites the score correction cached for its scoring ordinal on a cache miss, so score(i) depends on earlier score() calls; on the released 10.2.x/10.3.x a forceMerge of such a field builds a different HNSW graph, and on main and 10.4+ only internal callers reach it (known: open PR #16830) | 1 |
| LFV-423 | search / filtered kNN (ExitableDirectoryReader with the 9.x HNSW vectors readers in backward-codecs) | low | ExitableDirectoryReader turns off filtered HNSW search on 9.x-format vector segments, so a filtered kNN query ignores the KnnSearchStrategy.Hnsw threshold even when the timeout never fires | 1 |
| LFV-035 | search / sorting | low | DoubleValuesSource and LongValuesSource sort fields never equal identical ones | 1 |
| LFV-1236 | core / search: DisjunctionMaxQuery (equals and hashCode contract) | low | DisjunctionMaxQuery treats tie-breakers 0.0f and -0.0f as equal in equals() (IEEE ==) but hashes their raw bits in hashCode(), so two equal queries get different hash codes and the query cache, BooleanQuery clause sets and other hash-based structures treat them as different queries (since 1.9) | 1 |
| LFV-899 | expressions / SimpleBindings binding resolution (add(String, Expression), getDoubleValuesSource) and the ExpressionValueSource constructor | low | SimpleBindings rebuilds an Expression binding on every reference, so building the source of bindings that share sub-expressions creates one ExpressionValueSource per path (exponential in the depth of sharing) | 1 |
| LFV-905 | expressions / SimpleBindings.validate() (cycle and missing-reference check, CycleDetectionBindings) | low | SimpleBindings.validate() copies the whole binding path into a new set at every step and re-checks every binding once per origin, so validating a plain chain of 2000 expression bindings takes about 45 s instead of about 100 ms (cubic since 8.6.0, a regression from LUCENE-9338) | 1 |
| LFV-1088 | search / field sorting: index-sort early termination (IndexSortedLeafFieldComparator) + NumericComparator points-based sort pruning (competitive iterator) | low | Since #16857 (upstream main and branch_11x, unreleased), a segment that its index sort terminates early can still build an unused points-based competitive iterator when an earlier segment of the same field-sorted search crossed the hits threshold without early termination: NumericComparator keeps hitsThresholdReached on the comparator that all leaves share, so IndexSortedLeafFieldComparator's not forwarding setHitsThresholdReached() no longer stops the delegate's BKD work (512 point doc IDs read in the repro, up to about cost/7 per segment, where 10.6.0 reads 0; performance regression, results correct) | 1 |
| LFV-126 | store / MMapDirectory read advice (MemorySegmentIndexInput slices, compound files) | low | MMapDirectory applies a slice's read advice to the wrong bytes when the slice starts inside an mmap chunk and crosses into the next one (the #14109 prefetch fix missed this caller of advise()) | 1 |
| LFV-081 | search / query cache | low | LRUQueryCache MinSegmentSizePredicate overflows maxDoc * 2, so segments of 2^30+ docs are never cached | 1 |
| LFV-362 | codecs / bloom (BloomFilteringPostingsFormat, DefaultBloomFilterFactory, FuzzySet sizing) | low | BloomFilteringPostingsFormat's default filter silently stops filtering for segments of 226,279,579 docs or more: FuzzySet.createOptimalSet computes 2 * setSize in int, which wraps negative and yields a 64-bit filter with zero hash functions that answers MAYBE for every key (released since 9.6.0) | 3 |
| LFV-169 | codecs / IndexedDISI jump table (presence sets of sparse doc values, norms and vectors) | low | IndexedDISI returns its jump-table entry count as a signed short, so a sparse doc-values, norms or vector field whose last doc id is >= 2,147,352,576 stores a negative count and every reader ignores the jump table that was written (advance walks block by block; results stay correct) | 1 |
| LFV-168 | join / JoinUtil global-ordinals join explain (GlobalOrdinalsQuery, GlobalOrdinalsWithScoreQuery) | low | Global-ordinals join explain() ignores toQuery, so documents that are not hits (from-side documents, or to-side documents a narrower toQuery excludes) are explained as matches | 1 |
| LFV-174 | expressions / ExpressionRescorer explain (Expression.getRescorer, ExpressionValueSource.explain over SortRescorer) | low | ExpressionRescorer.explain evaluates the expression with _score = 0 (the value of SortRescorer's placeholder explanation) instead of the first-pass score, so the explanation shows the wrong _score and expression values; the rescored ranking is correct | 1 |
| LFV-922 | core / search similarities (DFR after effect B explanation: AfterEffectB.explain, reached through DFRSimilarity.explain) | low | AfterEffectB.explain shows the raw totalTermFreq and docFreq under children labelled 'F, ... + 1' and 'n, ... + 1' (and lists tfn twice), so its own formula (F + 1) / (n * (tfn + 1)) on the children it lists does not give the value it shows; the score itself is correct | 1 |
| LFV-921 | core / search similarities (Normalization.NoNormalization explanation; IBSimilarity and DFRSimilarity explain trees) | low | Normalization.NoNormalization.explain reports 1 instead of tf, so IBSimilarity explains its Distribution at tfn = 1 and that child disagrees with the score it explains | 1 |
| LFV-370 | spatial-extras / BBoxStrategy overlap-ratio relevance (BBoxOverlapRatioValueSource.score: explanation tree) | low | BBoxStrategy's overlap-ratio explanation (BBoxOverlapRatioValueSource) shows the target ratio under 'queryFactor' instead of the query ratio, so explain() misreports how the score was computed; the score itself is correct | 1 |
| LFV-920 | core / search similarities (Axiomatic F1/F3 term-frequency explanation, tfExplain) | low | AxiomaticF1EXP, F1LOG, F3EXP and F3LOG explain tf as 'computed as 1 + log(1 + log(freq))' of the raw freq, but the value they show is 1 + log(1 + log(freq + 1)); the score itself is correct | 1 |
| LFV-231 | analysis / Thai (ThaiRepeatFilter offset split; ThaiAnalyzer with ThaiCharFilter, or a custom chain with HTMLStripCharFilter) | low | ThaiRepeatFilter gives the repeated word the offsets of a deleted character or of the following markup instead of the Maiyamok's, when a CharFilter removed characters right after the Maiyamok (a zero-width space in the default ThaiAnalyzer, a closing tag with HTMLStripCharFilter) | 1 |
| LFV-603 | analysis / nori KoreanTokenizer (Viterbi decompound backtrace; UserDictionary and bundled-dictionary compounds) | low | KoreanTokenizer gives the parts of a decompounded word offsets counted back from the end of the word while their text is cut from the start of the word, so when the parts do not cover the whole word (a user-dictionary entry with a shorter segmentation such as '세종시 세종', or 7 compounds of the bundled dictionary such as 픽토그램) the offsets point at other characters (픽토 at [1,3) covers '토그') | 1 |
| LFV-925 | monitor / HighlightsMatch on batches (DocumentBatch: MultiDocumentBatch keeps the caller's FieldType, SingletonDocumentBatch uses MemoryIndex with offsets) | low | Monitor HighlightsMatch returns -1 offsets for a TextField document matched in a batch of two or more documents, but the real offsets when the same document is matched alone; the upstream batch test expects the offsets but cannot notice, because Hit.compareTo ignores offsets | 1 |
| LFV-338 | analysis / char filters (MappingCharFilter, BaseCharFilter offset correction) | low | MappingCharFilter.reset() rewinds the input but keeps the offset corrections recorded on the first pass, so after a reset and re-read correctOffset() (and the token offsets a Tokenizer derives from it) are wrong, or BaseCharFilter's ordering assertion fires | 1 |
| LFV-609 | highlighter / matchhighlight: PassageFormatter multi-marker formatting (crossing markers with per-marker end strings; also end to end through MatchHighlighter, FieldValueHighlighters.highlighted and MatchHighlighter.QueryOffsetRange) | low | matchhighlight PassageFormatter closes crossing markers in opening order instead of innermost first, so per-marker end strings come out mis-nested (e.g. '<a>one <b>two</a></b><b> three</b>' instead of '<a>one <b>two</b></a><b> three</b>') | 1 |
| LFV-774 | highlighter / matchhighlight: PassageSelector passage windows and long-match truncation, BreakIteratorShrinkingAdjuster (through FieldValueHighlighters.maxLeadingCharacters and highlighted) | low | matchhighlight PassageSelector can cut a passage or a truncated match between the two halves of a supplementary character, so FieldValueHighlighters.maxLeadingCharacters and highlighted return a snippet with an unpaired surrogate | 1 |
| LFV-500 | core / util AttributeSource (removeAllAttributes and the cached State chain, getCurrentState / currentState[0]) | low | AttributeSource.removeAllAttributes() leaves the cached State chain in place, so until the next addAttribute() captureState/restoreState, copyTo, hashCode, the impls iterator, reflection and clearAttributes/endAttributes still act on the removed attributes | 1 |
| LFV-026 | queryparser / flexible | low | Flexible StandardQueryParser throws ClassCastException on the input *>a | 1 |
| LFV-355 | queryparser / flexible (AbstractRangeQueryNode.toQueryString, PointQueryNode.getTermEscaped, the StandardSyntaxParser range lexer, the open-bound forms of OpenRangeQueryNodeProcessor and PointRangeQueryNodeProcessor, BooleanQueryNodeBuilder) | low | Flexible query parser: AbstractRangeQueryNode.toQueryString does not keep the 11.0 'can be parsed back' promise for quoted bounds that contain a space, ']' or '}' or for open bounds in processed trees, and an open point bound makes it throw IllegalArgumentException, which escapes StandardQueryParser.parse at the clause limit | 1 |
| LFV-028 | queryparser / classic and flexible | low | A boost too large for a float parses to Infinity and both query parsers throw IllegalArgumentException | 1 |
| LFV-300 | queryparser / classic (QueryParserBase.handleQuotedTerm and getFieldQuery, MultiFieldQueryParser.applySlop; the negative-slop check of PhraseQuery and MultiPhraseQuery.Builder) | low | Classic QueryParser and MultiFieldQueryParser: a negative phrase slop such as "a b"~-1 makes parse() throw IllegalArgumentException instead of ParseException | 1 |
| LFV-715 | queryparser / complexPhrase: ComplexPhraseQueryParser (pass-2 same-field check for clauses nested in a phrase) | low | ComplexPhraseQueryParser skips its same-field check for prefix and regular-expression clauses: "jo* id:2*" parses and then fails at search time with IllegalArgumentException, and name:"id:2*" searches field id | 1 |
| LFV-588 | core / util QueryBuilder token boosts on stacked tokens (newSynonymQuery; BoostAttribute from DelimitedBoostTokenFilter and weighted synonyms; reached through the classic and simple query parsers) | low | QueryBuilder hands a token boost (BoostAttribute) above 1 or equal to 0 on a word that shares its position with a synonym straight to SynonymQuery, which throws IllegalArgumentException, so every query containing that word fails, while the same weight on a word without a synonym works | 1 |
| LFV-548 | analysis-common / synonym (SolrSynonymParser; SynonymGraphFilterFactory and SynonymFilterFactory, format solr) | low | SolrSynonymParser rejects a whole synonyms file because one line holds only spaces or tabs, although its javadoc says blank lines are comments (ParseException 'Invalid synonym rule at line N', every release since 3.4.0) | 1 |
| LFV-307 | analysis / char filters (MappingCharFilterFactory mapping-file parser) | low | MappingCharFilterFactory throws ArrayIndexOutOfBoundsException ('Index 256 out of bounds for length 256') when a mapping rule's source or target is longer than 256 characters, because it unescapes every rule string into a fixed char[256] buffer, so the analyzer cannot be built | 1 |
| LFV-345 | analysis / hunspell (Dictionary affix-file parsing) | low | Hunspell Dictionary throws NullPointerException instead of a parse error when a REP, MAP, ICONV/OCONV, COMPOUNDRULE, BREAK or CHECKCOMPOUNDPATTERN table at the end of the .aff file has fewer lines than its count | 1 |
| LFV-1012 | analysis-common / hunspell Dictionary parsing (AM morphological aliases) | low | Hunspell Dictionary throws a raw ArrayIndexOutOfBoundsException (or NullPointerException) instead of a descriptive error when a .dic entry uses an AM morphological alias number that the .aff file does not define, although the same mistake in the AF flag-alias table gets 'Bad flag alias number' | 1 |
| LFV-372 | util / sorters (Sorter heap sort, IntroSorter's depth fallback) | low | Sorter.heapChild overflows int, so IntroSorter's heap-sort fallback compares a negative slot outside [from, to) when 2*to - from > 2^31 (ArrayIndexOutOfBoundsException from ArrayUtil.introSort on a legal array slice) | 1 |
| LFV-335 | analysis / kuromoji (JapaneseCompletionFilterFactory 'mode' argument parsing, SPI name japaneseCompletion) | low | JapaneseCompletionFilterFactory upper-cases the default mode name instead of the configured value, so mode="query" is rejected with IllegalArgumentException while the sibling JapaneseTokenizerFactory accepts lower-case modes (minor consistency defect; no javadoc promises case-insensitive values) | 1 |
| LFV-439 | analysis-common / compound word factory (DictionaryCompoundWordTokenFilterFactory parameter handling) | low | DictionaryCompoundWordTokenFilterFactory (main only) warns 'onlyLongestMatch has been removed' when the key is absent and stays silent when onlyLongestMatch="false" is passed | 1 |
| LFV-361 | queryparser / xml (BooleanQueryBuilder) | low | XML query parser: a <Clause> without the occurs attribute, which LuceneCoreQuery.dtd and BooleanQueryBuilder's own code default to SHOULD, is rejected with ParserException 'Invalid value for "occurs" attribute of clause:' (regression since 5.1.0, LUCENE-6270) | 1 |
| LFV-570 | core / geo WKT parsing (SimpleWKTShapeParser) | low | SimpleWKTShapeParser rejects a MULTIPOINT whose points each sit in their own parentheses, e.g. MULTIPOINT ((1 2), (3 4)), with ParseException "expected ) but found: ','", although it accepts MULTIPOINT ((1 2)) and MULTIPOINT (1 2, 3 4) (every release since 7.6.0) | 1 |
| LFV-562 | core / geo GeoJSON parsing (Polygon.fromGeoJSON, SimpleGeoJSONPolygonParser) | low | Polygon.fromGeoJSON rejects a valid GeoJSON Feature whose properties (or another non-geometry member object) contain a member named "type", throwing ParseException 'can only handle type ... but got <value>' (every release since 6.2.0) | 1 |
| LFV-569 | core / geo GeoJSON parsing (Polygon.fromGeoJSON, SimpleGeoJSONPolygonParser) | low | Polygon.fromGeoJSON garbles every \uXXXX string escape (it appends the code point as decimal digits and then reads the four hex digits again), so valid GeoJSON with an escaped letter in a key or type value is rejected with ParseException, and a malformed escape throws NumberFormatException (every release since 6.2.0) | 2 |
| LFV-953 | core / geo GeoJSON parsing (Polygon.fromGeoJSON, SimpleGeoJSONPolygonParser) | low | Polygon.fromGeoJSON throws NullPointerException instead of its own ParseException 'coordinates should be an array, but got: ...' when "coordinates" (or an element of a MultiPolygon's coordinates) is JSON null or an object, because the error message calls o.getClass() on the null the parser uses for those values (every release since 6.2.0) | 1 |
| LFV-339 | misc / IndexMergeTool command-line tool (option parsing) | low | IndexMergeTool's '--' end-of-options branch compares Strings with ==, so a command-line '--' is rejected as an unrecognized option, and if the branch ever fires it leaves '--' as the target path | 1 |
| LFV-1035 | luke / Search model paging session (SearchImpl.nextPage, SearchResults.of) behind the Luke Search tab | low | Luke: Search.nextPage() after a full last page returns an empty page with offset 0 instead of Optional.empty() when the hit total is a lower bound, so with default settings and more than 1,000 hits the Search tab ends on an empty page with 'previous' disabled | 1 |
| LFV-1036 | luke / Search model, sorted search (SearchImpl.search) behind the Luke Search tab | low | Luke: a sorted search ignores exactHitsCount, so a sorted Search-tab query with more than 1,000 hits shows a lower-bound total ('1001+ hits') although the Sort tab forces 'exact hits count' on | 1 |
| LFV-264 | facet / taxonomy (SearcherTaxonomyManager.refreshIfNeeded exception path) | low | SearcherTaxonomyManager refresh calls t2.addSuppressed(t2), so when the taxonomy reopen fails and closing the just-reopened index reader also fails, maybeRefresh throws IllegalArgumentException ('Self-suppression not permitted') and the taxonomy failure is lost | 1 |
| LFV-549 | suggest / spell: SpellChecker.indexDictionary (n-gram spell index build, failure cleanup) | low | SpellChecker.indexDictionary never closes or rolls back its IndexWriter when the build throws, so the spell index stays write-locked and every later indexDictionary, clearIndex or IndexWriter on it in the same JVM fails with LockObtainFailedException until the JVM restarts | 1 |
| LFV-507 | monitor / persistent query index (WritableQueryIndex construction, failure cleanup) | low | When opening a persistent Monitor fails after its query index has built the IndexWriter (stored queries the serializer cannot parse, no serializer for a non-empty index, an I/O error, or a purge frequency of 0), the writer and its write lock are never released, so the same index cannot be opened for writing again in that JVM | 1 |
| LFV-555 | facet / taxonomy writer: DirectoryTaxonomyWriter.close() (failure cleanup) | low | DirectoryTaxonomyWriter.close() skips its own cleanup when its commit fails: after an I/O error that closes the internal IndexWriter every close() throws and the writer's near-real-time reader keeps its segment files open, and after an fsync error inside close() the IndexWriter and the taxonomy write lock stay held until close() is retried or rollback() is called (every release since 5.0.0) | 1 |
| LFV-558 | facet / taxonomy writer (DirectoryTaxonomyWriter construction, failure cleanup) | low | DirectoryTaxonomyWriter's constructor never closes or rolls back the IndexWriter it has opened when a later step of the constructor fails with an I/O error, so the taxonomy stays write-locked and every later DirectoryTaxonomyWriter on it in the same JVM fails with LockObtainFailedException | 1 |
| LFV-554 | misc / index tools (MultiPassIndexSplitter.split, failure cleanup) | low | MultiPassIndexSplitter.split never closes the IndexWriter it opened on an output when addIndexes throws, so that output directory stays write-locked and every later IndexWriter or split into it in the same JVM fails with LockObtainFailedException until the JVM restarts | 1 |
| LFV-840 | index / deletion policies (PersistentSnapshotDeletionPolicy save-file failure handling) | low | After one failed fsync of its save file, PersistentSnapshotDeletionPolicy's next fault-free snapshot() or release() fails with FileAlreadyExistsException on its own leftover file: persist() leaves the complete snapshots_N behind when Directory.sync throws and does not advance its generation, while snapshot() and release() undo their change in memory | 1 |
| LFV-446 | index / IndexWriter merge-reader acquisition (ReadersAndUpdates.getReaderForMerge) | low | When a merge fails to open the refreshed reader of a segment with doc-values updates, IndexWriter never releases its reference on the pooled segment reader, so the segment's files stay open after IndexWriter.close | 1 |
| LFV-1065 | core / IndexWriter constructor failure path (reader-commit branch: IndexWriterConfig#setIndexCommit(reader.getIndexCommit()), ReaderPool pre-enrollment; LUCENE-6524, LUCENE-8260) | low | An IndexWriter opened from a reader's IndexCommit whose constructor then fails (for example the IndexDeletionPolicy's onInit throws, or an I/O error while the deleter reads a commit) never releases the segment readers its ReaderPool pre-enrolled from that reader, so the reader's segment files stay open after the caller closes the reader | 1 |
| LFV-495 | core / index reader reopen (FilterDirectoryReader.wrapDirectoryReader on every doOpenIfChanged path; SoftDeletesDirectoryReaderWrapper as the stock trigger) | low | When DirectoryReader.openIfChanged on a FilterDirectoryReader (for example SoftDeletesDirectoryReaderWrapper) fails while wrapping the reopened reader, the newly opened inner reader is never closed, so the segment readers it shares with the old reader, and its files, leak | 1 |
| LFV-1061 | core / index reader open (StandardDirectoryReader.createSegmentReaders, executor branch behind the ExecutorService overloads of DirectoryReader.open and openIfChanged, #15428) | low | DirectoryReader.open and openIfChanged with an ExecutorService never close the segment readers of tasks the executor already accepted when a later submit is rejected (or when the opening thread is interrupted while it waits), so those segments' files stay open | 1 |
| LFV-1059 | core / index reader reopen (StandardDirectoryReader reopen factory behind every non-NRT openIfChanged, with a leaf sorter, LUCENE-9507) | low | DirectoryReader.openIfChanged on a reader opened with a leaf sorter leaks segment reader references when the sorter throws while the new reader is built, so closing the old reader no longer closes the shared segments and the new segment's reader is never closed | 1 |
| LFV-1067 | core / NRT reader open from IndexWriter (StandardDirectoryReader.open(IndexWriter, ...) failure path, with an IndexWriterConfig leaf sorter, LUCENE-9507) | low | A failed NRT reader open (DirectoryReader.open(IndexWriter), openIfChanged over the writer, or a SearcherManager/ReaderManager refresh) whose IndexWriterConfig leaf sorter throws never releases the IndexFileDeleter reference it took, so the still-open writer keeps every segment file of that point in time on disk for the rest of its life | 1 |
| LFV-626 | core / index NRT reader open from IndexWriter (StandardDirectoryReader.open(IndexWriter, ...) keep check for fully deleted segments; SoftDeletesRetentionMergePolicy as the stock trigger) | low | If MergePolicy.keepFullyDeletedSegment throws while IndexWriter opens an NRT reader (for example a read error while SoftDeletesRetentionMergePolicy runs its retention query), StandardDirectoryReader.open never releases the SegmentReader it obtained just before the check, so that segment's core and files stay open after IndexWriter.close() | 1 |
| LFV-440 | index / flush-time index sorting (SortingStoredFieldsConsumer, SortingTermVectorsConsumer) | low | With an index sort, a failure while creating the sorted stored-fields or term-vectors writer during flush leaves the reader on the temporary .fdt/.fdx (.tvd/.tvx) files open after IndexWriter closes itself | 1 |
| LFV-486 | misc / BP reordering (BPIndexReorderer forward index; merge-time reordering through BPReorderingMergePolicy) | low | BPIndexReorderer leaks the forward index's term-ids temp input when opening the start-offsets temp file (or building the ForwardIndex) fails, so a failed BP reordering merge leaves an input on a deleted temp file open after IndexWriter and the Directory are closed | 1 |
| LFV-456 | index / IndexWriter commit failure path (prepareCommit, IndexFileDeleter reference counts, merge-on-commit) | low | A commit that fails before startCommit (merge-on-commit setup, doAfterFlush, the merge scheduler or the event listener) keeps references on all of its files, so the still-open writer never deletes them, not even on rollback() or close() | 1 |
| LFV-309 | facet / taxonomy (SearcherTaxonomyManager.refreshIfNeeded and the NRT and Directory constructors: the taxonomy reader taken before an unguarded SearcherManager.getSearcher call) | low | SearcherTaxonomyManager leaks a taxonomy reader (an extra reference on the current one, or a whole newly opened reader with its open files) when the SearcherFactory throws during a refresh, and the NRT and Directory constructors leak theirs when it throws on the first searcher | 2 |
| LFV-357 | util / OfflineSorter concurrent sort (temp-file cleanup on failure) | low | OfflineSorter.sort with an ExecutorService runs its failure cleanup before the partition-sort and merge tasks it already submitted have finished, so each task still queued or running leaves a temp file (prefix_sort_N.tmp) behind that nothing deletes (released since 6.6.0) | 1 |
| LFV-1011 | misc / index tools (IndexRearranger.execute failure path: the await loops of createRearrangedIndex and applyDeletes inside the try-with-resources) | low | A failed IndexRearranger.execute() throws without waiting for its other tasks, and closes the input reader and the IndexWriter while those tasks still use them | 1 |
| LFV-1080 | misc / index tools (IndexRearranger.execute: lifecycle of the method-local executor on the failure path) | low | IndexRearranger.execute() shuts down its own thread pool only when the run succeeds, so a run that fails after starting work leaves non-daemon 'rearranger' worker threads alive forever and keeps the JVM from exiting | 1 |
| LFV-1006 | analysis-common / hunspell Dictionary loading (SortingStrategy.offline, HunspellStemFilterFactory) | low | A hunspell Dictionary load that fails with the offline sorting of the Dictionary(Directory, ...) constructors leaves its temp IndexOutput open (regression since 9.9.0, #12834): through HunspellStemFilterFactory every failed inform() keeps a file descriptor on the deleted temp file until GC, and with a caller-supplied tempDir the temp file also stays behind | 1 |
| LFV-790 | suggest / SortedInputIterator temp-file cleanup (used by WFSTCompletionLookup and TSTLookup) | low | SortedInputIterator leaves its temp input file (and, when reopening the sorted file fails, the sorted file too) in the temp Directory when its constructor fails, so every WFSTCompletionLookup or TSTLookup build that fails while reading or sorting its input leaks a temp file (regression since 6.0.0) | 1 |
| LFV-461 | analysis-opennlp / lemma dictionary loading (OpenNLPOpsFactory.getLemmatizerDictionary) | low | OpenNLPOpsFactory.getLemmatizerDictionary never closes the lemma-dictionary InputStream it opens from the ResourceLoader, so every OpenNLPLemmatizerFilterFactory with a 'dictionary' leaves that file open until garbage collection (regression since 9.1.0: LUCENE-10171 undid the LUCENE-8188 fix) | 1 |
| LFV-624 | misc / index tools (GetTermInfo command-line helper) | low | GetTermInfo.getTermInfo opens a DirectoryReader on the caller's Directory and never closes it, so every call leaks that reader's open index files (file descriptors or memory mappings) | 1 |
| LFV-1010 | analysis / ICU (ICUTokenizerFactory per-script rule files: rulefiles, parseRules) | low | ICUTokenizerFactory leaves a custom per-script rule file (rulefiles) open when reading or decoding it fails: parseRules closes its reader only after a successful read loop, so a rule file that is not valid UTF-8, or an I/O error while reading it, leaves the stream the ResourceLoader opened unclosed until garbage collection (every release since 4.1.0) | 1 |
| LFV-070 | util / FST | low | Util.shortestPaths with topN=0 throws NoSuchElementException | 1 |
| LFV-553 | queries / MoreLikeThis term selection (MoreLikeThis.createQueue bounded priority queue; MoreLikeThisQuery; XML query parser LikeThisQueryBuilder) | low | MoreLikeThis with maxQueryTerms = 0 throws NullPointerException from like(...), retrieveInterestingTerms(...) and the rewrite of MoreLikeThisQuery or the XML parser's LikeThisQuery, instead of returning a query with no terms (regression since 4.10.0) | 2 |
| LFV-799 | facet / range-on-range facet counts (LongRangeOnRangeFacetCounts and DoubleRangeOnRangeFacetCounts constructors: getEncodedRanges reads ranges[0]) | low | LongRangeOnRangeFacetCounts and DoubleRangeOnRangeFacetCounts throw an internal ArrayIndexOutOfBoundsException from every public constructor when given no ranges, instead of returning an empty result like the classic range facet counters or rejecting the empty list with an IllegalArgumentException | 1 |
| LFV-462 | queries / intervals (MultiTermIntervalsSource behind Intervals.prefix, wildcard, regexp, range, fuzzyTerm and multiterm; Weight#matches / IntervalsSource#matches) | low | MultiTermIntervalsSource.matches() checks the expansion limit with a post-increment ('count++ > maxExpansions'), so Weight#matches, and highlighting through it, accepts a document with exactly maxExpansions + 1 matching terms, where the javadoc and the search path (which uses '++count') reject it (IllegalStateException; IndexSearcher.TooManyClauses on main since #16899) | 1 |
| LFV-519 | suggest / spell (WordBreakSpellChecker word combinations) | low | WordBreakSpellChecker.suggestWordCombinations does not honour maxEvaluations: the counter is compared with == and the break leaves only the inner loop, so every later left term is still evaluated and a limit of 0 or less is ignored (the #12077 fix in 9.5.0 covered only suggestWordBreaks) | 1 |
| LFV-743 | core / index (ParallelLeafReader and ParallelCompositeReader stored fields, StoredFieldVisitor protocol) | low | ParallelLeafReader stored fields ignore StoredFieldVisitor.Status.STOP: the later parallel readers still offer and deliver fields after the visitor answered STOP | 1 |
| LFV-733 | queries / spans: SpanMultiTermQueryWrapper top-N rewrite methods vs the core IndexSearcher clause limit | low | SpanMultiTermQueryWrapper's top-N span rewrites (TopTermsSpanBooleanQueryRewrite, FrequentTermsSpanBooleanQueryRewrite) do not cap their size at IndexSearcher#getMaxClauseCount, so a span-wrapped FuzzyQuery that works unwrapped throws TooManyNestedClauses | 1 |
| LFV-944 | queries / spans (SpanMultiTermQueryWrapper.FrequentTermsSpanBooleanQueryRewrite queue sizing; core ScoringRewrite creates the top-level builder before collecting terms; util PriorityQueue pre-allocates maxSize + 1 slots) | low | SpanMultiTermQueryWrapper.FrequentTermsSpanBooleanQueryRewrite (new in 10.6.0) sizes its priority queue from maxSize before collecting any term, so maxSize >= 2147483631 (for example Integer.MAX_VALUE as 'no limit') makes every rewrite throw IllegalArgumentException, and a large maxSize allocates a (maxSize + 1)-slot array on every rewrite | 1 |
| LFV-993 | core / search: field-sorted top-N collection (FieldValueHitQueue, TopFieldCollectorManager) | low | On main, a field-sorted TopFieldCollectorManager with numHits >= ArrayUtil.MAX_ARRAY_LENGTH (e.g. Integer.MAX_VALUE) throws OutOfMemoryError instead of the IllegalArgumentException that 10.x throws, because since #14873 FieldValueHitQueue.create allocates the numHits-sized sort comparators before the PriorityQueue size check runs (unreleased regression of the SOLR-5661 guard) | 1 |
| LFV-392 | util / BytesRefArray (iterator(Comparator) with a null comparator) | low | BytesRefArray.iterator(Comparator) throws NullPointerException for a null comparator once the array holds 2 or more values, instead of iterating in append order as its javadoc says (regression since 8.5.0, LUCENE-9228) | 1 |
| LFV-219 | geo / XY shapes (XYPolygon winding order, Tessellator.tessellate(XYPolygon), XYShape.createIndexableFields and createDocValueField) | low | XYPolygon evaluates its winding sum in float, so valid polygons with large finite coordinates (differences of about 1.8e19 or more) can get the wrong winding order, and XYShape rejects them as 'Unable to Tessellate shape' | 1 |
| LFV-771 | core / geo (Rectangle.fromPointDistance circle bounding box, used by LatLon distance and Circle queries) | low | Rectangle.fromPointDistance throws 'invalid longitude NaN' for some legal circles whose edge stops just short of a pole, so LatLon distance queries on them fail with IllegalArgumentException | 1 |
| LFV-742 | spatial3d / geom path distances (GeoStandardPath and GeoDegeneratePath PathSegment foot selection; Geo3DDocValuesField.newPathSort) | low | geo3d path distance methods (GeoStandardPath, GeoDegeneratePath) and Geo3DDocValuesField.newPathSort throw RuntimeException "Can't find world intersection" for a point inside the path that sits at the edge of the 1e-12 tolerance band of a segment's cutoff plane | 1 |
| LFV-080 | memory / MemoryIndex | low | MemoryIndex reports the total number of point dimensions as the number of index dimensions | 1 |
| LFV-136 | index / MultiDocValues merged numeric, binary and norms doc-values views (also the merged reader passed to MergePolicy.OneMerge#reorder) | low | MultiDocValues numeric, binary and norms views throw NullPointerException from advance() after advanceExact() landed on a segment without the field | 1 |
| LFV-055 | util / automaton | low | AutomatonTermsEnum throws ArrayIndexOutOfBoundsException for an NFA with a reachable dead state | 1 |
| LFV-029 | util / automaton | low | RunAutomaton throws ArrayIndexOutOfBoundsException on a 0-state automaton | 1 |
| LFV-865 | core / analysis: AutomatonToTokenStream (automaton to token-graph conversion) | low | AutomatonToTokenStream.toTokenStream throws ArrayIndexOutOfBoundsException ('Index 0 out of bounds for length 0') on a 0-state automaton, Lucene's standard empty-language value (Automata.makeEmpty(), or an empty Operations result such as intersection("a", "b")) | 1 |
| LFV-021 | util / automaton | low | FiniteStringsIterator returns the empty string twice | 1 |
| LFV-067 | util / FST | low | FSTCompiler throws ArrayIndexOutOfBoundsException on BYTE4 nodes whose labels span 2^31-8 or more | 1 |
| LFV-031 | store / ByteBuffersDataInput | low | ByteBuffersDataInput.readLongs and readFloats fail when blocks are smaller than 8 bytes | 1 |
| LFV-476 | store / ByteBuffersDataInput sequential reads (ByteBuffersDirectory, ByteBuffersIndexInput, NRTCachingDirectory RAM tier) | low | ByteBuffersDataInput readShort/readInt/readLong throw IndexOutOfBoundsException instead of EOFException on a read past the end of input longer than one block (ByteBuffersDirectory files over 1 KiB) | 2 |
| LFV-130 | store / MMapDirectory (MemorySegmentIndexInput sequential reads and seek) | low | After a read hits EOF on a multi-chunk MMapDirectory input, seek() past EOF succeeds and later reads return bytes from the wrong offset | 1 |
| LFV-129 | store / MMapDirectory read advice (PosixNativeAccess madvise, MemorySegmentIndexInput slices of closed inputs) | low | Slicing an MMapDirectory clone with read advice after its original is closed throws AssertionError instead of AlreadyClosedException (PosixNativeAccess.madvise wraps the closed-arena IllegalStateException in an Error) | 1 |
| LFV-135 | store / MMapDirectory (MemorySegmentIndexInput absolute reads, error reporting) | low | MemorySegmentIndexInput.readBytes(long, ...) past EOF on a multi-chunk MMapDirectory input reports a masked position: IllegalArgumentException 'read negative position' for a non-negative argument, or EOFException naming the wrong position | 1 |
| LFV-480 | store / BufferedIndexInput.SlicedIndexInput (BufferedIndexInput.wrap and the default slice()) | low | Inputs from BufferedIndexInput.wrap and the default BufferedIndexInput.slice accept seek and skipBytes past the end instead of throwing EOFException | 1 |
| LFV-060 | search / scoring | low | MaxScoreBulkScorer can skip a document whose score equals the minimum competitive score (1-ulp rank inversion) | 1 |
| LFV-079 | codecs / vectors | low | Quantized MIP score of a document equal to its segment centroid is 3.0 instead of 3.5 | 1 |
| LFV-095 | index / IndexWriter doc-values updates | low | IndexWriter accepts doc-values updates of the reserved parent field; with index sorting and document blocks this leaves a segment that fails CheckIndex, or an index whose merges fail | 1 |
| LFV-108 | index / merge setup (MergeState merge instances, KnnVectorsReader finishMerge lifecycle) | low | If merge setup throws, the vectors merge instances obtained so far never get finishMerge (MergeState constructor and PerFieldKnnVectorsFormat merge copy constructor) | 2 |
| LFV-575 | index / IndexWriter point-in-time merges (merge-on-commit, merge-on-getReader: the preparePointInTimeMerge OneMerge wrapper and the OneMerge lifecycle hooks) | low | IndexWriter's merge-on-commit / merge-on-getReader wrapper forwards mergeFinished to the merge policy's OneMerge but never calls its mergeInit, so a merge that ran and committed reaches the policy's OneMerge as mergeFinished(success=true) with no mergeInit before it (since 8.6.0) | 1 |
| LFV-090 | memory / MemoryIndex vectors | low | MemoryIndex.addField throws AssertionError under -ea for a KnnFloat16VectorField, because a stale assertion in storeVectorValues predates the FLOAT16 branch | 1 |
| LFV-092 | queries / function vector sources | low | ConstKnnFloat16ValueSource accepts Inf/NaN float16 query vectors that its float32 twin ConstKnnFloatValueSource rejects (missing VectorUtil.checkFiniteFloat16) | 1 |
| LFV-084 | codecs / vectors | low | FLOAT16 vectors read back from a quantized index whose raw vectors were dropped can contain +-Infinity, so full-precision rescoring ranks an exact match last | 1 |
| LFV-085 | codecs / vectors | low | With raw vectors dropped from a Lucene104 scalar-quantized field, rescorer().bulk() reads quantized bytes as float32 vectors and returns wrong scores | 2 |
| LFV-065 | codecs / vectors | low | PACKED_NIBBLE quantized vectors with an odd dimension fail once raw vectors are dropped | 1 |
| LFV-112 | index / SortingCodecReader re-sort (index sorting with document blocks) | low | With assertions enabled, re-sorting an index with document blocks through SortingCodecReader and addIndexes fails SortingCodecReader's cache assertion for the parent field | 1 |
| LFV-821 | suggest / document (NRT) suggester (ContextQuery: ContextCompletionWeight.setInnerWeight when the inner automaton accepts the empty string) | low | ContextQuery throws AssertionError 'input should not end with the context separator' (only with -ea) when its inner RegexCompletionQuery or FuzzyCompletionQuery accepts the empty string ('.*', 'z*', 'b?', or a fuzzy prefix within the edit budget), also through the automatic rewrite of a plain completion query on a ContextSuggestField: an incomplete fix of LUCENE-8287 (released since 5.3.0) | 1 |
| LFV-697 | misc / document: LazyDocument (lazy loading of stored fields, multi-valued fields) | low | LazyDocument.fetchRealValues checks its value-count assertion in the wrong direction: with assertions enabled, reading a lazy value of a multi-valued field before that field's last getField call throws AssertionError ('More lazy values then real values'), while the over-request case the message names is not caught and fails with ArrayIndexOutOfBoundsException | 1 |
| LFV-761 | util / BKD points (BKDReader.BKDPointTree navigation: visitDocIDs/visitDocValues on a leaf reset the inner-node input; default points format) | low | Default points format: after a PointTree visits a leaf and moves back to its parent, the next visitDocIDs, visitDocValues or moveToChild there fails an assertion in BKDReader (only with -ea; results are correct with -da) | 1 |
| LFV-713 | analysis / hunspell (Hunspell.spell and suggest compound checking, CHECKCOMPOUNDPATTERN replacements) | low | Hunspell spell() and suggest() throw AssertionError under -ea when a word ends with a CHECKCOMPOUNDPATTERN replacement whose beginchars are empty, because the compound check looks up a zero-length second part | 1 |
| LFV-421 | misc / BP merge-time reordering (BpVectorReorderer centroid arithmetic) | low | BpVectorReorderer scales a zero DOT_PRODUCT/COSINE centroid by 1/sqrt(0), so a split whose vectors cancel out gets a NaN centroid: with assertions on, reordering fails and a reordering merge closes the IndexWriter; with assertions off, that split is silently not refined | 1 |
| LFV-267 | search / TopDocs.merge tie breaking (score and Sort merges with a custom tie breaker) | low | TopDocs.merge with a custom tie breaker fails an assertion (only with -ea) when the tie breaker returns 0 for tied hits from two different shards at the same rank | 1 |
| LFV-057 | util / automaton | low | UTF32ToUTF8 still accepts overlong UTF-8 for ranges that span into 3- and 4-byte code points | 1 |
| LFV-058 | util / bitsets | low | SparseFixedBitSet.nextClearBit returns NO_MORE_DOCS in the last 4096-bit block | 1 |
| LFV-066 | util / bitsets | low | RoaringDocIdSet.Builder.add(min, max) throws on the last 2^16-doc block | 1 |
| LFV-069 | util / heaps | low | LongHeap and TernaryLongHeap stop growing at 715,827,883 elements despite 'grows unbounded' | 1 |
| LFV-294 | util / PriorityQueue (sift-down; base class of HitQueue and FieldValueHitQueue) | low | PriorityQueue.downHeap computes the child index i << 1 in int, so a queue holding 2^30 or more elements can throw ArrayIndexOutOfBoundsException (when a sift-down reaches node 2^30) from updateTop, pop or insertWithOverflow and is left with one element lost and another duplicated | 2 |
| LFV-043 | util / sorters | low | TimSorter overflows its 49-entry run stack on legal inputs of about 1.1 billion elements | 1 |
| LFV-133 | util / FixedBitSet (approximateCardinality) | low | (Latent) FixedBitSet.approximateCardinality returns a negative value for bit sets of 2^31-63 bits or more, because its scale factor 64 * numWords overflows int | 1 |
| LFV-323 | util / RamUsageEstimator | low | RamUsageEstimator.sizeOfCollection adds the assumed backing-array bytes in int arithmetic, so a collection of 536,870,908 or more elements (268,435,453 with 8-byte references) gets a size estimate that is a multiple of 4 GiB too low, and negative when the elements add little | 1 |
| LFV-148 | util / packed ints (MonotonicBlockPackedWriter, MonotonicBlockPackedReader) | low | (Latent) MonotonicBlockPackedWriter writes a block whose values end close to Long.MAX_VALUE with too few bits, so MonotonicBlockPackedReader returns wrong values: min + (long) (avg * i) overflows in flush() | 1 |
| LFV-449 | index / sorted-set doc values terms enum (SortedSetDocValuesTermsEnum, the default SortedSetDocValues#termsEnum()) | low | The default SortedSetDocValues terms enum casts the ordinal to int in seekExact(long) and seekExact(term, TermState): on a view with more than 2^31 values a seek by ordinal throws, and from 2^32 values on it can silently land on the wrong term | 1 |
| LFV-298 | codecs / BufferingKnnVectorsWriter flush-time vector values (KnnVectorValues.ordToDoc and getAcceptOrds) | low | BufferingKnnVectorsWriter hands writeField vector values whose ordToDoc(ord) returns ord, which is wrong for sparse fields and, with an index sort, for every field (latent: no shipped writer calls it) | 1 |
| LFV-159 | util / HNSW graph node iterators (HnswGraph.NodesIterator, DenseNodesIterator) | low | HnswGraph.DenseNodesIterator.consume() (the level-0 node iterator of every HNSW graph) does not advance its cursor, so draining level 0 in chunks with consume() returns the first chunk forever and a nextInt() after consume() starts again at node 0 (latent: Lucene itself never calls consume() on level 0) | 1 |
| LFV-165 | index / doc values and norms flush with index sorting (NumericDocValuesWriter.SortingNumericDocValues) | low | With an index sort, the flush-time iterator that IndexWriter hands to a doc-values or norms consumer for a numeric field that every document has ends intoBitSet(upTo >= maxDoc) on docID() == maxDoc instead of NO_MORE_DOCS, so a custom consumer that bulk-loads it and loops until NO_MORE_DOCS never finishes (latent: Lucene's own consumers skip the bulk load for such fields) | 1 |
| LFV-418 | index / doc values flush (DocValuesWriter Buffered*DocValues iterators handed to DocValuesConsumer) | low | The flush-time doc-values iterators that IndexWriter hands to a DocValuesConsumer move only their doc-ID cursor in intoBitSet(), so values read afterwards belong to earlier documents (NUMERIC, BINARY, SORTED, SORTED_NUMERIC, SORTED_SET; latent: Lucene's own consumers never read values after intoBitSet on the same iterator) | 1 |
| LFV-753 | codecs / SimpleText points format (SimpleTextBKDReader.SimpleTextPointTree#clone) | low | SimpleText points: PointTree.clone() shares a saved split-value array with the tree it was cloned from, so moving one tree corrupts the node bounds the other reports | 1 |
| LFV-071 | codecs / vectors | low | Panama minMaxScalarQuantize rounds differently from the default implementation at one boundary value | 1 |
| LFV-063 | search / similarities | low | AxiomaticF2LOG and AxiomaticF2EXP scores drop by 1 ulp as term frequency crosses a power of two | 1 |
| LFV-072 | search / similarities | low | IBSimilarity with DistributionLL returns -0.0f scores | 1 |
| LFV-162 | codecs / block-tree terms dictionary (Lucene103 Stats, CheckIndex verbose statistics) | low | Lucene103 block tree never sets Stats.indexNumBytes, so Terms.getStats() and CheckIndex -verbose print 'index trie: 0 bytes' for every field | 1 |
| LFV-062 | util / automaton | low | Operations.topoSortStates misses self-loop cycles and returns an order instead of throwing | 1 |
| LFV-868 | core / analysis: AutomatonToTokenStream (automaton to token-graph conversion) | low | AutomatonToTokenStream.toTokenStream silently requires every state to be reachable from state 0, which its javadoc does not say, and rejects an acyclic automaton with an unreachable state with a false 'Cycle found in automaton' / 'Start node has incoming edges, creating cycle' message (documentation and error-message defect; the restriction itself was stated at design time) | 1 |
| LFV-025 | util / bitsets | low | FixedBitSet and LongBitSet equals depend on the backing array capacity, not only on the bits | 1 |
| LFV-039 | analysis, util and document / equals methods | low | equals(null) throws in KeywordAttributeImpl and MutableValue, and DecodedTriangle.equals throws ClassCastException | 1 |
| LFV-042 | util / UnicodeUtil | low | UnicodeUtil.UTF8toUTF32 throws ArrayIndexOutOfBoundsException instead of IllegalArgumentException for lead bytes 0xF8-0xFF | 1 |
| LFV-389 | test infrastructure / JUnit 4 test discovery (core, core.tests, monitor, distribution.tests, analysis-common hunspell) | low | Test suite on main: #16028 removed @Test from six test classes that do not extend LuceneTestCase, so their 18 test methods never run (TestRuntimeDependenciesSane and TestCandidateMatcherVisibility report no tests; TestClassloadingDeadlock, TestModularLayer and TestScripts each report one green placeholder; the opt-in TestHunspellRepositoryTestCases fails with 'No runnable methods') | 1 |
| LFV-1013 | tests / test-method discovery (core geo TestXYRectangle, core automaton TestOperations, analysis-common TestCommonGramsFilter) | low | Four Lucene test methods never run because their names do not start with lowercase 'test' (TestXYRectangle.tesInvalidMinMaxX/Y, TestOperations.TestOptionalOptionalAcceptsState0, TestCommonGramsFilter.TestFirstAndLastStopWord); the two TestXYRectangle ones would also fail if run, because they look for '5 > 4' while XYRectangle reports '5.0 > 4.0', so XYRectangle's reversed-bounds check has had no running test since 2020 | 1 |
| LFV-576 | test-framework / merge policies (ForceMergePolicy; FilterMergePolicy forwarding of MergePolicy.findFullFlushMerges for merge-on-commit and merge-on-getReader) | low | Test-framework ForceMergePolicy, documented as 'only returns forced merges', still lets the wrapped policy's natural merges run on commit() and NRT reopen, because it inherits FilterMergePolicy's forwarding of findFullFlushMerges (regression since 9.3.0) | 1 |
| LFV-664 | test-framework / search: AssertingLeafCollector DocIdStream wrapper (AssertingIndexSearcher, bulk collection) | low | Test framework: AssertingLeafCollector's DocIdStream wrapper ignores upTo in forEach(int upTo, IOIntConsumer) and passes every remaining doc to the consumer, so a collector that reads a stream in bounded steps under AssertingIndexSearcher (the default of LuceneTestCase.newSearcher) gets wrong per-step results with -da and a spurious 'exhausted' AssertionError on its next legal call with -ea | 1 |
| LFV-073 | test-framework / similarities | low | BaseSimilarityTestCase's 'scores don't decrease as terms get rarer' check is dead code | 1 |
| LFV-102 | test-framework / search checkers (CheckHits) | low | CheckHits.checkTopScores (test framework) fails on correct minimum-should-match disjunctions because it walks the COMPLETE and TOP_SCORES two-phase approximations in lockstep | 1 |
| LFV-033 | test-framework / postings formats | low | Test-framework RAMOnlyPostingsFormat cannot index DOCS-only fields | 1 |
| LFV-823 | index / IndexWriter delete-by-query (deleteDocuments(Query...) and updateDocuments(Query, ...) javadoc and class NOTE vs deferred application in FrozenBufferedUpdates and the applyUpdatesPacket tragic close) | low | IndexWriter.deleteDocuments(Query...) and updateDocuments(Query, ...) do not document that the query runs only when the buffered delete is applied later, or that an exception it throws then (for example a PhraseQuery or FieldExistsQuery on a StringField, or TooManyClauses from an interval prefix once more than 128 terms match) closes the IndexWriter and discards every change since the last commit (documentation defect; the close itself is an intended fail-safe) | 2 |
| LFV-847 | queryparser / classic and flexible standard grammars (_WHITESPACE, _TERM_START_CHAR) and the query syntax documentation | low | Classic QueryParser and flexible StandardQueryParser: the query syntax docs never say that only space, TAB, LF, CR and U+3000 separate clauses, so AND, OR or '-' written next to any other Unicode space (EN, EM or THIN space, U+205F, NBSP, ...) silently becomes part of a search term and a field prefix spreads to the following words: 'title:foo<EM SPACE>AND<EM SPACE>-bar' parses as 'title:foo title:and title:bar' | 1 |
| LFV-514 | analysis / phonetic (PhoneticFilter and DaitchMokotoffSoundexFilter output from the bundled commons-codec); release notes (lucene/CHANGES.txt, lucene/MIGRATE.md) | low | Bundled commons-codec upgrades changed phonetic filter tokens (RefinedSoundex in 10.2.0; Metaphone, ColognePhonetic and Daitch-Mokotoff on main), and neither CHANGES.txt nor MIGRATE.md mentions it or asks for re-indexing (documentation defect) | 1 |
| LFV-870 | analysis-common / synonym.word2vec (Word2VecSynonymFilter minAcceptedSimilarity javadoc vs Word2VecSynonymProvider threshold test) | low | Word2VecSynonymFilter documents minAcceptedSimilarity as a cosine similarity, but Word2VecSynonymProvider compares it with the normalised score (1 + cosine) / 2, so the effective cosine cutoff is 2m - 1 (the default 0.8 accepts cosine 0.6, 0.5 accepts orthogonal terms, values below 0.5 accept negatively correlated terms); documentation defect, the javadoc fix is the default proposal | 1 |
| LFV-351 | facet / facet sets (MatchingFacetSetsCounts child counts vs. FacetSets.adoc and the demo javadoc) | low | FacetSets.adoc says MatchingFacetSetsCounts counts the documents each FacetSetMatcher matches, but it counts matching facet sets, so one document can add more than 1 to a matcher (documentation defect; the per-set code is intended and pinned by upstream tests) | 1 |
| LFV-830 | queries / intervals (Intervals.within / Intervals.notWithin and their javadoc; queryparser fn:within / fn:notWithin docs) | low | Intervals.within and notWithin are documented as opposites, but a multi-position source interval only partly inside the n-position window around the reference matches neither (documentation / API-contract defect) | 1 |
| LFV-903 | core / search similarities (MultiSimilarity: undocumented norm ownership, inherited getDiscountOverlaps) | low | MultiSimilarity does not document that only sims[0] computes the field norm, so the other sub-similarities' index-time norm settings (discountOverlaps, a computeNorm override) are silently ignored and the array order decides the stored norm, and its inherited getDiscountOverlaps() always returns true (documentation defect; on one index the score is an exact sum in either order) | 1 |
| LFV-812 | index / IndexWriter delete APIs (deleteAll and deleteDocuments(Query...) javadoc) | low | IndexWriter.deleteAll() javadoc says deleteDocuments(MatchAllDocsQuery) is slower and only marks documents deleted, but since 5.2.0 (LUCENE-6379) deleteDocuments(Query...) runs an exact MatchAllDocsQuery as deleteAll(), which also resets the field schema (javadoc only; the routing is intended) | 2 |
| LFV-529 | facet / taxonomy (TaxonomyFacetLabels, per-document facet label retrieval) | low | TaxonomyFacetLabels javadoc offers it as a replacement for stored fields, but for dimensions configured multi-valued plus hierarchical (or multi-valued plus requireDimCount) it also returns the ancestor paths and the bare dimension that FacetsConfig indexes only for counting (documentation/contract defect; every release since 8.7.0) | 1 |
| LFV-536 | analysis-common / ConcatenateGraphFilter and ConcatenateGraphFilterFactory (maxGraphExpansions javadoc); also suggest / CompletionAnalyzer | low | ConcatenateGraphFilter, its factory and CompletionAnalyzer misdocument maxGraphExpansions: the javadoc promises a TooComplexToDeterminizeException when the token graph has more than maxGraphExpansions paths (and 'no limit on graph expansions' for CompletionAnalyzer's 1- and 3-argument constructors), but the code silently keeps the first maxGraphExpansions paths (default 10000) and also uses the same value as the determinize work limit, so it can throw for a graph with fewer paths than the limit (documentation defect; the truncation is intended) | 1 |
| LFV-961 | grouping / package documentation (package-info.java inputs list vs the collector managers it names) | low | The grouping package documentation says groupOffset 3 with topNGroups 10 returns 7 groups, but FirstPassGroupingCollectorManager and BlockGroupingCollectorManager, which the page names and shows since #16385 (10.6.0), return 10: for them topNGroups is the page size after the offset (documentation defect; the inputs list has also disagreed with the page's own example code since 3.2) | 1 |
| LFV-885 | core / index merge scheduling (MultiIndexMergeScheduler visibility) | low | MultiIndexMergeScheduler is listed under Lucene 10.3.0 New Features as 'a production multi-tenant merge scheduler' and its javadoc says to create one instance per index, but the class is package-private, so application code cannot compile against it or construct it through supported means | 1 |
| LFV-989 | core / analysis (org.apache.lucene.analysis package overview, package-info.java: the TokenStream API tutorial) | low | The org.apache.lucene.analysis package overview (the TokenStream API tutorial) has seven code examples that do not compile on any release since 6.0: they call StandardAnalyzer(Version), WhitespaceTokenizer(Version) and FilteringTokenFilter(Version, TokenStream), removed in 5.0, and LengthFilter(boolean, TokenStream, int, int), gone since 4.4, subclass the final StandardAnalyzer, and define a custom AttributeImpl without reflectWith, abstract since 6.0 (documentation defect) | 1 |
| LFV-1018 | core / search (LeafCollector class javadoc example) | low | LeafCollector's class javadoc example ('collect docIDs into a BitSet') does not compile on any release since 5.1.0: its anonymous Collector has no scoreMode() (the abstract needsScores() before 8.0.0) and its setScorer(Scorer) does not implement LeafCollector.setScorer(Scorable) (documentation defect) | 1 |
| LFV-980 | core / search (TermInSetQuery class javadoc example) | low | TermInSetQuery's class javadoc example does not compile: it calls the varargs constructor TermInSetQuery(String, BytesRef...), removed in 10.0 (#12837), and new BooleanQuery() / bq.add(...), removed in 6.0 (LUCENE-6570); the equal-scores claim it illustrates still holds (documentation defect) | 1 |
| LFV-992 | analysis-icu / module overview documentation (overview.html 'Example Usages') | low | analysis-icu overview page: the ICUTokenizer example and the three collation examples (Farsi range, Danish sort, Turkish case) call APIs removed between Lucene 4.0 and 10.0, and on main the Serbian transliteration example is not valid Java (documentation defect) | 1 |
| LFV-1041 | analysis-common / compound (package overview examples and output table, package-info.java) | low | The org.apache.lucene.analysis.compound package overview's three code examples do not compile on any release since 4.0.0: they call HyphenationCompoundWordTokenFilter.getHyphenationTree(Reader), WhitespaceTokenizer(Reader) and the String[] dictionary constructors of both decompounding filters, all removed; their loop never calls reset(), and the page's output table shows per-part offsets that the filters stopped emitting in 4.4.0 (documentation defect) | 1 |
| LFV-1027 | core / util/fst (package overview examples, package-info.java) | low | The org.apache.lucene.util.fst package overview's code examples do not compile on any release since 9.0.0: they call Util.getByOutput (removed in 9.0.0), the public FSTCompiler(INPUT_TYPE, Outputs) constructor (removed in 9.9.0) and the Util.Result fields input/output (private record components since 10.0.0) (documentation defect) | 1 |
| LFV-1085 | analysis-common / collation package documentation (package-info.java 'Example Usages') | low | The collation package overview's Danish Sorting example calls Sort.setSort, which was removed in 9.0.0, so the example does not compile; on main it is the one error left on the page after #16904 updated its examples (documentation defect) | 1 |
| LFV-702 | analysis-nori / KoreanPartOfSpeechStopFilterFactory (javadoc example of the stop tags) | low | KoreanPartOfSpeechStopFilterFactory's class javadoc example tags="E,J" fails with IllegalArgumentException ('No enum constant org.apache.lucene.analysis.ko.POS.Tag.E') since 10.0.0: GITHUB#11778 replaced the POS tags E and J with fine-grained tags and updated the factory test, but not the javadoc example, and no CHANGES or MIGRATE note survives (documentation defect; the tag change is intended) | 1 |
| LFV-930 | analysis-common / SimplePattern(Split)TokenizerFactory javadoc examples; core / util.automaton RegExp error message | low | SimplePatternSplitTokenizerFactory and SimplePatternTokenizerFactory javadoc whitespace examples (pattern="[ \t\r\n]+" and "[^ \t\r\n]+" in an XML attribute, so the backslashes stay literal) never split on whitespace: since 9.0.0 RegExp rejects them with IllegalArgumentException (the rejection is intended, LUCENE-9370), on 6.5 to 8.x they split on the letters t, r, n; the RegExp error also prints the rejected letter as a decimal code point ('invalid character class \116' for \t) | 1 |
| LFV-987 | analysis / stemming filters (PorterStemFilter and StempelFilter class javadoc) | low | PorterStemFilter's and StempelFilter's class javadocs still tell readers to use LowerCaseTokenizer, which was removed in 8.0.0 (LUCENE-8498), and PorterStemFilter's MyAnalyzer example calls new LowerCaseTokenizer(version, reader), a constructor form gone since 5.0.0, so the example does not compile; the documented replacement is LetterTokenizer followed by LowerCaseFilter (documentation defect) | 1 |
| LFV-1026 | core / search (BulkScorer#score javadoc example) | low | BulkScorer#score's javadoc example ('a Scorer-based implementation could look like below') calls scorer.advance(min) and scorer.nextDoc(), which Scorer has not had since LUCENE-6919 made it expose iterator() instead of extending DocIdSetIterator, so the example does not compile on any release since 5.5.0 (documentation defect) | 1 |
| LFV-1032 | memory / MemoryIndex (class javadoc example) | low | MemoryIndex's class javadoc example calls new SimpleAnalyzer(version) and new QueryParser(version, "content", analyzer), constructors removed in 5.0.0 (LUCENE-5859), so the example does not compile on any release since 5.0.0 (documentation defect) | 1 |
| LFV-1028 | queryparser / flexible StandardQueryParser (class and constructor javadoc examples) | low | StandardQueryParser's two javadoc code examples, the class's 'Typical usage, including configuration tweaks' and the StandardQueryParser(Analyzer) constructor's 'The same as:', have never compiled: they call setAllowLeadingWildcard and setAnalyzer on getQueryConfigHandler(), which returns a QueryConfigHandler that has no such setters (they are methods of StandardQueryParser itself), and the class example also assigns that QueryConfigHandler to a StandardQueryConfigHandler variable (documentation defect; every release since 2.9.0) | 1 |
| LFV-1031 | queries / spans (package javadoc example) | low | The spans package javadoc's example for combining a span query with other queries (restrict it to documents that also contain "iraq") calls new BooleanQuery(), Query.add(q, true, false) and new TermQuery(String, String), none of which exists, so it has not compiled in any release (documentation defect) | 1 |
| LFV-1020 | core / index merge policy (TemporalMergePolicy class javadoc example) | low | TemporalMergePolicy's class javadoc 'Configuration:' example calls .setBaseTimeSeconds(3600), a method that does not exist: the setter was renamed to setBaseTimeInSeconds(long) during review of #15620 and the example kept the old name, so it has not compiled on any release (documentation defect) | 1 |
| LFV-1019 | core / geo (Circle class javadoc example) | low | geo.Circle's class javadoc 'Example usage' calls LatLonShape.newDistanceQuery("location", circle), but the only overload is newDistanceQuery(String, QueryRelation, Circle...), so the example has not compiled on any release since #14534 added it in 10.3.0 (documentation defect) | 1 |
| LFV-1029 | suggest / document suggesters (ContextSuggestField class javadoc example) | low | ContextSuggestField's class javadoc example calls new ContextSuggestField(name, "suggestion", Arrays.asList("context1", "context2"), 4), but the only constructor is (String name, String value, int weight, CharSequence... contexts), so the example has not compiled on any release since the class was added in 5.3.0 (documentation defect) | 1 |
| LFV-984 | misc / index reordering (BPIndexReorderer class javadoc example) | low | BPIndexReorderer's class javadoc 'Typical usage' example calls reorderer.setForkJoinPool(pool), removed in 10.0.0, and the 2-argument reorder(reader, targetDir), removed in 9.12.0, so it names APIs that no longer exist; #13289 moved the class to an Executor argument, reorder(CodecReader, Directory, Executor), and left the example unchanged (documentation defect) | 1 |
| LFV-1034 | monitor / ConcurrentQueryLoader (class javadoc example) | low | ConcurrentQueryLoader's class javadoc example declares List<QueryError> and calls new ConcurrentQueryLoader(monitor, errors), but no QueryError type and no (Monitor, List) constructor has ever existed in Lucene, so the example has not compiled on any release since the monitor module was added in 8.2.0 (documentation defect) | 1 |
| LFV-1040 | benchmark / search-quality package (quality/package-info.java: the package overview's TREC sample) | low | The benchmark quality package overview's TREC sample calls qrun.execute(maxResults, judge, submitLog, logger), a 4-argument QualityBenchmark.execute that no release has ever had (maxResults moved to setMaxResults(int) in LUCENE-1116, before 2.3.0, the package's first release), so the sample has not compiled in any release (documentation defect) | 1 |
| LFV-1021 | core / index (UpgradeIndexMergePolicy class javadoc example) | low | UpgradeIndexMergePolicy's class javadoc example calls new IndexWriterConfig(Version.LUCENE_XX, new KeywordAnalyzer()), a constructor removed in 5.0.0 (LUCENE-5871), so the example does not compile with any version constant (documentation defect) | 1 |
| LFV-1033 | facet / taxonomy merge (OrdinalMappingLeafReader class javadoc example) | low | OrdinalMappingLeafReader's class javadoc example for re-mapping facet ordinals during an index merge does not compile on any release since 5.0.0: it uses IndexWriterConfig(Version, Analyzer) and addIndexes(IndexReader...), both removed in 5.0.0, a 2-argument constructor the class never had, and a static-style call to the instance method addTaxonomy (documentation defect) | 1 |
| LFV-988 | core / util/fst (FSTCompiler.compile() javadoc example) | low | FSTCompiler.compile()'s javadoc shows how to read back an FST written to a non-FSTReader DataOutput with 'fst = new FST<>(fstMetadata, dataInput, new OffHeapFSTStore())', but #13524 removed both the no-argument OffHeapFSTStore constructor and the 3-argument FST constructor in 9.12.0, so the example names APIs that no longer exist (documentation defect) | 1 |
| LFV-797 | facet / taxonomy (DirectoryTaxonomyReader.getBulkPath: side effect on the ordinals argument of the category-cache path added by #15711) | low | DirectoryTaxonomyReader.getBulkPath overwrites and duplicates entries of its ordinals argument when a cached ordinal comes before an uncached one (since 10.5.0), although the TaxonomyReader javadoc says the method may only reorder them (documentation/contract defect; the returned labels are correct) | 1 |
| LFV-907 | search / CachingCollectorManager lifecycle (documentation; new public API in 10.6.0) | low | CachingCollectorManager (new in 10.6.0) does not document that it is single-use: reused for a second search, replay() replays the hits of both searches and one earlier overflow keeps isCached() false | 1 |
| LFV-959 | release notes (lucene/CHANGES.txt 11.0.0, lucene/MIGRATE.md 10.x -> 11.0) x index / doc-values updates (IndexWriterConfig#DEFAULT_MAX_DOC_VALUES_OVERLAYS, GITHUB#16418, GITHUB#16648) | low | Main (the future 11.0) turns incremental doc-values updates on by default (IndexWriterConfig.DEFAULT_MAX_DOC_VALUES_OVERLAYS = 8; opt-in, 0, in 10.6), but neither the 11.0.0 section of CHANGES.txt nor MIGRATE.md records the change: the only note is the 10.6.0 'Opt-in' entry, because main's 'Enabled by default' note was moved to 10.6.0 and then reworded (documentation defect, unreleased) | 1 |
| LFV-1030 | index / forceMerge and index upgrade (lucene/MIGRATE.md 11.0 'Relaxed Index Upgrade Policy': Scenario 1 and 'Upgrade Example') | low | MIGRATE.md's 11.0 'Upgrade Example' says forceMerge(1) 'Rewrites all segments to latest format', but with the default merge policy it leaves an index that already has one segment and no deletions unchanged in its 9.x or 10.x format (documentation defect, unreleased; the code is correct) | 1 |
| LFV-945 | search / query cache (LRUQueryCache method javadocs and MIGRATE.md) | low | On main, the javadocs of LRUQueryCache.clearQuery and clearCoreCacheKey still say 'Remove all cache entries', but since #15558 both methods only mark the entries for the next cleanUp(), so the entries stay counted and keep producing cache hits until then; MIGRATE.md does not mention the deferred removal or the new cleanUp() duty (documentation defect, main only) | 1 |
| LFV-1000 | search / query cache (LRUQueryCache callback javadoc and MIGRATE.md) | low | On main, LRUQueryCache's class javadoc still says its statistics callbacks are 'called synchronously and under a lock', but since #15558 the callbacks of different partitions run at the same time and onClear() runs under no lock, and neither the javadoc nor MIGRATE.md tells subclasses that their statistics must now be thread-safe (documentation defect, main only) | 1 |
| LFV-890 | index / deletion policies (SnapshotDeletionPolicy and PersistentSnapshotDeletionPolicy restart lifecycle, javadoc) | low | A PersistentSnapshotDeletionPolicy re-opened over its save file counts the persisted snapshots, but getSnapshots() is empty and getIndexCommit(gen) returns null until an IndexWriter has opened with it, and no javadoc states this precondition (documentation gap; the behaviour is by design) | 1 |
| LFV-1008 | search / query cache (LRUQueryCache unified callback javadoc and MIGRATE.md) | low | On main, LRUQueryCache's onCacheEntryInserted/onCacheEntryEvicted javadoc still calls ramBytesUsed 'the total RAM cost of this entry', but since #16657 a query's shared RAM is reported only with its first inserted entry and its last removed entry, so one entry is inserted and evicted with different amounts and per-segment or per-index RAM kept through these callbacks drifts (one index stays positive, another goes negative) (documentation defect, main only) | 1 |
| LFV-931 | analysis-common, analysis-kuromoji, analysis-phonetic, analysis-opennlp / analysis factories (class javadoc <fieldType> schema examples) | low | Eight analysis-factory class javadoc schema examples cannot be used as written: six are not well-formed XML (StopFilterFactory, JapaneseIterationMarkCharFilterFactory, BeiderMorseFilterFactory, OpenNLPTokenizerFactory, OpenNLPLemmatizerFilterFactory, DropIfFlaggedFilterFactory) and two name a class that is not a factory (LimitTokenOffsetFilterFactory's solr.LimitTokenOffsetFilter, PatternTypingFilterFactory's com.example.PatternTypingFilter) (documentation defect) | 1 |
| LFV-122 | search / sorting (SortedNumericSortField missing values; javadoc) | low | SortedNumericSortField's class javadoc on main says missing values sort first or last via SortField.STRING_FIRST / STRING_LAST, but a numeric sort cannot use these string sentinels: the constructor accepts them, then every search or index sort with them throws ClassCastException | 1 |
| LFV-948 | release notes / lucene/CHANGES.txt 10.6.0 New Features (GITHUB#16243 entry) x search / similarities (StableTflSimilarity) | low | The Lucene 10.6.0 release notes (CHANGES.txt in the 10.6.0 RC1 and in main's copy of the 10.6.0 section) say StableTflSimilarity 'also supports k3 query-term frequency saturation', but 10.6.0 has no k3: the 10.6 backport left k3 out and dropped the sentence on review request, and an unrelated later backport put the sentence back (documentation defect, released in 10.6.0) | 1 |
| LFV-537 | suggest / spell (JaroWinklerDistance threshold) | low | JaroWinklerDistance.setThreshold javadoc says 'Set to a negative value to get the Jaro distance', but a negative threshold adds the Winkler bonus to every pair (the same as threshold 0); only a threshold of 1 or more gives plain Jaro; documentation defect, the javadoc fix is the default proposal | 1 |
| LFV-156 | index / ImpactsEnum shallow-advance contract (ImpactsSource javadoc, test-framework AssertingImpactsEnum); codecs / Lucene104 postings reader | low | ImpactsSource#advanceShallow javadoc does not say that the current document's freq(), positions and docIDRunEnd() become invalid after a shallow advance past its block: the default codec then returns another block's data, and a lazy freq() breaks the next legal advance() (javadoc and assertion gap; the codec behaviour is intended) | 1 |
| LFV-149 | search / kNN visit limit (visitedLimit javadoc on LeafReader, TopKnnCollector and the kNN collector managers; HNSW and exhaustive vector search) | low | The kNN visitedLimit javadoc (LeafReader#searchNearestVectors, TopKnnCollector, KnnCollectorManager, TopKnnCollectorManager, HnswGraphSearcher) calls it 'the maximum number of nodes that the search is allowed to visit', but since 10.3/10.4 batched scoring deliberately treats it as a best-effort limit that a search can exceed (javadoc only; the code behaviour is intended upstream) | 2 |
| LFV-119 | index / SegmentInfos version check (javadoc) | low | SegmentInfos#readLatestCommit(Directory, int) and #readCommit(Directory, String, int) javadocs misdescribe the minimum-version check: readLatestCommit still names the index-created major, and both say 'strictly greater' although the check is inclusive (javadoc only; the code is correct) | 1 |
| LFV-497 | index / IndexReader reference counting (decRef javadoc) | low | IndexReader#decRef javadoc says 'If an exception is hit, the refCount is unchanged', but since LUCENE-5553 (4.7.1) a final decRef whose doClose() or closed listener throws leaves the reader closed at refCount 0 (documentation defect; the code behaviour is intended and must not change) | 1 |
| LFV-973 | queryparser / flexible core nodes (BoostQueryNode javadoc) | low | Flexible query parser: the BoostQueryNode javadoc says three times (class, constructor @param, getValue) that the boost value 'may vary from 0.0 to 1.0', but boosts above 1.0 are standard syntax and are stored unchanged: StandardQueryParser's own documented example jones^2 gives a node value of 2.0 (documentation defect; every release since 2.9.0) | 1 |
| LFV-943 | index / SegmentInfos (segments_N file-format javadoc vs its writer and reader) | low | The SegmentInfos class javadoc gives a wrong segments_N (commit point) grammar: IndexCreatedVersionMajor, SoftDelCount, the SegmentCommitInfo id and FieldInfosFiles are missing, NameCounter is documented as an Int32 but written as a VLong, the fixed-width integers are written big-endian although the javadoc links the little-endian DataOutput#writeInt/#writeLong, and SegID is called the codec's identifier (documentation defect; the writer and reader agree) | 1 |
| LFV-942 | codecs / field infos (Lucene94FieldInfosFormat .fnm file-format javadoc vs its writer and reader) | low | The file-format javadoc of the default field infos format (Lucene94FieldInfosFormat) gives a wrong .fnm grammar: the per-field sequence leaves out IndexOptions, the doc-values skip-index byte, PointIndexDimensionCount and the three vector elements, and the value tables miss written values (doc-values codes 4 and 5, FieldBits 0x8 and 0x10, IndexOptions 5 since 10.5.0, VectorEncoding 2 on main) (documentation defect; the writer and reader agree) | 1 |
| LFV-934 | codecs / segment info (Lucene99SegmentInfoFormat .si file-format javadoc vs its writer and reader) | low | The file-format javadoc of the default segment info format (Lucene99SegmentInfoFormat) gives a wrong .si grammar: SegVersion and SegMinVersion are typed as String, but the writer stores three Int32s (and a flag byte plus three Int32s), and SegMinVersion and HasBlocks are missing from the documented sequence (documentation defect; the writer and reader agree) | 1 |
| LFV-939 | codecs / terms dictionary (Lucene103BlockTreeTermsWriter .tim/.tmd file-format javadoc vs its writer and reader) | low | The file-format javadoc of the default terms dictionary (Lucene103BlockTreeTermsWriter) gives a wrong .tim/.tmd grammar: each .tmd FieldStats still lists RootCodeLength and root-code bytes, which the trie-based terms index no longer writes, and the PostingsHeader is documented at the start of every .tim field although it is written once in .tmd, before NumFields (documentation defect; the writer and reader agree) | 1 |
| LFV-972 | codecs / default codec file-format overview (codecs/lucene104 package-info 'Summary of File Extensions' table and the Lucene104PostingsFormat 'Files and detailed format' list vs the files the default codec writes) | low | The default codec's 'Summary of File Extensions' table (codecs/lucene104 package documentation) is stale: it omits .fdm, .tvm, .tmd, .psm, .dvs, .dvp and .vemf, which the default codec writes, credits .veq to the default HNSW vectors format (which does not write it) and gives 'vex' without its dot; Lucene104PostingsFormat's 'Files and detailed format' list also omits .tmd and .psm (documentation defect; the code is correct) | 1 |
| LFV-938 | codecs / norms (Lucene90NormsFormat .nvm file-format javadoc vs Lucene90NormsConsumer / Lucene90NormsProducer) | low | The file-format javadoc of the default norms format (Lucene90NormsFormat) gives a wrong .nvm grammar: each Entry omits the Int16 jump-table entry count and the byte dense rank power that the writer stores right after DocsWithFieldLength, so a parser that follows it misreads NumDocsWithField and every later field; the grammar line is also labelled '.dvm' (documentation defect; the writer and reader agree) | 1 |
| LFV-970 | codecs / live docs (Lucene90LiveDocsFormat .liv file-format javadoc vs its writer and reader) | low | The file-format javadoc of the default live-docs format (Lucene90LiveDocsFormat) gives the .liv grammar as 'IndexHeader,Generation,Bits', but no separate Generation has been written since LUCENE-5969 (the deletes generation is the IndexHeader suffix), the codec footer the writer appends is missing, and the type list defines SegmentHeader instead of IndexHeader (documentation defect; the writer and reader agree) | 1 |
| LFV-974 | codecs / doc values (Lucene90DocValuesFormat class javadoc prose vs Lucene90DocValuesConsumer) | low | The file-format javadoc of the default doc-values format (Lucene90DocValuesFormat) says terms dictionaries are 'written in chunks of 16, with the first value written completely', but since 9.0 they are written in blocks of 64 terms whose other 63 terms are prefix-coded and then LZ4-compressed; it also says table compression is used for fewer than 256 unique values, while exactly 256 are table-compressed (documentation defect; the writer and reader agree) | 1 |
| LFV-971 | codecs / compound files (Lucene90CompoundFormat .cfe file-format javadoc vs the Lucene90CompoundFormat writer / Lucene90CompoundReader) | low | The file-format javadoc of the default compound format (Lucene90CompoundFormat) gives an incomplete .cfe entry-table grammar: it leaves out the codec footer the writer appends (the .cfs line beside it lists one), and it says each entry holds the file's name although the writer stores the name with the segment name stripped (documentation defect; the writer and reader agree) | 1 |
| LFV-941 | codecs / vectors (Lucene99FlatVectorsFormat .vemf and Lucene99HnswVectorsFormat .vem and .vex file-format javadoc vs their writers and readers) | low | The file-format javadocs of the default vector formats (Lucene99FlatVectorsFormat and Lucene99HnswVectorsFormat) give a wrong .vemf/.vem/.vex grammar: both metadata lists leave out the int32 vector encoding that is written right after the field number, so every later element is misread, and since 10.3 the .vex list still calls the HNSW neighbour deltas vints although they are group-varint encoded (documentation defect; the writers and readers agree) | 1 |
| LFV-255 | codecs / term vectors (Lucene90TermVectorsFormat .tvd file-format javadoc vs Lucene90CompressingTermVectorsWriter / Reader) | low | The file-format javadoc of the default term-vectors format (Lucene90TermVectorsFormat) contradicts the .tvd bytes in three places: the Flags bit meaning is inverted, FieldNums are called delta-encoded but are the plain field numbers, and AvgCharsPerTerm is called absent without positions but is written whenever a field has offsets (documentation defect; the writer and reader agree) | 1 |
| LFV-957 | release notes / lucene/CHANGES.txt 10.6.0 Improvements (CheckIndex / CorruptSegmentInfoException entry, GITHUB#7820) | low | The Lucene 10.6.0 RC1 release notes credit the CheckIndex '.si file could not be read' change to GITHUB#17820, an issue that does not exist, instead of GITHUB#7820, so the generated Changes page links to a 404; the extra digit came in with the stable-branch backports of #16788 (documentation defect, released in 10.6.0; main is correct) | 1 |
| LFV-1087 | build-tools / documentation build (DocumentationConfigPlugin.MarkdownTemplateTask.withProjectList: the 'API Javadocs' list of the documentation front page docs/index.html) | low | The documentation front page's 'API Javadocs' list links benchmark-jmh/index.html, a page no build renders: the Java port of the documentation build (#15350, backported by #16592) lists every module that has a renderSiteJavadoc task, while the Groovy build it replaced listed only modules whose task is enabled (dead link in the released 10.6.0 docs and in documentation builds of main, branch_11x and branch_10_6; documentation defect) | 1 |
| LFV-1086 | build-tools / documentation build (DocumentationConfigPlugin createDocumentationIndex template binding; lucene/documentation index.template.md) | low | The 10.6.0 documentation front page says the Migration Guide covers migrating 'from Lucene 0.x' (main builds: 'Lucene 12; ... from Lucene 2.x'), because the build binds majorVersion as a String and the template's ${project.majorVersion-1} then deletes the first '1' character instead of subtracting (documentation build defect) | 1 |
| LFV-040 | index / deletion policies | low | PersistentSnapshotDeletionPolicy.getLastSaveFile reads nextWriteGen without synchronization (benign data race) | 1 |
Snapshot of 2026-11-03. AI-assisted; not yet triaged by a human Lucene committer. Feedback: open an issue in lucene-ai-bug-hunt.