{
 "name": "AI-assisted bug hunt in Apache Lucene",
 "snapshot": "2026-11-03",
 "owner": {
  "name": "Shitij Bhargava",
  "url": "https://github.com/shbhar"
 },
 "repository": "https://github.com/shbhar/lucene-ai-bug-hunt",
 "lucene": {
  "main_tested": {
   "commit": "ea57360912ed31ae2f2c0a7a5fef422ddf4e06b0",
   "date": "2026-10-24"
  },
  "main_rechecked": {
   "commit": "e1faeba08bde7af8399e9df0849d295f0d6405f3",
   "date": "2026-11-02",
   "rerun": 1054,
   "still_reproduce": 1052,
   "unchanged": 1052,
   "behaviour_changed": 0,
   "repro_adapted": 0,
   "could_not_run": 0,
   "fixed_upstream": 2
  }
 },
 "counts": {
  "total": 1154,
  "new": 864,
  "known": 290,
  "withheld": 2,
  "public": 1152,
  "documented": 868,
  "priority": {
   "high": 9,
   "medium": 250,
   "low": 895
  }
 },
 "export": {
  "unranked": 0,
  "repro_dirs": 1152,
  "model_units": 153
 },
 "withheld_line": "Details withheld pending security review",
 "columns": [
  "id",
  "withheld",
  "area",
  "priority",
  "priority_rank",
  "title",
  "summary",
  "impact_class",
  "introduced_commit",
  "introduced_date",
  "first_affected_version",
  "affected_versions",
  "security",
  "novelty",
  "upstream_links",
  "doc",
  "repro",
  "triage_status",
  "triage_by",
  "triage_date",
  "triage_link",
  "triage_note",
  "triage_hide",
  "new_in_10_6",
  "new_in_10_6_note"
 ],
 "bugs": [
  {
   "id": "LFV-001",
   "priority": "high",
   "priority_rank": 1,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter NRT",
   "title": "openIfChanged returns null and isCurrent() stays true after a flush when the only changes are doc-values updates",
   "summary": "You open an NRT reader, update a doc-values field (or soft-delete through updateDocValues), and then call flush(), a no-op forceMerge(1), or open readers with writeAllDeletes=true. You expect DirectoryReader.openIfChanged(reader, writer) to return a reader that sees the change. Instead it returns null and reader.isCurrent() is true, so SearcherManager keeps the stale searcher, and hasUncommittedChanges() can also return false while updates are uncommitted.",
   "impact_class": "silent wrong results",
   "introduced_commit": "LUCENE-8290 591fc6627ac (flush, no-op forceMerge and writeAllDeletes paths); LUCENE-7868 58105a203a19 (RAM-pressure path and the hasUncommittedChanges symptom, commit-level bisect)",
   "introduced_date": "2018-05-02 (LUCENE-8290, authored); 2017-06-21 (LUCENE-7868)",
   "first_affected_version": "7.0.0 (RAM-pressure path and hasUncommittedChanges); 7.4.0 (flush and writeAllDeletes paths)",
   "affected_versions": "flush and open(w,true,true): every release 7.4.0-10.5.2 plus branch_10_6 d04ee73177 (2026-10-22, six commits before the 10.6.0 tag 4ae946e5a9b) and main [exec]; the 10.6.0 release itself was not run; no-op forceMerge(1) variant from 7.5.0 with the default config [exec]; RAM-pressure path and hasUncommittedChanges: 7.0.0+ [exec]; 7.3.1 and earlier correct for the flush case",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-001.html",
   "repro": "repro/LFV-001/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-016",
   "priority": "high",
   "priority_rank": 2,
   "novelty": "known",
   "withheld": false,
   "area": "index / doc-values updates",
   "title": "deleteDocuments(Query) on a doc-values field is evaluated against stale values when doc-values updates are pending",
   "summary": "You update a doc-values field and then delete documents with a query on that field before the updates are written. You expect the delete to see the updated values. Instead delete-by-query is resolved against the written values, and inside a packet deletes run before doc-values updates, so the wrong documents are deleted or kept.",
   "impact_class": "data corruption",
   "introduced_commit": "unknown (not yet bisected)",
   "introduced_date": "unknown (not yet bisected)",
   "first_affected_version": "unknown (not yet bisected; 4.9.1 is the oldest version affected per the study's report)",
   "affected_versions": "4.9.1+ per the study's report §5a; main [exec]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/8398",
    "https://issues.apache.org/jira/browse/LUCENE-7344"
   ],
   "doc": "",
   "repro": "repro/LFV-016/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-044",
   "priority": "high",
   "priority_rank": 3,
   "novelty": "known",
   "withheld": false,
   "area": "codecs / doc values",
   "title": "Doc-values range queries with a skip index return wrong hits when a segment's values span more than Long.MAX_VALUE",
   "summary": "You index numeric doc values with a skip index (NumericDocValuesField.indexedField) where one segment's values span more than Long.MAX_VALUE, and run a doc-values range query. You expect the same hits as 10.5.2. Instead the encoded-domain bound transform wraps: 100k random latitudes queried for [45, 90] gave 0 hits instead of 25,157, 64-bit hashes gave 2 instead of 49,931, and some cases add wrong hits.",
   "impact_class": "silent wrong results",
   "introduced_commit": "#16160 (9b68f633fdd6) and #16285 (263c3a4765f0)",
   "introduced_date": "2026-07-02 (#16160); 2026-07-13 (#16285)",
   "first_affected_version": "10.6.0 (released 2026-10-29) and unreleased main",
   "affected_versions": "main b83101cdd2 and branch_10_6 d04ee73177 [exec]; 10.5.2 correct [exec]; main 645d4fe14a2 [exec]; branch_10x 657014b3c57 and branch_10_6 4ae946e5a9b (10.6.0 RC1) have the identical Lucene90DocValuesProducer blob c9e4bc13f1c [read]; 10.6.0 release jars (rev 4ae946e5a9b) [exec]; main e1faeba08bd [exec]; branch_11x da3ea39fa59 (same producer blob dd67e555e5e as main) and branch_10_6 91eaab4fb29 (the 10.6.1 work; still the 10.6.0 blob c9e4bc13f1c) [read]; not targeted for 10.6.1 as of 2026-11-02 (#16896 has no milestone and files its CHANGES entry under 11.0.0); branch_10x was decommissioned on 2026-10-29 (#16911)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16896"
   ],
   "doc": "bugs/LFV-044.html",
   "repro": "repro/LFV-044/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b): 10 of 11 fail; 10.5.2 passes 11 of 11."
  },
  {
   "id": "LFV-222",
   "priority": "high",
   "priority_rank": 4,
   "novelty": "known",
   "withheld": false,
   "area": "join / block join (ToParentBlockJoinQuery.BlockJoinBulkScorer) x search / BooleanQuery MUST_NOT bulk scoring (ReqExclBulkScorer, #16669)",
   "title": "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",
   "summary": "You index parent/child blocks and search BooleanQuery(MUST ToParentBlockJoinQuery(skill:java, parentsFilter, ScoreMode.Avg), MUST_NOT status:hidden), expecting only the parents that are not hidden, which is what count() of the same query and ScoreMode.None return. Instead, on main the hidden parent p2 comes back for Avg, Max, Min and Total ([p1, p2] instead of [p1]); a MUST_NOT clause that matches only child documents (MUST_NOT skill:java) removes both parents ([] instead of [p1, p2]); and in a 6,000-doc segment where a block straddles doc 4096 the search throws AssertionError in ReqExclBulkScorer$WindowBits.get with -ea and ArrayIndexOutOfBoundsException (index -1) with -da. The cause is that since #16669 ReqExclBulkScorer folds the MUST_NOT matches of each 4096-doc window into a bit set that it passes to the required clause as acceptDocs, and the join's BlockJoinBulkScorer forwards that acceptDocs unchanged to its child scorer (ToParentBlockJoinQuery.java:541), so the exclusions are tested on child doc IDs, some of them below the window, and never on the parents it collects.",
   "impact_class": "silent wrong results",
   "introduced_commit": "c5fa32ce49f6d28e82ac1b6f111264d955d54a7f on main (apache/lucene#16669 'Use intoBitSet to speed up ReqExclBulkScorer with dense exclusions', by kkewwei for issue #16668, merged by romseygeek 2026-09-24), backported the same day to branch_10x as 92ce3eaf4bf524ee24d7dc742cedeaa812695db8, which branch_10_6 contains [exec]. Latent precondition, harmless until then: 45da83bd723f4129340322aed4cc84fdf1f194cd (apache/lucene#13697 'Add Bulk Scorer For ToParentBlockJoinQuery', 2024-09-11; 9.x backport #13764, 4d379db1a82, first shipped in 9.12.0 and 10.0.0) added BlockJoinBulkScorer forwarding acceptDocs to the child scorer (ToParentBlockJoinQuery.java:541), which could not be observed while acceptDocs was always the live docs and valid block-join indexes delete whole blocks [exec]",
   "introduced_date": "2026-09-24 (c5fa32ce49f on main; 92ce3eaf4bf on branch_10x and branch_10_6); latent precondition 2024-09-11 (45da83bd723, #13697)",
   "first_affected_version": "10.6.0 (released 2026-10-29, the first release with it, then 11.0.0; CHANGES.txt lists #16669 under 10.6.0) [exec]",
   "affected_versions": "main (11.0.0-SNAPSHOT) from c5fa32ce49f (2026-09-24) through 645d4fe14a2 (upstream main head, 2026-10-29) [exec]; 10.6.0 (released 2026-10-29) [exec]; branch_10_6 (10.6.0-SNAPSHOT) [exec]; branch_10x [read]; not affected: every release through 10.5.2 [exec] and branch_10_5 [read]; #16715 (2026-10-08/09, on main and branch_10_6) narrows the trigger to joins whose cost exceeds 3*maxDoc/1000 but does not fix it",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/14067",
    "https://github.com/apache/lucene/issues/16669",
    "https://github.com/apache/lucene/issues/13697",
    "https://github.com/apache/lucene/issues/16702",
    "https://github.com/apache/lucene/issues/13770",
    "https://github.com/apache/lucene/issues/12194"
   ],
   "doc": "bugs/LFV-222.html",
   "repro": "repro/LFV-222/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b): 3 of 3 fail with -ea and -da; 10.5.2 passes 3 of 3."
  },
  {
   "id": "LFV-106",
   "priority": "high",
   "priority_rank": 5,
   "novelty": "new",
   "withheld": false,
   "area": "search / vector similarity queries and the query cache",
   "title": "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",
   "summary": "You search with a vector similarity (threshold) query, for example FloatVectorSimilarityQuery, in a non-scoring context such as IndexSearcher#count or ConstantScoreQuery, with a query cache that several readers or searchers share (the IndexSearcher default in 9.10.0-10.6.0, 10.6.0 by reading). You expect every reader and every search to get the hits it gets without the cache. Instead the cache hands one reader's or one search's per-segment result to another: an older point-in-time reader misses a document that only a newer reader has deleted (99 hits instead of 100), a search without a timeout gets the empty result of an earlier timed-out search (0 instead of 100), and with a filter on an updated doc-values field a newer reader gets a document that no longer matches the filter (100 instead of 99).",
   "impact_class": "silent wrong results",
   "introduced_commit": "cd195980ecb (#12679 'Add support for similarity-based vector searches', main; branch_9x backport 8089b8c9d33) for the live-docs and filter dependence: the query was added with isCacheable() returning true and a per-segment result built from leafReader.getLiveDocs() and the filter Weight [read]; e0e5d81df80 (#13285 'Add timeout support to AbstractVectorSimilarityQuery', main only, never backported to 9.x) added the timeout dependence without changing isCacheable() [exec]; not a regression: isCacheable() has returned true since the query's first version",
   "introduced_date": "2023-12-11 (#12679 merged on main 19:18 UTC; branch_9x backport 19:43 UTC the same day); 2024-08-06 (#13285 merged on main)",
   "first_affected_version": "9.10.0 [exec] (live docs and filter; first release with the query, 9.9.2 has no FloatVectorSimilarityQuery [exec]); 10.0.0 [exec] for the timeout manifestation",
   "affected_versions": "live docs and non-cacheable filter: all 19 releases 9.10.0, 9.11.0, 9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2 and main ea57360912ed [exec]; timeout: the 12 releases 10.0.0-10.5.2 and main [exec], not 9.x [exec]; with zero cache configuration every release 9.10.0-10.5.2 is affected, because IndexSearcher installs a shared static LRUQueryCache with UsageTrackingQueryCachingPolicy [exec], main only when the application installs a query cache (#14187 removed the default; in no release yet) [exec]; not applicable before 9.10.0 (API absent) [exec]; upstream main, branch_10x, branch_10_6 and branch_9_12 still return true [read], so 10.6.0 (released 2026-10-29) is affected too [read]; not fixed upstream [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-106.html",
   "repro": "repro/LFV-106/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-038",
   "priority": "high",
   "priority_rank": 6,
   "novelty": "known",
   "withheld": false,
   "area": "search / multi-term queries",
   "title": "Doc-values-rewritten multi-term queries are invisible to QueryVisitor, so they escape the nested clause limit and the query-cache RAM budget",
   "summary": "You run a query tree whose leaves are multi-term queries rewritten with MultiTermQuery.DOC_VALUES_REWRITE (or SortedSetDocValuesField/SortedDocValuesField.newSlowSetQuery) under IndexSearcher's maxClauseCount. You expect IndexSearcher.rewrite to count each such leaf toward the nested clause limit, and an LRUQueryCache to account for the terms a cached query holds. Instead MultiTermQueryDocValuesWrapper.visit calls visitor.getSubVisitor(FILTER, query) and throws the result away, so each leaf counts as 0: with maxClauseCount=8 a query with 10 such leaves raises no TooManyNestedClauses, and a cached 50,000-term TermInSetQuery that holds 966,712 bytes is accounted as 200 bytes; search results stay correct.",
   "impact_class": "silent wrong results",
   "introduced_commit": "5286098ac5c (LUCENE-8849)",
   "introduced_date": "2020-03-11",
   "first_affected_version": "8.6.0",
   "affected_versions": "every release since 8.6.0, branch_10_6 and main [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/13140"
   ],
   "doc": "",
   "repro": "repro/LFV-038/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-011",
   "priority": "high",
   "priority_rank": 7,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter merge",
   "title": "With index sorting and a parent field, deleting only a block's parent makes every later merge fail",
   "summary": "You use index sorting with a parent field and document blocks, and delete only the parent document of a block. You expect later merges to work. Instead MultiSorter finds no parent for the orphaned child (nextSetBit returns NO_MORE_DOCS), every later merge of that segment throws (an EOFException with the default codec on a file-system directory, IndexOutOfBoundsException on ByteBuffersDirectory), the writer closes tragically and uncommitted documents are lost.",
   "impact_class": "index unusable",
   "introduced_commit": "#12829 (df6bd25ce44 on main; backport 0aa88910ca9) introduced the parent field",
   "introduced_date": "2024-01-11",
   "first_affected_version": "9.10.0",
   "affected_versions": "9.10.0+ [read]; 9.12.3, 10.1.0, 10.3.1, 10.5.2, 10.6.0 and main [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-011.html",
   "repro": "repro/LFV-011/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-005",
   "priority": "high",
   "priority_rank": 8,
   "novelty": "new",
   "withheld": false,
   "area": "search / HNSW",
   "title": "HNSW merge-time graph reuse can leave the entry node with no neighbours, dropping kNN recall to zero",
   "summary": "You delete a cluster of documents around the HNSW entry node and merge, for example with forceMerge(1), so the merge reuses and repairs the biggest segment's graph. You expect kNN recall to stay about the same. Instead the repair cannot reconnect an entry node that lost every neighbour, every search starts at that isolated node and returns only it (recall@10 0.906 to 0.000 in the repro), and CheckIndex reports no problem.",
   "impact_class": "silent wrong results",
   "introduced_commit": "#15003 (ef10476d98a; backport 3e024479d35) added merge-time reuse of graphs with deletions",
   "introduced_date": "2025-12-01",
   "first_affected_version": "10.4.0 (non-per-field HNSW codec); 10.5.1 (default codec)",
   "affected_versions": "10.5.1, 10.5.2, branch_10_6, main with the default codec [exec]; 10.4.0 and 10.5.0 only with a codec whose vectors format is not wrapped per field (#16400) [exec]; 10.3.2 not affected [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-005.html",
   "repro": "repro/LFV-005/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-811",
   "priority": "high",
   "priority_rank": 9,
   "novelty": "known",
   "withheld": false,
   "area": "codecs / HNSW vectors on the 10.x line (merge-time graph reuse: InitializedHnswGraphBuilder, MergingHnswGraphBuilder, ConcurrentHnswMerger; Lucene99HnswVectorsWriter .vem metadata)",
   "title": "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)",
   "summary": "You build a vector index with HNSW maxConn 16 (the default), later open a writer whose codec sets maxConn 32 for the same field (or go the other way), and force-merge, or add the old index with addIndexes(CodecReader...); you expect the merge to succeed and kNN search to keep working, as it does on main, and as raising did on 10.3.2. Instead, on 10.5.1, 10.5.2 and branch_10_6, raising makes the merge throw IllegalStateException 'No growth is allowed' and closes the IndexWriter, and lowering lets the merge succeed but every kNN query on the new segment throws ArrayIndexOutOfBoundsException (AssertionError 'too many neighbors' with -ea). The 10.x backport of #15003 sizes the merged graph from the reused graph's maxConn, while the merge builders insert the new vectors, and the writer records the .vem metadata, with the configured maxConn.",
   "impact_class": "index unusable",
   "introduced_commit": "3e024479d358e77ba7d802308b70ccb25ccf08c4, the branch_10x backport of #15003 'Avoid reconstructing HNSW graphs during segment merging' (authored by @Pulkitg64, committed to branch_10x by @benwtrent as a direct push, no backport PR): it replaced new OnHeapHnswGraph(M, ...) with new OnHeapHnswGraph(initializerGraph.maxConn(), ...) but kept the configured M in MergingHnswGraphBuilder.fromGraphs, ConcurrentHnswMerger and Lucene99HnswVectorsWriter.writeMeta; the main merge of #15003 (ef10476d98a) is consistent because main already had #14097 (builder M = hnsw.maxConn()) and #14121 (writeMeta writes graph.maxConn()), neither of which is on 10.x [read]. Made reachable with the default codec by #16403 (fixes #16400, @jeho-rpls; 2459ab7749c on branch_10x and branch_10_6, cherry-picked to branch_10_5 as 6c59b2e5933), which restored graph reuse under per-field vectors formats [exec]",
   "introduced_date": "2025-12-01 (3e024479d35 on branch_10x; first released in 10.4.0, 2026-02-20); reachable with the default codec from #16403 (branch_10x 2026-07-23, branch_10_5 2026-08-05; first released in 10.5.1, 2026-08-07)",
   "first_affected_version": "10.4.0 [exec], where it and 10.5.0 are reachable only through a legal custom codec whose vectors format is not wrapped in PerFieldKnnVectorsFormat (6 of 7 fail; with the default codec no graph reuse happens there, #16400); 10.5.1 with the default codec or any per-field vectors format [exec]; last release without it 10.3.2, which has an older, different form of the same trigger [exec]",
   "affected_versions": "10.5.1 [exec], 10.5.2 [exec], branch_10_6 head 4ae946e5a9b = 10.6.0 RC1 (released as 10.6.0 on 2026-10-29) [exec], branch_10x head 657014b3c57 [exec]; branch_10_5 head e85bb7b2c86 [read]; 10.4.0 and 10.5.0 only through a codec without PerFieldKnnVectorsFormat [exec]. Not affected: main a9779ef3c193 [exec], consistent by design (#14097, #14121). Older, different defects with the same trigger, not this bug: 9.10.0-10.3.2 [exec], 9.9.0 [exec], 9.6-9.8 (#12570, not executed). Caveats: JDK 25 on aarch64 only; old releases run on a modern JDK",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/14118",
    "https://github.com/apache/lucene/issues/14121",
    "https://github.com/apache/lucene/issues/12570",
    "https://github.com/apache/lucene/issues/12571",
    "https://github.com/apache/lucene/issues/16905",
    "https://github.com/apache/lucene/issues/16913"
   ],
   "doc": "",
   "repro": "repro/LFV-811/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-158",
   "priority": "medium",
   "priority_rank": 10,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / StandardTokenizer and the other JFlex-generated scanners (zzRefill in both Lucene JFlex skeletons)",
   "title": "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",
   "summary": "You index a text field with StandardAnalyzer at default settings, and the value ends in an unpaired high surrogate, for example 'hello world' followed by U+D83D, which is what cutting a Java String inside an emoji, or decoding the JSON escape \\ud83d, produces. You expect hello and world to be indexed and end() to report the input length as the final offset, as happens when the same lone surrogate sits mid-text and as Lucene 7.6.0 did. Instead the scanner's refill reads the whole text, looks one char ahead for the missing low surrogate, hits end of input and reports 'no new input', so the scanner ends the stream without scanning what it just read: no tokens, final offset 0, and the document does not match title:hello; values longer than the 255-char buffer lose or split their last window instead.",
   "impact_class": "silent wrong results",
   "introduced_commit": "283b19a8da6ab9e0b7e9a75b132d3067218d5502 (LUCENE-8527, apache/lucene#9573, JFlex 1.7.0 upgrade by sarowe, a JIRA patch committed without a pull request; the same change went to branch_7x as e8c65da6bb8 (first released in 7.7.0) and to branch_8x as 0e903cab47e) added the low-surrogate lookahead with 'if (c == -1) { return true; }' to the no-buffer-expansion skeleton only, which generates StandardTokenizerImpl and UAX29URLEmailTokenizerImpl; af831d281056 (LUCENE-10239, apache/lucene#452, JFlex 1.7.0 -> 1.8.2 by rmuir; branch_9x backport ee56d314257, first released in 9.1.0) brought the same branch into the default skeleton from JFlex 1.8.2's own skeleton, which generates ClassicTokenizerImpl, WikipediaTokenizerImpl and HTMLStripCharFilter [exec]",
   "introduced_date": "2019-01-08 (283b19a8da6, LUCENE-8527; 7.7.0 tagged 2019-02-08); 2021-11-19 (af831d281056, LUCENE-10239; 9.1.0 tagged 2022-03-21)",
   "first_affected_version": "7.7.0 [exec] for StandardTokenizer (and so StandardAnalyzer) and UAX29URLEmailTokenizer (7.6.0 passes); 9.1.0 [exec] for ClassicTokenizer, WikipediaTokenizer and HTMLStripCharFilter (9.0.0 passes for those three)",
   "affected_versions": "StandardTokenizer, StandardAnalyzer and UAX29URLEmailTokenizer: 7.7.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2 (the last release before 10.6.0) and main ea57360912ed; ClassicTokenizer, WikipediaTokenizer and HTMLStripCharFilter: 9.1.0-9.12.3, 10.0.0-10.5.2 and main. Executed: the follow-up's framework-free history probe ('hello world' + U+D83D through all five scanners) fails on 7.7.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main with -ea (also -da on 7.7.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.5.2 and main), losing text only in StandardTokenizer and UAX29URLEmailTokenizer on 7.7.0-9.0.0 and in all five from 9.1.0 on, and passes on 6.6.6, 7.5.0 and 7.6.0 (7.6.0 also -da); the finder's JUnit fails on 9.1.0, 9.12.3, 10.5.2 and main and its main() on 7.7.0, 7.7.3, 8.0.0, 8.11.4, 9.12.3 and 10.5.2; the independent reproduction's JUnit fails on 9.12.3, 10.5.2 and main (-ea, -da) [exec]. The other releases come from a grep of the generated scanners at every release tag in the history clone (branch present in StandardTokenizerImpl at every tag from 7.7.0 to 10.5.2, in ClassicTokenizerImpl from 9.1.0; 8.8.2-8.11.3 are not tagged there, 8.11.4 was executed) [read]. The long-text symptoms (tail lost or a word split at the last refill boundary) were executed on 9.1.0 and later only; on 7.7.0-9.0.0 they follow from the identical branch [read]. Not fixed upstream: upstream main head equals the tested commit, no open PR touches the scanners or skeletons, and JFlex master's skeleton.default has the same branch [read]; release branches were not checked.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-158.html",
   "repro": "repro/LFV-158/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-146",
   "priority": "medium",
   "priority_rank": 11,
   "novelty": "known",
   "withheld": false,
   "area": "index / FieldInfos and segment metadata strings (DataOutput#writeString in .fnm, segments_N and .si)",
   "title": "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)",
   "summary": "You add a document with two field names that differ only in an unpaired surrogate, for example 'f\\uD800' and 'f\\uFFFD' (or two different lone surrogates in the same position), and commit; addDocument and commit return normally, as IndexWriter documents that malformed UTF-16 is silently replaced with U+FFFD, and you expect the committed index to open. Instead DataOutput#writeString writes both names as the same bytes ('f' + U+FFFD), so DirectoryReader.open and a new IndexWriter throw IllegalArgumentException 'duplicate field names: 0 and 1 have: f\\uFFFD' for the whole index, and CheckIndex can only recover it by dropping the whole segment. On main the same happens for two colliding field attribute keys or commit user-data keys ('duplicate key'), and a lone-surrogate index-sort field name is stored in its U+FFFD form, so a new IndexWriter with the same sort is refused.",
   "impact_class": "index unusable",
   "introduced_commit": "04b346bdd4d4 (branch_4x copy of trunk 63a95f11759f, LUCENE-4196 'add missing checks when reading up-front metadata', migrated issue apache/lucene#5268, commits by rmuir) turned the FieldInfos duplicate-name assertion into an IllegalArgumentException, which makes the committed index unopenable with and without assertions; the collision itself comes from the root-cause commit 8af3598b74d5 (LUCENE-510 / #1588 'store strings as true UTF8 not modified UTF8', first in 2.4.0), since which writeString writes EF BF BD for every unpaired surrogate (UnicodeUtil.java:231-235 still blames to it); the commit user-data and field attribute key manifestations come from fe761a06f02 (#15457 for GITHUB#15453, Map.ofEntries in readMapOfStrings, main only); the index-sort manifestation from LUCENE-6766 (6.2.0, after a merge) and LUCENE-7579 (6.5.0, after any commit) [read]",
   "introduced_date": "2012-08-31 (LUCENE-4196 hard check; first release 4.0.0, tagged 2012-10-11); root cause 2008-03-26 (LUCENE-510; first release 2.4.0); map-key manifestations 2025-12-08 (#15457, main only)",
   "first_affected_version": "4.0.0 [exec] (committed index unopenable with -ea and -da); with assertions only: 3.6.0 [exec] and 4.0.0-ALPHA/4.0.0-BETA [exec]; silent field merge from 2.4.0 [exec]; index-sort manifestation 6.2.0 after a merge and 6.5.0 after any commit [exec]; commit user-data and field attribute keys: unreleased, main only [exec]",
   "affected_versions": "field names: every release 4.0.0 through 10.6.0 (10.6.0 by reading) and main ea57360912ed; executed failing on 4.0.0 and 4.10.4 (-ea and -da), 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.11.3, 9.0.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) [exec]; the other tags by the identical 'duplicate field names' check at all 121 release tags from 4.0.0 to 10.5.2 and the unchanged U+FFFD substitution [read]; branch_10x and branch_10_6 carry the same check [read], so 10.6.0 (released 2026-10-29) is affected; field attribute and commit user-data keys: main only (fatal since #15457), while 9.12.3, 10.0.0 and 10.5.2 silently keep one of the two entries [exec]; index-sort field name: 6.2.0-6.4.2 after a merge, 6.5.0 through 10.5.2 and main after any commit [exec]; milder symptoms of the same root cause: 2.4.0-3.5.0, and 3.6.x with -da, silently merge the two fields under the U+FFFD name [exec], 3.6.2 with -ea fails with an AssertionError, 4.0.0-ALPHA/BETA fail with an AssertionError with -ea and silently lose one field's postings with -da [exec]; unaffected: 2.3.2 and earlier (modified UTF-8 keeps lone surrogates) [exec]; not fixed upstream [read]",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-510",
    "https://github.com/apache/lucene/issues/1588",
    "https://issues.apache.org/jira/browse/LUCENE-4196",
    "https://github.com/apache/lucene/issues/5268",
    "https://github.com/apache/lucene/issues/15453",
    "https://github.com/apache/lucene/issues/15457"
   ],
   "doc": "",
   "repro": "repro/LFV-146/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-904",
   "priority": "medium",
   "priority_rank": 12,
   "novelty": "new",
   "withheld": false,
   "area": "core / index write path (delete-by-query: FrozenBufferedUpdates.applyQueryDeletes) x core / search and queries (reader-dependent rewrites)",
   "title": "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",
   "summary": "You call IndexWriter.deleteDocuments(query) (or updateDocuments(query, docs)) on an index with two or more segments and expect it to delete the documents IndexSearcher.search(query) returns, since the javadoc says it 'Deletes the document(s) matching any of the provided queries'. Instead the writer rewrites the query on a separate one-segment IndexSearcher for each segment, so top-k, top-N term expansion and index statistics are computed per segment: a kNN query with k=2 deletes up to 2 documents per segment (4 on two segments), a default FuzzyQuery deletes 60 documents where search finds 50, and MoreLikeThisQuery or a score-range predicate deletes none of the documents search returns. With the same documents committed in one segment before the delete, the delete equals the search result, so the segment layout alone decides what is deleted, and the result is permanent once committed.",
   "impact_class": "data corruption",
   "introduced_commit": "5b113c8af63c (LUCENE-1194 / #2271, 'add IndexWriter.deleteDocuments(Query)', svn r634219, Subversion era, no PR) [read]. The first implementation already resolved a delete query per segment: DocumentsWriter.applyDeletes did 'IndexSearcher searcher = new IndexSearcher(reader); Weight weight = query.weight(searcher)' for each SegmentReader (DocumentsWriter.java:2794-2801 at the commit), and Query.weight starts with searcher.rewrite(this). Every later rewrite of the resolution code kept the per-segment searcher: LUCENE-2680 / LUCENE-1076 (BufferedDeletes, BufferedDeletesStream, 3.1/3.2), QueryWrapperFilter per segment (3.3-5.2.1), 5d16b973962 (LUCENE-6688 / #7746, 2015, new IndexSearcher(readerContext.reader())), 58105a203a1 (LUCENE-7868 / #8919, 2017, FrozenBufferedUpdates) and 798d3510341 (LUCENE-8242 / #9289, 2018, explicit searcher.rewrite + createWeight). On main the lines are FrozenBufferedUpdates.java:397-400 (git blame -w -M -C: 397-398 from 5d16b973962, 399-400 from 798d3510341). Not a regression: the bug is as old as the API; what changed over time is only which stock queries expose it.",
   "introduced_date": "2008-03-06 (5b113c8af63, author date = commit date)",
   "first_affected_version": "2.4.0 [exec], the first release with IndexWriter.deleteDocuments(Query) (CHANGES 'Release 2.4.0 2008-10-06', New features item 9); 2.3.2 and older have no such method [exec]. Trigger families by release [read]: MoreLikeThisQuery and the default FuzzyQuery (then capped at 1024 terms) from 2.4.0, explicit TopTerms rewrites from 3.1, the default FuzzyQuery with maxExpansions = 50 from 4.0.0, CommonTermsQuery from 4.1.0, score-range FunctionRangeQuery from 5.4.0, kNN from 9.0.0 (KnnVectorQuery) / 9.5.0 (KnnFloatVectorQuery), and the second entry point updateDocuments(Query, Iterable) from 9.7.0 (#12346).",
   "affected_versions": "every release from 2.4.0 to 10.5.2, 10.6.0 (branch_10_6 head 4ae946e5a9b, the RC1 revision) and main a9779ef3c193. [exec] portable history probes (public API; reference = search on a 2-segment index, plus a per-segment-union and a one-segment control) fail on 22 releases (2.4.0, 2.4.1, 2.9.4, 3.0.3, 3.1.0, 3.6.2, 4.0.0, 4.1.0, 4.10.4, 5.0.0, 5.2.1, 5.3.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.5.0, 9.12.3, 10.0.0, 10.5.2; -da also on 2.4.0, 9.12.3 and 10.5.2), branch_10_6 and main (-ea and -da): default FuzzyQuery 1074 deleted vs 1024 searched (2.x-3.x) or 60 vs 50 (4.0.0 on), MoreLikeThisQuery 0 vs 6, CommonTermsQuery 3 vs 2 (4.1.0 on), kNN k=2 4 vs 2 (9.0.0 on); in every deviating check the deleted set equals the per-segment union, the one-segment layout deletes exactly the search set, and the numbers do not change across any rewrite of the resolution code. The finder's JUnit fails 6 of 7 on main (-ea, -da), branch_10_6, 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 7 of 9 on main (-ea, -da), 10.5.2 and 9.12.3; re-run at the registration check on main (-ea and -da). [read] every one of the 136 release tags from 2.4.0 to 10.5.2 in the clone resolves a delete query with a one-segment IndexSearcher (or a QueryWrapperFilter that builds one). Not executed: updateDocuments(Query, ...) on releases (exercised on main by the finder's matrix and the independent reproduction's JUnit), the explicit TopTerms and score-range triggers before 9.12.3. Not fixed upstream: FrozenBufferedUpdates.java last changed in 169cbffd12f (#16581, author date 2026-09-21), which does not touch the delete-query searcher [read]. All runs on JDK 25 (aarch64 Linux).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-904.html",
   "repro": "repro/LFV-904/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1045",
   "priority": "medium",
   "priority_rank": 13,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter full flush (DocumentsWriterFlushControl.nextPendingFlush)",
   "title": "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",
   "summary": "Several threads replace documents by key with updateDocument while another thread calls commit(); you expect every commit point to hold exactly one live document per key and only the operations up to the sequence number commit() returned. Instead, an indexing thread that has just seen 'no full flush running' in nextPendingFlush can, if the commit's full flush starts at that moment, flush a buffer that belongs after the commit inside it, so the commit contains newer operations and, when the delete half of an update misses the older document, two live documents for one key. With assertions enabled it often shows instead as a tragic AssertionError in DocumentsWriter.doFlush that closes the writer.",
   "impact_class": "silent wrong results",
   "introduced_commit": "4fd5dceb998bea7e2d3da96bcd24fce43ed2014c (LUCENE-3090, apache/lucene#4163 'DWFlushControl does not take active DWPT out of the loop on fullFlush', svn r1104026, author s1monw, reviewed by mikemccand; no pull request, svn/JIRA era) [read]. Kept open by LUCENE-3773 (d5056929d02, 2012-02-12: fullFlush is read under the monitor into a local, the check-out still runs after the release) and LUCENE-9304 (2602269f3ec on main, 83b34d47900 on branch_8x, 2020-04-11: DWPT pool rewrite; checkOutForFlush never looks at fullFlush)",
   "introduced_date": "2011-05-17 (author and commit date of 4fd5dceb998, 06:58:39 UTC)",
   "first_affected_version": "4.0.0-ALPHA by code [read] (git tag --contains 4fd5dceb998: 4.0.0-alpha first; no 3.x release has DocumentsWriterPerThread). First release with an executed failure: 5.3.0",
   "affected_versions": "[exec] main 645d4fe14a20 (-da and -ea: the repro, the independent reproduction, the cross-model review, the intended-behaviour check, the adjudication and the re-run), 10.6.0 RC1 4ae946e5a9b (core jar, a port with both oracles: fails; passes with the fix), 10.5.2, 9.12.3, 9.6.0, 9.5.0, 9.1.0, 8.5.2, 7.7.3, 6.6.6, 5.5.5 and 5.3.0 fail (-da; every one of them except 9.6.0 passes with only that release's one-hunk fix shadowed). [read] 4.0.0-ALPHA to 5.2.1, 8.6.0 to 9.0.x, 9.3.0 and 10.0.0 to 10.5.1 have the same window; runs of 60-600 s on 4.0.0, 4.10.4, 5.2.1, 8.6.0, 8.11.4, 9.0.0 and 9.3.0 did not hit (not reproduced, not shown unaffected); upstream main e1faeba08bd changes DocumentsWriterFlushControl.java since 645d4fe only by #16867, outside nextPendingFlush, and the minimal repro fails there with -da and -ea [exec]. Not affected [exec]: 3.6.2 and earlier (no DocumentsWriterPerThread; pass with -da and -ea)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1045.html",
   "repro": "repro/LFV-1045/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-118",
   "priority": "medium",
   "priority_rank": 14,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexingChain per-field schema validation (frozen-FieldType cache)",
   "title": "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",
   "summary": "You index documents whose field id is a StringField plus a SortedDocValuesField, adding the StringField first, and then a document that has only the StringField. You expect IllegalArgumentException, as Lucene's per-field consistency rule (LUCENE-9334, MIGRATE.md) requires, as 9.0-10.4 do, and as main still does when the doc-values value comes first, the type is an unfrozen copy, or a flush comes in between. Instead the document is accepted, because the frozen-FieldType cache added in 10.5.0 (#15886) caches the first value's type after the union of all the document's values was validated and then skips the check for every later document whose first value has that type; on the same fast path the schema state is not rebuilt, so after a rejected addBatch a valid StringField + StoredField document fails with 'index options: expected DOCS, but it has NONE'.",
   "impact_class": "wrong error",
   "introduced_commit": "9e1c6a37c6e3 (#15886 'Cache frozen FieldType to skip schema validation', by Tim-Brooks, merged by ChrisHegarty; 10.x backport 9a6f19f34b29 with an identical patch-id; CHANGES lists it under 10.5.0 Optimizations) [read]; widened by #16171 (3ca085e1c77, 10.x eccb3394382), which re-caches the first value's type after every validated document (not needed for the row repro); symptom 2 also needs IndexWriter#addBatch, added by #15990 (3d895681557, backport #16066 / 3ec3bff01b1), where the full repro fails 4 of 6 [exec]; the skipped check itself, FieldSchema.assertSameSchema, dates from LUCENE-9334 (d03662c48bf, 9.0.0)",
   "introduced_date": "2026-04-07 (#15886 merged into main as 9e1c6a37c6e); 2026-05-14 (#15990, addBatch); 2026-06-14 (#16171); 10.5.0 is the first release containing all three",
   "first_affected_version": "10.5.0 [exec]",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2 and main ea57360912ed (unreleased 11.0.0) [exec]; branch_10x and branch_10_6 (10.6.0, released 2026-10-29) carry the same code [read]; not affected: 9.1.0, 9.12.3, 10.0.0, 10.3.2, 10.4.0 and the parent commit of #15886, which reject the subset documents (the cache does not exist there) [exec]; 9.0.0 and 8.x not run (the per-field consistency contract starts in 9.0.0); symptom 2 cannot predate 10.5.0 because addBatch did not exist; not fixed upstream as of 2026-10-26 (upstream main head is ea57360912ed; the last IndexingChain.java change on main, branch_10x and branch_10_6 is #16708 of 2026-09-28, which does not touch the cache) [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-118.html",
   "repro": "repro/LFV-118/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-009",
   "priority": "medium",
   "priority_rank": 15,
   "novelty": "new",
   "withheld": false,
   "area": "index / doc-values updates",
   "title": "tryUpdateDocValue is overwritten by an earlier, still-buffered doc-values update",
   "summary": "You update a doc-values field by term and, before that buffered update is resolved, call tryUpdateDocValue on the same document. You expect the later tryUpdateDocValue to win, as sequence numbers say. Instead it is applied in place with the next delete generation, the earlier term update resolves later and wins, and the wrong value (or a lost un-delete) is durable.",
   "impact_class": "data corruption",
   "introduced_commit": "LUCENE-8297 (#9344; 48a2138e899 on branch_7x, b0b32931b28 on master) [exec]",
   "introduced_date": "2018-05-07",
   "first_affected_version": "7.4.0 [exec]",
   "affected_versions": "7.4.0 to 10.5.2 (all 67 releases) and main [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-009.html",
   "repro": "repro/LFV-009/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-901",
   "priority": "medium",
   "priority_rank": 16,
   "novelty": "known",
   "withheld": false,
   "area": "core / index write path (delete-by-query: FrozenBufferedUpdates.applyQueryDeletes over the ReadersAndUpdates pooled reader) x core / search kNN queries",
   "title": "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)",
   "summary": "You index 10 documents with vectors, delete the nearest one (d0) by its id term, commit, then call deleteDocuments(new KnnFloatVectorQuery(field, target, 1)) and expect it to delete the nearest remaining document, d1, which is what an NRT search at that point returns. Instead nothing more is deleted: IndexWriter runs delete queries on its internal pooled SegmentReader, whose live docs are not refreshed after deletes, so the kNN query still sees d0 as live and picks it again (also after an NRT reopen, or with both deletes in one session). Likewise, while the documents are still buffered, a document added after the kNN delete can take the top slot inside the flushed segment and is then cut by the delete's docID limit, so the delete removes nothing.",
   "impact_class": "data corruption",
   "introduced_commit": "two triggers, both on main before 9.0.0 [exec]. Core trigger (a kNN delete after the same writer deleted a document): 6993fb9a9985372b0f0984b8bdd7434aaa33ad26, 'LUCENE-10040: Handle deletions in nearest vector search' (apache/lucene#239, by jtibshirani), which made the kNN query pass ctx.reader().getLiveDocs() as acceptDocs, so its matches started to depend on the live docs of the reader it is rewritten against; at its parent 19e5c00a4ff search and delete still agree (the kNN query ignored deletions everywhere). Flush-path trigger (a later document takes a top-k slot and is cut by the docIDUpto limit): 624560a3d7060a1ae9f9b647b229590f28c4aa24, 'LUCENE-9614: add KnnVectorQuery implementation' (apache/lucene#235, by msokolov), the first kNN query. The write-path view itself is older [read]: applyQueryDeletes over segState.reader with evaluate-then-cut at the limit is from 58105a203a1 (LUCENE-7868, 2017, which also made reader pooling the default in 7.0.0), ReadersAndUpdates#getReader without a live-docs refresh goes back to 263787259c6 (LUCENE-3855, 2012), and swapNewReaderWithLatestLiveDocs (refresh after doc-values writes, not after deletes) to e99a19755c7 (LUCENE-8246, 2018); no stock query before kNN depended on live docs, so none could expose it.",
   "introduced_date": "2021-08-16 (core trigger; author date 2021-08-16 17:44 +0300); 2021-08-13 (flush-path trigger; author date 2021-08-13 12:15 -0400)",
   "first_affected_version": "9.0.0 (release tag 2021-12-06), the first release with any kNN query [exec]",
   "affected_versions": "every release from 9.0.0 to 10.5.2, 10.6.0 (branch_10_6 4ae946e5a9b [exec], below) and main a9779ef3c193. [exec] 9.0.0 (-ea and -da), 9.4.2, 9.5.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main: the same 4 scenarios fail on each (history variant on 9.0.0-9.12.3, the candidate's JUnit from 9.5.0); the independent reproduction's own JUnit and a separate JUnit also fail on 10.5.2 and 9.12.3; branch_10_6 4ae946e5a9b fails 4 of 5 (finder run). [read] all 33 release tags 9.0.0 to 10.5.2 carry the same three mechanism lines (SegmentState takes rld.getReader; applyQueryDeletes searches new IndexSearcher(segState.reader) and cuts at the limit after evaluation; the kNN rewrite reads getLiveDocs) and DEFAULT_READER_POOLING = true. Query families: KnnVectorQuery 9.0.0-9.12.x, KnnFloatVectorQuery and KnnByteVectorQuery since 9.5.0, SeededKnnVectorQuery and PatienceKnnVectorQuery since 10.2.0 (byte, seeded and patience executed on main only, in the finder's matrix; byte also in a separate test). Not affected: 8.11.4 and older (no vector API; the history repro does not compile). Not fixed on upstream main c5ab3e57b9b (no upstream commit since 2026-09-21 touches the four fix-site files).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/8398",
    "https://issues.apache.org/jira/browse/LUCENE-7344",
    "https://github.com/apache/lucene/issues/8919",
    "https://issues.apache.org/jira/browse/LUCENE-7868",
    "https://github.com/apache/lucene/issues/9512",
    "https://issues.apache.org/jira/browse/LUCENE-8466"
   ],
   "doc": "",
   "repro": "repro/LFV-901/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-643",
   "priority": "medium",
   "priority_rank": 17,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter doc-values updates (BinaryDocValuesUpdate, DocumentsWriterDeleteQueue slices, FieldUpdatesBuffer)",
   "title": "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)",
   "summary": "You call IndexWriter.updateBinaryDocValue(term, field, value), or updateDocValues(term, binaryDocValuesField), and afterwards reuse or change that BytesRef, for example one BytesRefBuilder scratch for a loop of updates or a BinaryDocValues.binaryValue() taken from another reader; each document should get the value it was passed. Documents in flushed segments do, but documents still buffered in RAM get whatever bytes the BytesRef holds when the writer next adds a document or flushes, so a loop over one scratch buffer gives every buffered target the last value. The wrong value is committed silently: no exception, CheckIndex is clean, and the outcome depends on whether the target document had already been flushed.",
   "impact_class": "silent wrong results",
   "introduced_commit": "c5263086b4da47ae0331678f1ec64dc1e7e3577b on trunk / 019b0c879cbc8d788152dc0693ff2c7d6e88ccda on branch_4x (the backport that 4.8.0 contains), LUCENE-5513 'add IndexWriter.updateBinaryDocValue' (JIRA LUCENE-5513 = apache/lucene#6576; Subversion era, no pull request) [read]. It added BinaryDocValuesUpdate, whose constructor stores the BytesRef reference, and updateBinaryDocValue, which passes the caller's BytesRef straight in; no later commit added a copy (git log -S deepCopyOf on DocValuesUpdate.java finds none; LUCENE-8282 and LUCENE-8298 refactored the class in 2018 and kept the reference). The second entry point, updateDocValues(Term, Field...), came with LUCENE-5680 (de8e86b5d094227eeca7abf56083ee598687b0e6 on branch_4x / f99a9d7ab0497b88f5a49dbe7b7bbb958756aa1a on trunk) and passes f.binaryValue() into the same constructor.",
   "introduced_date": "2014-03-18 (LUCENE-5513); 2014-05-29 (LUCENE-5680, second entry point)",
   "first_affected_version": "4.8.0 [exec]; 4.9.0 for updateDocValues(Term, Field...) [exec]",
   "affected_versions": "every release from 4.8.0 through 10.5.2 (the last release before 10.6.0) and main a9779ef3c193; never fixed. [exec] 116 releases (4.8.0-4.10.4 and every 5.x, 6.x, 7.x, 8.x, 9.x and 10.x release) plus main, 117 targets, all fail with era-adapted public-API main() programs; the JUnit fails on 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da), and the independent reproduction reproduced 10.5.2 and 9.12.3 with its own test. How it shows: on 4.8.0-7.6.0 every updated document, flushed or buffered, reads the late bytes; from 7.7.0 on (LUCENE-8590, whose FieldUpdatesBuffer copies the bytes when the global slice is applied inside the call) flushed segments get the value as of the call and only documents still buffered in RAM read late bytes; the reused-buffer loop is wrong on every release. [read] upstream main a95c754ee003 (2026-10-26) and branch_10x still store the reference.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-643.html",
   "repro": "repro/LFV-643/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1046",
   "priority": "medium",
   "priority_rank": 18,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter buffered delete terms (DocumentsWriterDeleteQueue.DeleteSlice.apply, BufferedUpdates.DeletedTerms)",
   "title": "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)",
   "summary": "You add a document, call deleteDocuments(new Term(\"id\", t)) with t longer than 32,766 bytes, and commit. No indexed term can be that long, so you expect the delete to match nothing (as it did up to 9.8.0) or to be rejected, and the commit to contain the document. Instead the delete throws BytesRefHash.MaxBytesLengthExceededException after it was already queued and is never removed from the queue, so every later addDocument and delete throws the same exception and commit() fails (with assertions off an IllegalStateException 'Can't close queue unless all changes are applied', with -ea an AssertionError that closes the writer); the only clean way out is rollback().",
   "impact_class": "index unusable",
   "introduced_commit": "8b84f6c0965dda01514c196126ed10e57cb6d01a (apache/lucene#12573 'Use radix sort to speed up the sorting of deleted terms', gf2121, approved by jpountz; branch_9x backport d3a3391d225e737126428669bb54630d6c93298e) [exec]. It replaced BufferedUpdates' Map<Term,Integer> delete-term buffer (no key-length limit) with per-field BytesRefHash maps on a shared ByteBlockPool, which reject keys over BYTE_BLOCK_SIZE - 2 = 32766 bytes. The queue behaviour that keeps a failing node (append before apply; DeleteSlice.apply resets only after every node applied) dates to LUCENE-2956 (e95097a7c8d, 2011) and 058970e72bd (2016) and did no harm while applying a term node could not throw",
   "introduced_date": "2023-09-22 (author date of 8b84f6c0965 on main, 00:33:01 -05:00; PR merged 2023-09-22T05:33:01Z; backport authored 01:22:15 -05:00 the same day)",
   "first_affected_version": "9.9.0",
   "affected_versions": "[exec] main 645d4fe14a20 (-ea and -da: the finder, the independent reproduction, the cross-model review, the intended-behaviour check, the adjudication and the registration check), 10.6.0 RC1 4ae946e5a9b (plain probe on the core jar: the bad delete, the next addDocument and the NRT reopen fail, committed numDocs 1 of 3 and 0 of 3), and all 22 releases 9.9.0, 9.9.1, 9.9.2, 9.10.0, 9.11.0, 9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0 and 10.5.0-10.5.2 (-da: IllegalStateException 'Can't close queue unless all changes are applied'; -ea also on 9.9.0, 9.12.3 and 10.5.2). [read] upstream main and branch_11x: no change to BufferedUpdates.java or DocumentsWriterDeleteQueue.java since 645d4fe14a20. Not affected [exec]: 9.8.0 (-ea and -da) and 9.7.0 (-da); earlier releases [read] have the HashMap delete-term buffer. Not new in 10.6",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1046.html",
   "repro": "repro/LFV-1046/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-045",
   "priority": "medium",
   "priority_rank": 19,
   "novelty": "new",
   "withheld": false,
   "area": "search / concurrency",
   "title": "IndexSearcher#count hangs forever when Weight#count throws, for example on a query timeout, on a segment split into intra-segment partitions",
   "summary": "You search with an executor and intra-segment partitions (IndexSearcher.slices(..., allowSegmentPartitions=true)) and call IndexSearcher#count, and the first partition of a segment to arrive throws from Weight#count, for example the ExitingReaderException of a stock ExitableDirectoryReader timeout. You expect the exception to propagate, as TaskExecutor#invokeAll promises. Instead TotalHitCountCollectorManager completes the segment's shared future only on success or CollectionTerminatedException, so the other partitions wait in an unbounded get() and the call never returns (with no test hooks, 124/200 and 176/200 calls hung on main, 44/50 on 10.5.2).",
   "impact_class": "hang",
   "introduced_commit": "#13542",
   "introduced_date": "2024-09-10",
   "first_affected_version": "10.0.0 [read]",
   "affected_versions": "10.0.0-10.5.2, branch_10_6 and main (10.1.0, 10.5.2, main [exec])",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-045.html",
   "repro": "repro/LFV-045/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-596",
   "priority": "medium",
   "priority_rank": 20,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter frozen update packets vs. merge carry-over (forceApply, commitMergedDeletesAndUpdates, BufferedUpdatesStream)",
   "title": "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)",
   "summary": "You update a document's doc-values field (updateNumericDocValue, updateDocValues) or replace a document with softUpdateDocument while background merges run; IndexWriter returns a sequence number, so every later NRT reader and commit should show the change. If the update packet must re-resolve because a merge committed meanwhile and that merge's result was dropped as fully deleted, IndexWriter.forceApply finds no segment left, leaves the IndexWriter lock and only then marks the packet finished; a second merge that commits in that gap treats the packet as still running, skips its already-resolved update on the merged-away segment, and nobody applies it again. The update is silently lost (id 3 keeps value 30 instead of 7, also after commit and reopen), and with softUpdateDocument the old version is never soft-deleted, so two live versions of one document remain.",
   "impact_class": "data corruption",
   "introduced_commit": "58105a203a19d18a56e09cf69dc0083c1b890315 (LUCENE-7868 'use multiple threads to concurrently resolve deletes and DV udpates', GitHub #8919, by mikemccand; JIRA patch reviewed on Review Board r/60154, no pull request): added in one commit the optimistic re-resolve loop, the 'packet matches no segments' break, the post-loop BufferedUpdatesStream#finished and the merge carry-over skip of still-running packets, with every exit finishing outside the IndexWriter lock. The current shape dates from the incomplete fix eaf1d45a1cad (LUCENE-7888, #8939, 2017-07-02, by mikemccand), which moved only the regular exit's finish under the lock and kept an out-of-lock 'if (finished == false)' fallback that the empty exit still reaches; 6f0a884582a (LUCENE-8269) and 8059eea1608 (#1454, 2020, moved the loop into IndexWriter.forceApply, first released in 8.6.0) kept the shape [read]",
   "introduced_date": "2017-06-21 (LUCENE-7868); 2017-07-02 (LUCENE-7888, the incomplete fix that left today's shape)",
   "first_affected_version": "7.0.0 [exec]; 6.6.0 and 6.6.6, the last releases before, resolve deletes and updates inside synchronized IndexWriter methods and have no such exit (controls pass) [exec]",
   "affected_versions": "every release from 7.0.0 through 10.6.0 (10.6.0 by reading) and main a9779ef3c193, never fixed. [exec] the doc-values variant fails on 7.0.0 (-ea/-da), 7.3.1, 7.4.0, 7.7.3, 8.0.0, 8.5.2, 8.6.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea/-da); the softUpdateDocument variant fails on every executed release from 7.4.0 (the first with softUpdateDocument) and main; 6.6.0 and 6.6.6 controls pass; the cross-model review and the intended-behaviour check re-ran 10.5.2. Release runs use version ports that differ only where the API forces it, all force the window deterministically, and were run on JDK 25; the natural hit rate was measured on main only. [read] a source scan of every release tag 7.0.0-10.5.2 finds the empty-exit break, the post-loop conditional finish and the carry-over still-running skip (8.8.2-8.11.3 untagged in the history clone, inferred between 8.8.1 and 8.11.4). Not fixed on upstream main a95c754ee003, branch_10x or branch_10_6 (2026-10-26) [read].",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-7888",
    "https://github.com/apache/lucene/issues/8939",
    "https://issues.apache.org/jira/browse/LUCENE-7868",
    "https://github.com/apache/lucene/issues/8919",
    "https://github.com/apache/lucene/issues/16570",
    "https://github.com/apache/lucene/issues/16571"
   ],
   "doc": "",
   "repro": "repro/LFV-596/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-002",
   "priority": "medium",
   "priority_rank": 21,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter merge",
   "title": "Merge doc-values carry-over (#16570) can lose an acknowledged update or close the writer on a duplicate delGen",
   "summary": "While a merge runs, a document in a merging segment gets an older doc-values update that is still being applied and a newer update to the same segment and field that finishes first. You expect the newest value to win on the merged segment. Instead the merge gives the carried-over on-disk value a delGen at or above the in-flight packet's, so the older value silently wins and survives commit and reopen, or, with assertions on and equal gens, a duplicate-delGen assertion closes the writer and discards uncommitted changes.",
   "impact_class": "data corruption",
   "introduced_commit": "#16570 (9092bda09d on main); backport #16591 (4b1ed860c1, base branch_10x, inherited by branch_10_6)",
   "introduced_date": "2026-09-01 (#16570 merged); 2026-09-07 (#16591 merged)",
   "first_affected_version": "10.6.0 (released 2026-10-29) only with opt-in overlays; unreleased main with any overlays setting",
   "affected_versions": "main b83101cdd2: yes with any maxDocValuesOverlays, 0 included [exec]; branch_10_6 d04ee73177: only with setMaxDocValuesOverlays(n>0), new and experimental in 10.6.0 [exec]; 10.5.2: no, the code is absent [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-002.html",
   "repro": "repro/LFV-002/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b): 2 of 8 fail with -ea and -da, with the opt-in setMaxDocValuesOverlays(n > 0); 10.5.2 does not have the code."
  },
  {
   "id": "LFV-451",
   "priority": "medium",
   "priority_rank": 22,
   "novelty": "new",
   "withheld": false,
   "area": "index / soft deletes (tryUpdateDocValue un-delete vs. a running merge's carry-over)",
   "title": "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",
   "summary": "With a soft-deletes field, you soft-delete a document and later restore it with tryUpdateDocValue(reader, docID, <soft-deletes field = null>) while a merge of its segment is running. You expect what the javadoc promises: the segment has not been merged away, so the update succeeds and returns a sequence number > 0 and the document stays live (otherwise the call returns -1 and you retry). Instead the call does return > 0 and NRT readers show the document again, but the merge, which already treated it as deleted and left it out, commits without it, so the restored document disappears with no error and the next commit persists the loss.",
   "impact_class": "data corruption",
   "introduced_commit": "a3c86373e47ddd43368c5800eea63b50d2064759 (master, which became 8.0) and its branch_7x backport 0c65af048b3a497ea2e95e48c886b3a653412a0c (first released in 7.4.0): LUCENE-8298 'Allow DocValues updates to reset a value', now apache/lucene#9345, by s1monw (JIRA patch reviewed on JIRA, no GitHub PR) [exec] [read]; it was the last of four ingredients: try* applies to any segment still in segmentInfos (LUCENE-4203, 2012; shared with tryUpdateDocValue by LUCENE-8297, #9344, b0b32931b28d / 48a2138e899, same release), merges drop non-retained soft-deleted documents (LUCENE-8233, ecc17f90233), and the carry-over skips source documents without a merged docID (LUCENE-5248 / LUCENE-7868; kept by the unreleased main rewrite #16570, 9092bda09d6)",
   "introduced_date": "2018-05-09 (committed on master and branch_7x; authored 2018-05-07)",
   "first_affected_version": "7.4.0 [exec]; 7.3.1 and earlier have no soft deletes, no tryUpdateDocValue and no null doc-values reset [exec]",
   "affected_versions": "every release from 7.4.0 through 10.5.2 and main ea57360912ed. [exec] all 67 releases 7.4.0-10.5.2 and main lose the un-delete with the portable main() probe, controls passing on every one (history step, -ea; -da also on 7.4.0, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main); the finder's JUnit fails on main (-ea, -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit on main (-ea, -da), 10.5.2 (-ea, -da), 9.12.3 (-ea, -da), 9.0.0 and 8.11.4; the intended-behaviour check's probe on main (-ea, -da), 10.5.2, 9.12.3, 8.11.4 and 7.4.0. Not executed: 10.6.0 / branch_10_6, x86, JDKs other than 25 (all runs aarch64, JDK 25). No upstream fix as of 2026-10-26 (upstream main 49483e82b357 has no later commit touching the files involved).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-451.html",
   "repro": "repro/LFV-451/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-110",
   "priority": "medium",
   "priority_rank": 23,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter doc-values update write path (ReadersAndUpdates.writeFieldUpdates, the checkpoint after writeReaderPool, IndexFileDeleter reference counts)",
   "title": "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",
   "summary": "You update a doc-values field (updateNumericDocValue, updateBinaryDocValue, or a soft delete) and open an NRT reader, flush or commit, and the doc-values update write throws a non-tragic IOException after the new files were already published into the segment's SegmentCommitInfo (re-opening the writer's pooled segment reader fails, or a second segment's update write in the same batch fails); the writer stays open (isOpen() true, no tragic exception) and you keep using it. You expect the acknowledged update to reach the next NRT reader and commit, and every file the writer's SegmentInfos references to stay on disk, as in 6.x and as the since-deleted test testNoLostDeletesOrUpdates required. Instead the writer skips its IndexFileDeleter checkpoint and keeps a stale pooled reader whose pending update was already pruned: in releases (and on main with maxDocValuesOverlays=0) the next update rewrites the column from that stale reader and a later commit succeeds with the update reverted (doc 0 = 0 instead of 100, no exception), while with overlays (main's default) or on the partial-batch path the writer later deletes the published files and NRT opens or commits fail with NoSuchFileException. On main's default config the silent revert happens too when the next step is a merge of that segment, for example forceMerge(1): the merge reads the stale pooled reader, the published overlay files are no longer referenced, and the following commit succeeds with the old value and a clean CheckIndex.",
   "impact_class": "data corruption",
   "introduced_commit": "Part A (a failed re-open loses the update): 58105a203a1 on master, LUCENE-7868 = apache/lucene#8919 'use multiple threads to concurrently resolve deletes and DV udpates' (mikemccand), a performance change that prunes the resolved updates right after the write and before the re-open; its parent 1737fce5df1 is correct [exec]. Part B (a partial-batch failure deletes still-referenced files): LUCENE-8232 = #9279 'Separate out PendingDeletes from ReadersAndUpdates' (s1monw), a refactoring that removed writer.checkpointNoSIS() from the end of writeFieldUpdates and left the checkpoint to callers that checkpoint only on normal return: branch_7x d47931c4b8a (parent 2caf52587cd correct for part B) and master acb3c379427 (parent ab092942cf6) [exec]. Patch era, no pull requests. Later changes that kept the outcome: #13017 (47792dfcd3c / fc9d6770a55, moved the re-open after publication; 9.10.0 and 9.11.0 behave identically [exec]) and #16418 (75eddfaff22, overlays on by default on main: part A's default symptom became a deleted, still-referenced file [exec])",
   "introduced_date": "2017-06-21 (part A, LUCENE-7868); 2018-03-29 (part B, LUCENE-8232)",
   "first_affected_version": "7.0.0 for part A and 7.4.0 for part B [exec]; 5.5.5, 6.6.0 and 6.6.6 are correct for both parts [exec]; doc-values updates exist since 4.6.0, and 4.6.0-5.4.x (read only: 4.6.0, 4.8.0, 4.10.4) have the same safe publish-checkpoint-re-open order as 6.x",
   "affected_versions": "Part A (lost update after a failed re-open): every release from 7.0.0 through 10.5.2 [exec], 10.6.0 (released 2026-10-29; branch_10_6 head 2763db11b0a: default config = lost update, overlays opted in = deleted file) and main ea57360912ed (default = deleted, still-referenced file; maxDocValuesOverlays=0 = lost update) [exec]. Part B (deleted still-referenced files): every release from 7.4.0 through 10.5.2 [exec], 10.6.0 (branch_10_6 head 2763db11b0a) and main [exec]. -ea and -da give the same results. Not affected: 5.5.5, 6.6.0 and 6.6.6 (both parts), 7.0.0-7.3.1 for part B [exec]. Not run: 4.6.0-5.4.x (the probe needs the 5.x API), 8.8.2-8.11.3 individually (8.11.4 run). Not fixed upstream at ea57360912ed: no later commit on main, no commit on branch_10x or branch_10_6 and none of the 412 open PRs change the fix sites [read]; on main e1faeba08bd (2026-11-02) with the default config (overlays on) a forceMerge(1) after the failed re-open also persists the reverted update silently [exec].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9738",
    "https://issues.apache.org/jira/browse/LUCENE-8692",
    "https://issues.apache.org/jira/browse/LUCENE-5263",
    "https://github.com/apache/lucene/issues/6327",
    "https://issues.apache.org/jira/browse/LUCENE-5189",
    "https://issues.apache.org/jira/browse/LUCENE-7868"
   ],
   "doc": "",
   "repro": "repro/LFV-110/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-473",
   "priority": "medium",
   "priority_rank": 24,
   "novelty": "known",
   "withheld": false,
   "area": "index / DocumentsWriter full flush (DocumentsWriterFlushControl.abortFullFlushes, blockedFlushes) and the error paths of IndexWriter.getReader and prepareCommit",
   "title": "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",
   "summary": "One thread opens an NRT reader from the IndexWriter (or commits) while other threads keep indexing, and the reopen or commit fails after its flush with an ordinary, non-tragic exception, for example an I/O error while opening a segment file; the writer stays open and the other threads' updateDocument and addDocument calls returned normally with sequence numbers. You expect those changes in the next commit, whose sequence number covers them, and updateDocument to stay atomic. Instead Lucene discards the per-thread buffers that filled up and were parked during the failed full flush, so the added documents never reach the index, and the update keeps only its delete, so the updated document disappears entirely.",
   "impact_class": "data corruption",
   "introduced_commit": "7f22bd1118de (LUCENE-3028, apache/lucene#4102, s1monw, realtime_search branch): swaps in the new delete queue inside markForFullFlush, so the DWPTs blocked during a full flush are new-queue DWPTs, clears both queues in abortFullFlushes and lets getReader call finishFullFlush(success) itself; on top of e95097a7c8df (LUCENE-2956, #4030), which added blockedFlushes, finishFullFlush and abortFullFlushes; both reached trunk with 2a969f828c1b (LUCENE-3023 'Land DWPT on trunk', #4097) [read]. The main-branch reader-open trigger reaches the abort since 80e5fbc7a8c2 (LUCENE-6214, #7276, mikemccand), which moved getReader's success flag after the reader open as part of a deadlock fix [exec]",
   "introduced_date": "2011-04-14 (realtime_search branch; e95097a7c8df 2011-04-13); 2011-05-01 on trunk; the reader-open trigger since 2015-02-01 (LUCENE-6214)",
   "first_affected_version": "4.0.0 [exec]; the reader-open trigger from 4.10.4 and 5.0.0 [exec]",
   "affected_versions": "[exec] fails on 4.0.0, 4.10.3, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.4.0, 7.7.3, 8.7.0, 8.11.4, 9.12.3, 10.0.0, 10.5.2 and main ea57360912ed (main with -ea and -da; 10.5.2 and 9.12.3 also by the independent reproduction and the intended-behaviour check). Triggers by version: 4.0.0-4.10.3 only a failure inside the full flush's own DWPT flush (4.10.3 passes the reader-open variant); 4.10.4 and 5.0.0 on an I/O error while the NRT reader opens; 7.4.0 on also MergePolicy#keepFullyDeletedSegment failing while commit publishes (7.3.1 lacks the API); 8.7.0 on also MergePolicy#findFullFlushMerges(GET_READER) failing (8.6.3 lacks the API; merge-on-refresh is on by default from 9.3.0). Since 5.0.0 (LUCENE-5987) a failure inside a DWPT flush closes the writer, so that 4.x trigger is documented loss from then on. [read] every release tag 4.0.0-alpha..8.8.1 and 9.0.0..10.5.2 in the history clone aborts blockedFlushes in abortFullFlushes while finishFullFlush queues them; 8.8.2-8.11.3 are not in the clone (8.11.4 executed). Also failing: main e1faeba08bd [exec] and the 10.6.0 release jars [exec]. Not fixed upstream: #16867 (2813efa40a3) only appended updateStallState() to abortFullFlushes; main e1faeba08bd, branch_11x da3ea39fa59 and branch_10_6 91eaab4fb29 still abort blockedFlushes [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16867",
    "https://github.com/apache/lucene/issues/9738",
    "https://issues.apache.org/jira/browse/LUCENE-8692",
    "https://github.com/apache/lucene/issues/4220",
    "https://issues.apache.org/jira/browse/LUCENE-3147",
    "https://github.com/apache/lucene/issues/11126"
   ],
   "doc": "",
   "repro": "repro/LFV-473/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1078",
   "priority": "medium",
   "priority_rank": 25,
   "novelty": "known",
   "withheld": false,
   "area": "index / DocumentsWriter flush failure handling (DocumentsWriter.doFlush, DocumentsWriterPerThread.prepareFlush, DocumentsWriterDeleteQueue.freezeGlobalBuffer)",
   "title": "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",
   "summary": "You buffer a document, a delete and doc-values updates in an IndexWriter, and commit() fails with an ordinary exception while the in-memory segment is being prepared for flushing (executed: ArithmeticException 'integer overflow' after about 2.2 million updateNumericDocValue calls on a 1 KB id); the writer stays open and reports no tragic exception. You expect either the writer to close itself, as it does for every other failure while flushing a segment, or the next successful commit (or close()) to contain every operation its returned sequence number covers. Instead the failed flush has already taken the buffered deletes and updates out of the shared delete queue and then drops them together with the in-memory segment, so the next commit silently lacks the buffered document, keeps the deleted document live and holds a stale doc-values value.",
   "impact_class": "data corruption",
   "introduced_commit": "b88d3e19889f (apache/lucene#12392 'Catch offset overflows in byte pool (#9660)'; 9.x backport 445b30d421c7) is the exposing change and correct in itself: ByteBlockPool.nextBuffer's Math.addExact makes the 2 GiB overflow of this workload throw inside prepareFlush (non-tragic, silent loss) instead of failing later in FrozenBufferedUpdates.applyDocValuesUpdates via IndexWriter.forceApply (tragic close, nothing lost) [read]. The handling defect itself (prepareFlush freezes the global buffer before it applies the per-thread slice, doFlush handles a failure only for a non-null ticket, and the finally drops the DWPT) dates from e95097a7c8df (LUCENE-2956 'Support updateDocument() with DWPTs', realtime_search branch, 2011-04-13; trunk with LUCENE-3023), restructured without semantic change by LUCENE-3692 (ed4894dd8fb, 2012-01-16), #12647 (268dd54a869, 2023-10-12) and #14913 (27d1272984f, 2025-07-14) [read]",
   "introduced_date": "2023-06-28 (author date of b88d3e19889f and 445b30d421c7, the exposing change); the handling defect 2011-04-13 (e95097a7c8df, LUCENE-2956)",
   "first_affected_version": "9.8.0 [exec]; for the prepareFlush step the handling defect is latent from 4.0.0-alpha (3.6.2 does not contain it) through 9.7.0, with no public-API trigger known there [read]; for a second unguarded step of the same handling it is not latent: an InfoStream that throws on DocumentsWriterPerThread.flush's first message ('flush postings as segment') loses the in-memory segment's documents from 4.0.0 on [exec]",
   "affected_versions": "[exec] the claimed JUnit fails on 9.8.0 (-ea and -da), 9.9.0, 9.12.3, 10.0.0 and 10.5.2 (-da), 10.6.0 (released 2026-10-29, 4ae946e5a9b; -ea and -da) and main 645d4fe14a20 (-ea and -da); the independent reproducer's own JUnit fails on main (-ea, -da), 10.6.0 (-ea, -da), 10.5.2, 9.12.3 and 9.8.0; 9.7.0 passes (-ea and -da: the first commit throws ArrayIndexOutOfBoundsException -65536 and the writer closes itself, nothing is lost). [read] every release from 9.8.0 to 10.6.0 by tag scan (Math.addExact present, same null-ticket handling, no tragic event for prepareFlush). Not new in 10.6. Not fixed upstream: GitHub compare 645d4fe14a20 to upstream main e1faeba08bd (2026-11-02, 15 commits) touches no DocumentsWriter* file except DocumentsWriterFlushControl.java (#16867, the shared delete-buffer cap, which does not touch this path; a re-run with f815e679bf6's DocumentsWriterFlushControl.java as a shadow class gives the same result) and neither ByteBlockPool nor IndexWriter; second trigger (an InfoStream that throws on 'flush postings as segment', 2026-11-02): one JUnit fails on main e1faeba08bd, 10.6.0, 10.5.2 and 9.12.3 with -ea and -da, and a main() port fails with -da on 9.0.0, 8.11.4, 7.7.3, 6.6.6, 5.5.5, 5.0.0, 4.10.4 and 4.0.0 [exec]; the log line has sat before the flush's guarded block since the per-thread flush was introduced (LUCENE-2324, realtime branch, 2010) [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9738",
    "https://issues.apache.org/jira/browse/LUCENE-8692",
    "https://github.com/apache/lucene/issues/14261",
    "https://github.com/apache/lucene/issues/10661",
    "https://github.com/apache/lucene/issues/7049",
    "https://issues.apache.org/jira/browse/LUCENE-5987"
   ],
   "doc": "",
   "repro": "repro/LFV-1078/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-843",
   "priority": "medium",
   "priority_rank": 26,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter full flush (DocumentsWriter.flushAllThreads naked-delete freeze, DocumentsWriterDeleteQueue.close)",
   "title": "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)",
   "summary": "You commit documents id:1 and id:2, call deleteDocuments(id:1) and updateNumericDocValue(id:2, dv, 22) (both return sequence numbers), and then open an NRT reader from the writer or call commit() with no documents buffered, and an OutOfMemoryError strikes while the writer freezes those two buffered changes; the IndexWriter javadoc says the writer closes itself after an Error, so you expect to see the Error and a closed writer (or, if the writer stays usable, a later commit that contains both changes). Instead the finally of DocumentsWriter.flushAllThreads closes the delete queue that the flush has already swapped out, and its close() throws IllegalStateException(\"Can't close queue unless all changes are applied\"), which replaces the Error; IndexWriter does not treat that as tragic and stays open, the old queue with both changes is abandoned, and the next commit() returns -1 with id:1 still live and dv(id:2) still 2. With -ea an AssertionError ('Can not replace a full flush queue if the queue is not closed') replaces the Error instead, and since 10.0.0 it closes the writer.",
   "impact_class": "data corruption",
   "introduced_commit": "165d2d5ff53114613054e7b7df641618d99d3e5b (master: the first commit of apache/lucene-solr PR #688 'LUCENE-8813: Ensure we never apply deletes from a closed DWPTDeleteQueue' by Simon Willnauer (s1monw), approved by dnhatn, mikemccand and danmuzi, merged through b28de243be3; JIRA LUCENE-8813 'testIndexTooManyDocs fails', now apache/lucene#9857) and its branch_8x squash 4f79fdc709911277241c5427b3d063ade9b01b7d (the commit 8.2.0 ships) [exec]. It added flushingDeleteQueue.close() to flushAllThreads' finally, the throwing DocumentsWriterDeleteQueue.close() and the setFlushingDeleteQueue assertion; the freeze-before-clear order in the global-buffer freeze is older (present at 8.1.1). Older, separate ingredient [exec]: on 8.1.1 a RuntimeException thrown at the same point already left the writer open and dropped the swapped-out queue's changes; LUCENE-8813 sent the realistic Error case down that non-tragic path. #13277 (9af3ef89525, Robert Muir, 2024-04-23, 10.0.0) changed only the -ea outcome (the replacing AssertionError became tragic)",
   "introduced_date": "2019-05-28 (author date of 165d2d5ff53); landed on master (merge b28de243be3) and on branch_8x (4f79fdc7099) on 2019-06-01",
   "first_affected_version": "8.2.0 [exec] (8.1.1, the last release before LUCENE-8813, is not affected [exec]: the Error reaches the caller and the writer closes itself, with the injected Error (-ea and -da) and with a real OutOfMemoryError, 3/3 launches)",
   "affected_versions": "every release 8.2.0-8.11.4, 9.0.0-9.12.3 and 10.0.0-10.5.2, 10.6.0 (by reading), and main a9779ef3c193 [exec]; the releases in between by git tag --contains (8.2.0-8.8.1 contain 4f79fdc7099, every 9.x and 10.x tag contains 165d2d5ff53; 8.8.2-8.11.3 are not tagged in the history clone) [read]; not fixed upstream: upstream main 20ced71c1e6, branch_10x 1309534296e and branch_10_6 2763db11b0a have the same flushAllThreads and DocumentsWriterDeleteQueue.java [read], and no open PR changes that code; both files are unchanged from 2763db11b0a to the 10.6.0 commit 4ae946e5a9b, so the released 10.6.0 has it. All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16923",
    "https://github.com/apache/lucene/issues/16810",
    "https://github.com/apache/lucene/issues/16867",
    "https://github.com/apache/lucene/issues/9259",
    "https://issues.apache.org/jira/browse/LUCENE-8212",
    "https://github.com/apache/lucene/issues/13277"
   ],
   "doc": "",
   "repro": "repro/LFV-843/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-195",
   "priority": "medium",
   "priority_rank": 27,
   "novelty": "known",
   "withheld": false,
   "area": "search / phrase queries (ExactPhraseMatcher maxFreq and merged impacts, PhraseScorer TOP_SCORES pruning)",
   "title": "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",
   "summary": "You index text with an analyzer that can put the first word of a phrase twice at one position (for example KeywordRepeatFilter plus a stemmer, or index-time synonyms queried through QueryBuilder) and run an exact phrase search with IndexSearcher#search(q, n); you expect the same top hits as scoring every match. ExactPhraseMatcher counts such a phrase occurrence once per copy of the first word, so the document's phrase freq is 2, but the bound it reports for skipping work (maxFreq() and the block impacts behind getMaxScore) is the smallest term freq, 1. Once more than 1000 hits are counted the searcher skips documents whose real score is competitive: in the repro search(q, 1) returns doc 0 although exhaustive scoring ranks doc 1100 first, with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "c95dc6d95743f4a9a1ffe9baa04c3a9d1e3acdf9 (LUCENE-7993 'Faster phrases if total hit counts are not required', jpountz, 2017-12-29; a JIRA patch, migrated as apache/lucene#9041; parent b2f248164c1a): it added TOP_SCORES pruning to the exact phrase scorer with the minimum term freq as the bound, the first code that relies on phrase freq <= min term freq [exec]. getMaxScore part: LUCENE-8311 'phrase impacts' (apache/lucene-solr PR #760, 2019-07-09; d271770ed133 on branch_8x, cfac486afd7b on the main line) made the merged phrase impacts take the minimum freq [exec]. The precondition, one match per lead occurrence, is older and known: since LUCENE-6260 (fd8c4b31201, 5.1.0) for PhraseQuery [read] and for MultiPhraseQuery unions since at least 2011 (#4103). LUCENE-8249 (7d9059ef13d) later moved the bound into PhraseMatcher#maxFreq, and LUCENE-8060 (99dbe936818) made IndexSearcher#search(q, n) switch to TOP_SCORES after 1000 hits, both in 8.0.0 [read]",
   "introduced_date": "2017-12-29 (LUCENE-7993: TOP_SCORES top-hit loss); 2019-07-09 (LUCENE-8311: getMaxScore below score())",
   "first_affected_version": "8.0.0 [exec] for the TOP_SCORES top-hit loss (7.7.3 passes [exec]); 8.2.0 [exec] for the getMaxScore/impacts part (8.0.0, 8.1.0 and 8.1.1 hold that bound [exec]; 9.0.0 is the first main-line release with it)",
   "affected_versions": "Every release from 8.0.0 to 10.6.0 (10.6.0 by reading) and main ea57360912ed; the getMaxScore part from 8.2.0. [exec] seed DEADBEEF unless stated: a main() port of the independent reproduction's checks fails with -da on 8.0.0 (also -ea), 8.1.0 and 8.1.1 (the three TOP_SCORES checks; getMaxScore holds) and on 8.2.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (all four checks), every control passing; the finder's JUnit fails 5 of 5 on main (-ea, -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 5 of 9 on main (-ea, -da), 10.5.2 and 9.12.3; the intended-behaviour check's fails 4 of 4 on main (-ea, -da) and 10.5.2; the adjudication re-ran the independent reproduction's on main (-ea, -da) and 10.5.2 (-da) with seed 5EED1234 (5 of 9 fail each). Commit level: 8.0.0-SNAPSHOT at the parent b2f248164c1 passes and at c95dc6d9574 fails (-da). Not affected: 7.7.3 [exec] and every earlier release, which had no TOP_SCORES pruning (IndexSearcher#search scored every hit), although the over-count itself is visible there (phrase freq 2.0). Releases between the executed points [read]: all 51 release tags from 8.0.0 to 10.5.2 in the history clone contain c95dc6d9574 (8.8.2-8.11.3 are untagged there and lie on the 8.x line between 8.8.1 and the executed 8.11.4), and the min-of-freqs bound never changed (git log -S). Not fixed: ExactPhraseMatcher is the same on upstream main, branch_10x, branch_10_6 and branch_10_5, and no open PR changes the bound (read-only check 2026-10-26).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/4103",
    "https://issues.apache.org/jira/browse/LUCENE-3029",
    "https://github.com/apache/lucene/issues/9041",
    "https://issues.apache.org/jira/browse/LUCENE-7993",
    "https://github.com/apache/lucene/issues/9358",
    "https://issues.apache.org/jira/browse/LUCENE-8311"
   ],
   "doc": "",
   "repro": "repro/LFV-195/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-319",
   "priority": "medium",
   "priority_rank": 28,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / classic MultiFieldQueryParser (getFieldQuery(String,String,boolean) per-field clause grouping and getMultiTermPositionQuery; core util/QueryBuilder graph phrases)",
   "title": "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",
   "summary": "You search the fields title and body with MultiFieldQueryParser under AND_OPERATOR and expect what its class javadoc promises: every query term must appear, in any field, so adding a field never loses a document that QueryParser on one of those fields finds. Instead getFieldQuery takes clause i of each field's analyzed BooleanQuery as 'term position i' and requires every such group: with title tokenized on whitespace and body on letters, 'wi-fi router' becomes +(title:wi-fi body:wi) +(title:router body:fi) +(body:router), which misses a document titled 'wi-fi router' and matches one with title 'router' and body 'wi router' (released since 6.2.0, default settings since 7.0.0; since #16446 the single word 'wi-fi' loses the match too). Since #16446 (in 10.6.0), with autoGeneratePhraseQueries and the multi-word synonym 'guinea pig' -> 'cavy', 'guinea-pig' becomes +(body:\"guinea pig\") +(body:cavy), so even MultiFieldQueryParser over body alone finds nothing where QueryParser(body) finds the document.",
   "impact_class": "silent wrong results",
   "introduced_commit": "Two starts, one root cause. (1) The grouping: 17d113dac1e6 (master) / 7d092fac4ea (branch_6x), LUCENE-2605 'queryparser parses on whitespace' (apache/lucene#3679, 2016-07-05) added the termNum loop in MultiFieldQueryParser.getFieldQuery that ORs clause termNum of every per-field BooleanQuery across fields; for multi-word input with splitOnWhitespace=false, QueryParser's MultiTerm rule and addMultiTermClauses then made each group required under AND (opt-in in 6.2.0; default from 7.0.0, when 24e5c1c2058 made splitOnWhitespace=false the default). (2) c71ef11c549d (apache/lucene#16446, fixes #16443, merged 2026-10-22; backported to branch_10_6 as 88c0bd4c346) added getMultiTermPositionQuery, which combines the groups of one getFieldQuery call with the default operator (MUST under AND) and removed addMultiTermClauses: QueryBuilder.analyzeGraphPhrase's SHOULD alternatives and unaligned single-token per-field lists became required groups. [exec]",
   "introduced_date": "2016-07-05 (LUCENE-2605, 17d113dac1e) for the per-field grouping with multi-word input (released in 6.2.0, default settings from 7.0.0); 2026-10-22 (#16446, c71ef11c549 and the branch_10_6 backport 88c0bd4c346) for graph alternatives and single-token per-field input",
   "first_affected_version": "6.2.0 [exec] for per-field analyzers with multi-word input and setSplitOnWhitespace(false); 7.0.0 [exec] under default parser settings (splitOnWhitespace=false became the default). Graph alternatives and single-token per-field input: 10.6.0 (released 2026-10-29; main and branch_10_6 since #16446; 10.5.2 and 9.12.3 pass [exec])",
   "affected_versions": "Per-field analyzers, multi-word input: every executed release from 6.2.0 to 6.6.6 with setSplitOnWhitespace(false) and from 7.0.0 to 10.5.2 under default settings, and main [exec]; 6.0.0 to 6.1.0 not affected (no splitOnWhitespace option, whole per-field queries ORed) [exec]. Graph alternatives and single-token per-field input: main ea57360912ed [exec] and branch_10_6 head 2763db11b0a [exec]; no release before 10.6.0 [exec]. On releases up to 10.5.2 the single-token per-field input over-matches instead (the #16443 symptom that #16446 fixed; not counted here). The over-match of the per-field half reproduces on main (-ea and -da), 10.5.2 and 9.12.3 [exec]. Not fixed upstream: the newest commits on MultiFieldQueryParser.java are #16446 on main (c71ef11c549) and branch_10_6 (88c0bd4c346), and no open PR touches the file (413 open PRs scanned, 2026-10-26) [read]. All runs on JDK 25, aarch64 Linux, not each release's own JDK.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-319.html",
   "repro": "repro/LFV-319/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1136",
   "priority": "medium",
   "priority_rank": 29,
   "novelty": "new",
   "withheld": false,
   "area": "core document / LatLon distance sort (LatLonPointDistanceComparator.setBottom: sampled competitive bounding box)",
   "title": "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)",
   "summary": "You search with Sort(cat INT, LatLonDocValuesField.newDistanceSort(\"loc\", 0, 0)), so distance only breaks ties of cat, over 1026 documents: docs 0..1023 each have a smaller cat than the one before (so each becomes the new top hit) and lie about 1 km from the origin, and docs 1024 and 1025 share the smallest cat, with doc 1025 (about 1500 km away) closer than doc 1024 (about 2000 km). You expect doc 1025 as the top hit, because Sort says a later SortField breaks ties and the distance sort orders by ascending distance. You get doc 1024, with no error: after 1024 bottom updates the comparator rebuilds its competitive bounding box only on every 64th update, so it keeps the 1 km box built for the old bottom, and compareBottom rejects doc 1025 as outside that box without computing its distance.",
   "impact_class": "silent wrong results",
   "introduced_commit": "e169050dc3fe3418947b88948827141dcb3911c2 ('LUCENE-7099: speed up embarrasingly slow sandbox/ distance sort', Robert Muir (GitHub rmuir), master) and its branch_6x copy a4722845e3080dac06c59ca9837a602cf85f3e17 (the one in 6.1.0); no PR (JIRA LUCENE-7099, migrated as apache/lucene#8154): it added the bounding-box rejection in compareBottom together with the sampling guard 'if (setBottomCounter < 1024 || (setBottomCounter & 0x3F) == 0x3F)' in setBottom, commented as protection against 'a worst case order (e.g. backwards distance order)' [read]. Later edits (LUCENE-7103, -7104, -7123, -7184, -7240, -7407, -7314 and the 2020 reformat 2d6ad2fee6d) kept the guard. Not a regression: wrong since the first release with the API",
   "introduced_date": "2016-03-11 (author date of e169050dc3f and a4722845e30)",
   "first_affected_version": "6.1.0 [exec] (the first release with any LatLon distance sort, then in lucene-sandbox; in lucene-core from 7.5.0 [exec], after LUCENE-7314 (#8368) moved the class); 6.0.0 and 6.0.1 have no LatLonDocValuesField or LatLonPointDistanceComparator (the history program does not compile there) [exec], so there is no earlier correct release",
   "affected_versions": "every release from 6.1.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT). Executed: the finder's one-test JUnit, an earlier form of the minimal repro (fillers at 0.009 degrees, NoMergePolicy and the default codec set explicitly), fails on main (-ea and -da; finder, the independent reproduction, the intended-behaviour check, the adjudication and a separate re-run) and on 10.6.0 (-da; finder, the intended-behaviour check); the minimal repro fails on main (-ea and -da) [exec]; the independent reproduction's own test fails on main (-ea and -da) and on 10.6.0, 10.5.2, 10.0.0 and 9.12.3 (-da); the follow-up's main() form of that earlier test (same 1026 documents, sort and expected top hit) fails on 6.1.0, 6.2.0, 6.6.6, 7.4.0, 7.5.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2, 10.6.0 and main [exec]; the releases in between by code identity (every releases/* tag from 6.1.0 to 10.6.0 in the history clone contains e169050dc3f or a4722845e30, and the guard line is unchanged) [read]. Not affected: 6.0.x (API absent) [exec]. Not new in 10.6 (10.5.2 and older fail). Not fixed upstream: the last upstream commit on LatLonPointDistanceComparator.java is still 2d6ad2fee6d (author date 2020-12-23, reformatting), with upstream main at 1c2072f02843 (author date 2026-11-02), and no open PR touches it [read]. Executed on Linux aarch64 with JDK 25.0.3 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1136.html",
   "repro": "repro/LFV-1136/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-242",
   "priority": "medium",
   "priority_rank": 30,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / document (NRT) suggester (NRTSuggester.getMaxTopNSearcherQueueSize via SuggestIndexSearcher and CompletionQuery; Util.TopNSearcher queue depth)",
   "title": "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",
   "summary": "You index suggestions with SuggestField, delete one document or update it (which deletes the old version), and ask SuggestIndexSearcher.suggest for the top n completions; you expect the top n live completions, because NRTSuggester enlarges its bounded search queue 'to account for the filtered out suggestions' of deleted documents. With few deletions that enlargement, (long)(topN / liveDocsRatio), rounds back down to topN (for one deletion in ten documents, (long)(1 / 0.9) = 1), so a deleted completion that takes a result slot is thrown away and nothing replaces it: with abc_0, the best of abc_0..abc_9 in one segment, deleted, suggest('abc_', 1) returns [] instead of [abc_1], and after updateDocument lowers the best entry's weight from 1000 to 1, suggest(num=1) returns that entry at weight 1 instead of the live entry at weight 999. Deleting more documents (5 of 10) gives the queue enough room and the same lookup works.",
   "impact_class": "silent wrong results",
   "introduced_commit": "b7adb6ac7704a7e6364ee0d831bf77cf849f2090 (LUCENE-6339 'Added Near-real time Document Suggester via custom postings format' by areek, an svn-era JIRA patch now tracked as GitHub issue #7400, committed to trunk on 2015-03-27 with no pull request; branch_5x backport 40e94c39ad3b0f018ae9647b7d30bd0cfe341d86 on 2015-03-28) [read]. The commit created the whole suggest/document package, including the truncating line. Later edits to getMaxTopNSearcherQueueSize are type-only or formatting (1b9d98d6ec0, #11923, a (long) widening; 2cbf261032d, LUCENE-9570, reformat); LUCENE-6459 (5.3.0) and LUCENE-6858 (5.4.0) changed what topN is and kept the formula. The TopNSearcher bounded queue and its maxQueueDepth == topN last-path shortcut are older (LUCENE-3714 a519b630eea and LUCENE-4481 dc49949558d, 2012) and are correct on their own",
   "introduced_date": "2015-03-27",
   "first_affected_version": "5.1.0 [exec] (the first release with the org.apache.lucene.search.suggest.document package, from the branch_5x backport; the repro fails 2 of 3 there, and passes 3 of 3 with the Math.ceil line shadowed); 5.0.0 has no such package, so the repro does not compile [exec]",
   "affected_versions": "every release from 5.1.0 through 10.5.2 and main ea57360912ed; not fixed in any release or on upstream main as of 2026-10-26 [exec]. Caveats: releases up to 7.7.3 were run on JDK 25 with a JUnit 4 runner, not the JVM they targeted (the control passes in each run); 8.11.4 is not tagged in the history clone and rests on execution only; release branches after 10.5.2 were not checked",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-242.html",
   "repro": "repro/LFV-242/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-225",
   "priority": "medium",
   "priority_rank": 31,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / Thai (ThaiTokenizer#incrementWord skip loop; ThaiAnalyzer and the 'thai' tokenizer SPI)",
   "title": "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",
   "summary": "You index Thai text such as 'ประชุมวันที่ 1 ม.ค.2567' or 'ราคา ฿1,500' with the stock ThaiAnalyzer and expect the year 2567 or the amount 1,500 to be searchable, as they are when written 'พ.ศ. 2567' or 'ราคา 1,500 บาท'. Instead the number never reaches the index: the JDK word BreakIterator returns it together with its leading period or currency sign as one segment ('.2567', '฿1,500'), and ThaiTokenizer skips any segment whose first character is not a letter or digit, so the whole number is thrown away. A TermQuery for 2567 then finds 0 documents instead of 1, with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "6e2f6a69eb0adbefe90798b178e51539ab81aeca (trunk, svn r1579846; LUCENE-4984 / GitHub #6048 'Fix ThaiWordFilter', ThaiTokenizer patch by rmuir, +1 from rjernst and s1monw; pre-GitHub, no PR) and its branch_4x backport 72a0e1d09e421b3cb76dbadd743ec9449ad701d8 (svn r1579855), which shipped in 4.8.0; the commit added ThaiTokenizer with the first-code-point skip loop and switched ThaiAnalyzer to it [read]",
   "introduced_date": "2014-03-21 (trunk commit and branch_4x backport)",
   "first_affected_version": "4.8.0 [exec] (4.7.2, the last release before, has no ThaiTokenizer, and its ThaiAnalyzer, StandardTokenizer + ThaiWordFilter, keeps the numbers [exec])",
   "affected_versions": "every release from 4.8.0 to 10.5.2 (the last release before 10.6.0) and main ea57360912ed: 4.8.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3 and 8.11.4 [exec], 9.12.3, 10.5.2 and main [exec]; all 107 release tags from 4.8.0 to 10.5.2 contain one of the two introducing commits and the loop is identical, ignoring whitespace, in the inspected tags 4.8.0 to 10.5.2 [read]; in 4.8-5.x matchVersion < 4.8 still selected the old, unaffected chain (removed for 6.0 by LUCENE-5969); not fixed upstream: the loop is unchanged on main and branch_10x (newest ThaiTokenizer.java commit b304eeae024, 2026-09-29) and no open PR touches the Thai package [read]. JRE caveat: the drop needs the JDK word BreakIterator to keep the prefix and the number in one segment; executed on JDK 25.0.3, with supplementary runs on OpenJDK 11.0.33 and 17.0.21 that segment the same way; the Java 7/8 JREs of 2014-era users were not tested",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-225.html",
   "repro": "repro/LFV-225/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-305",
   "priority": "medium",
   "priority_rank": 32,
   "novelty": "known",
   "withheld": false,
   "area": "queryparser / classic QueryParser and MultiFieldQueryParser phrase slop (QueryParserBase.getFieldQuery(String,String,int), MultiFieldQueryParser.getFieldQuery and applySlop; core util/QueryBuilder graph and boosted phrases)",
   "title": "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",
   "summary": "You parse \"guinea pig food\"~1 with the classic QueryParser over an analyzer with a multi-word synonym 'guinea pig => cavy' and expect the documented proximity search, the words within one position of each other on every synonym path, as \"pig food\"~1 gives for a phrase without synonyms. Instead the parser analyzes the phrase with its default phraseSlop (0) and applies the explicit ~1 afterwards only to a top-level PhraseQuery or MultiPhraseQuery, so the BooleanQuery of per-path phrases that a token graph produces ('body:\"cavy food\" body:\"guinea pig food\"') and the BoostQuery that a token boost produces ('(body:\"pig food\")^2.0' for \"pig|2.0 food\"~1) keep slop 0, and 'my guinea pig dry food' is not found. The same root cause also over-matches: after setPhraseSlop(1), an explicit exact \"guinea pig food\"~0 is searched with slop 1 and returns extra documents; MultiFieldQueryParser has the graph defect in both directions but not the boost one, because its applySlop unwraps BoostQuery (since 9.6.0, #12196).",
   "impact_class": "silent wrong results",
   "introduced_commit": "Three starts, one per manifestation. (1) MultiFieldQueryParser graph phrases: a81ebce8049 (master) / 0a5300af6cf (branch_6x), LUCENE-7603 'Support Graph Token Streams in QueryBuilder' (apache/lucene#8654; apache/lucene-solr PR #130 merged on branch_6x, #129 for master): graph phrases came back as GraphQuery and QueryParserBase got a branch that re-applied the explicit slop to every path phrase, but MultiFieldQueryParser's own applySlop was not taught about it. (2) QueryParser graph phrases (the headline case, a regression): 96e8f0a0afe (master) / 43317a33f5d (branch_6x), LUCENE-7699 (apache/lucene#8750, JIRA patch, no GitHub PR): analyzeGraphPhrase began returning span queries built with the default slop the parser passes in, so the GraphQuery branch no longer matched; LUCENE-7702 (365a7ac0db3 / f05717d7d19, 44 minutes later) then deleted that already unreachable branch with GraphQuery. (3) Token boosts: 663611c99c7 (master) / 2752d50dd1d (branch_8x), SOLR-12238 (apache/lucene-solr PR #357; CHANGES entry LUCENE-9171 = apache/lucene#10211): analyzePhrase wraps the phrase in BoostQuery when a token boost is not 1, which QueryParserBase does not unwrap. [exec]",
   "introduced_date": "2016-12-26 (LUCENE-7603 author date, merged to branch_6x 2017-01-03) for MultiFieldQueryParser graph phrases; 2017-02-22 (LUCENE-7699) for QueryParser graph phrases; 2020-02-24 (SOLR-12238) for token boosts",
   "first_affected_version": "6.4.0 [exec] through MultiFieldQueryParser (graph phrases; 6.3.0 has no graph-phrase API, the probe does not compile); 6.5.0 [exec] through QueryParser (graph phrases; 6.4.0 and 6.4.2 pass, so a regression); 8.5.0 [exec] for QueryParser token boosts (8.4.1 has no query-time token boosts)",
   "affected_versions": "Graph phrases via QueryParser: 6.5.0 through 10.5.2 and main [exec]. Graph phrases via MultiFieldQueryParser: 6.4.0 through main [exec]. Both directions (explicit ~N under-matching with the default slop 0, explicit ~0 over-matching after setPhraseSlop) fail wherever the graph case fails [exec]. Token boosts via QueryParser: 8.5.0 through main [exec]. Token boosts via MultiFieldQueryParser: 8.5.0 to 9.5.0 only [exec]. Releases between the executed points were not run one by one [read]. The finder's and the independent reproduction's JUnits fail on main (-ea and -da), 10.5.2 and 9.12.3. Not fixed upstream: the newest upstream main commit to QueryParserBase.java, MultiFieldQueryParser.java or QueryBuilder.java is c71ef11c549d (#16446, already in ea57360912ed, no slop change), and no open PR changes their slop handling (read 2026-10-26). All runs on JDK 25, aarch64 Linux, not each release's own JDK.",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-7893",
    "https://issues.apache.org/jira/browse/LUCENE-483",
    "https://github.com/apache/lucene/issues/1561",
    "https://github.com/apache/lucene/issues/12195",
    "https://github.com/apache/lucene/issues/12196",
    "https://github.com/apache/lucene/issues/8750"
   ],
   "doc": "",
   "repro": "repro/LFV-305/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1099",
   "priority": "medium",
   "priority_rank": 33,
   "novelty": "known",
   "withheld": false,
   "area": "analysis / synonyms (SynonymGraphFilter position increments)",
   "title": "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)",
   "summary": "You run 'run the fast' through StopFilter('the') and SynonymGraphFilter with the rule fast -> quick and expect run +1, quick +2, as a non-matching token keeps its hole. Instead you get run +1, quick +1: the match is placed at the end node of the previous output token and the matched token's own position increment is ignored.",
   "impact_class": "silent wrong results",
   "introduced_commit": "unknown (not bisected); [read] present since SynonymGraphFilter was added (LUCENE-6664, 6.4.0), and reported in 2019 (#10028)",
   "introduced_date": "unknown (not bisected)",
   "first_affected_version": "unknown (not bisected); oldest executed 9.12.3 [exec]",
   "affected_versions": "9.12.3 [exec]; 10.5.2, 10.6.0, main 645d4fe14a20 [exec]; main e1faeba08bde with -ea and -da [exec].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/10028",
    "https://issues.apache.org/jira/browse/LUCENE-8985"
   ],
   "doc": "",
   "repro": "repro/LFV-1099/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-358",
   "priority": "medium",
   "priority_rank": 34,
   "novelty": "new",
   "withheld": false,
   "area": "facet / DrillSideways (sequential DrillSidewaysScorer, drill-down-advance strategy, two-phase drill-down dimensions)",
   "title": "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)",
   "summary": "You run DrillSideways without an executor on a DrillDownQuery with two or more dimensions, one of which is a two-phase query such as a distance or range drill-down with a fast-match query or a PhraseQuery, and expect the hits to match every dimension and each dimension's sideways counts to cover the documents that match all the other dimensions. Instead, on a segment with no deleted documents, when that dimension is the second-cheapest by approximation cost and the base query is broad, DrillSidewaysScorer never calls its TwoPhaseIterator#matches(), because the condition 'acceptDocs == null || acceptDocs.get(docID) && (dc.twoPhase == null || dc.twoPhase.matches())' parses as 'acceptDocs == null || (get && matches)'. So every document in that dimension's approximation (inside the bounding box but outside the radius, the phrase words in another order) is treated as matching it, returned as a hit and counted in the facets, while concurrent DrillSideways and plain boolean queries on the same searcher give the correct sets.",
   "impact_class": "silent wrong results",
   "introduced_commit": "8ad6fff42a333d8ddc1dd45702828b1e210808c1 (branch_5x, svn r1688672; first released in 5.3.0), the backport of trunk bc1c535617ba0c366a6ab86d8ad733e7cc784f99 (svn r1688661; first released in 6.0.0): LUCENE-6648 'Remove usage of oal.search.Filter in lucene/facet' (migrated as GitHub issue #7706), patch by GitHub jpountz, +1 by GitHub mikemccand; SVN era, no PR [read] [exec]. A regression: before LUCENE-6648 a custom drill-down Query was consumed through Scorer.nextDoc() (verified matches) and a random-access Filter forced the query-first strategy",
   "introduced_date": "2015-07-01 (both commits; 5.3.0 tagged 2015-08-20)",
   "first_affected_version": "5.3.0 [exec] (last unaffected 5.2.1 [exec]: the same repro source passes there 2 of 2 with -ea and -da and 40 of 40 over 20 seeds, and a strategy probe shows doDrillDownAdvanceScoring running with the phrase dimension as dims[1], so the pass is non-vacuous; DrillSideways and DrillDownQuery#add(String, Query) already existed in 5.2.1; the trunk commit first shipped in 6.0.0)",
   "affected_versions": "every release from 5.3.0 to 10.6.0 (10.6.0 by reading) and main ea57360912ed [read]; executed with repro.sh (seed DEADBEEF, JDK 25.0.3 aarch64, SHA-1-verified release jars, API-adapted sources for old lines): FAIL on 5.3.0 (also -da; 20 of 20 seeds), 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.2, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da), each with the deletion control passing where it exists [exec]; PASS on 5.2.1 [exec]; the independent reproduction's own JUnit fails on 10.5.2 (-ea, -da) and 9.12.3 (-ea), the intended-behaviour check's range-facet variant and the cross-model review's re-run fail on 10.5.2 [exec]. Still unfixed on upstream main e1c4184cb983, branch_10x and branch_10_6 (lines 401-402 there; read 2026-10-26). Not checked: x86, the taxonomy-facet path (same scorer), patch releases not listed",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-358.html",
   "repro": "repro/LFV-358/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-789",
   "priority": "medium",
   "priority_rank": 35,
   "novelty": "known",
   "withheld": false,
   "area": "facet / DrillSideways (sequential query-first scoring: score mode of the base weight and the scorable handed to the hit collector)",
   "title": "Sequential DrillSideways lets a TOP_SCORES hit collector prune the shared base query, so drill-sideways facet counts silently miss matching documents",
   "summary": "You run a sequential DrillSideways search (no executor) with a filter-style base query drilled down to color=red, and pass a TopScoreDocCollectorManager with a finite total-hits threshold (10 in the repro, or IndexSearcher's default 1000) as the hit collector through search(DrillDownQuery, CollectorManager, List). You expect the drill-sideways counts for color to include every document that matches the base query (75 in the repro), as the same search does with an exhaustive hit collector or with the concurrent DrillSideways. Instead the counts are silently too low (11, or 1001 instead of 2250 at threshold 1000): the base query is scored with the hit collector's TOP_SCORES mode and its scorer is handed to the hit collector, whose min-competitive-score updates make the shared base iteration skip documents that the sideways collectors then never see; the top hits are correct.",
   "impact_class": "silent wrong results",
   "introduced_commit": "61f8517000b3af74c0b079e4a5fa81eb870b1c35 (LUCENE-10030, issue #11069, PR #217 by gtroitskiy, merged by gsmiller: lazy score() for near-miss documents in DrillSidewaysScorer.doQueryFirstScoring); branch_8x backport apache/lucene-solr#2542 = c7210e494e165b66673000df6ae43a32702800cf [exec]. The change handed the hit collector ScoreCachingWrappingScorer(baseScorer), which forwards setMinCompetitiveScore to the base scorer, instead of the private ScoreAndDoc scorable whose setMinCompetitiveScore was the Scorable no-op. Older preconditions [read]: the base weight takes the caller's score mode since LUCENE-4100 (4fc5a872ded, 2017-12-07, 8.0.0), and ConstantScoreScorer empties its iterator under TOP_SCORES once minScore > score since LUCENE-8464 (b4449c73e4c, 2018-11-08, 8.0.0). Behaviour-preserving follow-ups: e44636c2808 (LUCENE-10036, #226) and f527eb3b12d (#12407).",
   "introduced_date": "2021-07-26 (main, 61f8517000b); 2021-08-01 (branch_8x backport c7210e494e16); first release 8.10.0 (release artifacts built 2021-09-21)",
   "first_affected_version": "8.10.0 [exec]",
   "affected_versions": "Every release from 8.10.0 through 10.6.0 (10.6.0 by reading) and main a9779ef3c193; not fixed upstream (upstream main f7bcc0abd816 has no lucene/facet commit after a9779ef3c193, and the fix-site lines are identical on branch_10x and branch_10_6). [exec] 8.10.0, 8.11.4, 9.0.0, 9.11.1, 9.12.0, 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.3.0, 10.4.0, 10.5.0, 10.5.2 and main (-ea and -da); [read] 8.10.1, 8.11.0-8.11.3, 9.1.0-9.11.0, 9.12.1-9.12.2, 10.2.1-10.2.2, 10.3.1-10.3.2 and 10.5.1. Trigger surface by release: in 8.10.0-9.11.x also the default search(DrillDownQuery, Collector) and the 2-arg manager search with default hooks (sideways and drill-down counts both low); from 9.12.0, #13568 and #13702 route hits and drill-down facets through MultiCollector(Manager), which forces COMPLETE, so only the 3-arg search and the 2-arg search with a null drill-down facets hook remain affected. A filter/constant-score base fails on every affected release; a minShouldMatch=2 disjunction base passes on 9.12.x and 10.0.0 and fails from 10.1.0 on for the tested data (not bisected). Not affected: 8.9.0 [exec], 8.0.0-8.8.x [read].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15220",
    "https://github.com/apache/lucene/issues/15221",
    "https://github.com/apache/lucene/issues/11069",
    "https://github.com/apache/lucene/issues/217",
    "https://github.com/apache/lucene/issues/11040",
    "https://issues.apache.org/jira/browse/LUCENE-10001"
   ],
   "doc": "",
   "repro": "repro/LFV-789/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-019",
   "priority": "medium",
   "priority_rank": 36,
   "novelty": "new",
   "withheld": false,
   "area": "util / automaton",
   "title": "RegExp no longer parses an escaped range start such as [\\.-z] as a range",
   "summary": "You write a RegexpQuery or RegExp whose character class starts a range with an escaped character, such as [\\.-z]. You expect it to match the range from '.' to 'z', as in 10.1 and java.util.regex. Instead, since 10.2.0, it is parsed as the three characters '.', '-' and 'z', so the query silently matches different terms.",
   "impact_class": "silent wrong results",
   "introduced_commit": "19be0e5fd11 (#14227), commit-level bisect",
   "introduced_date": "2025-02-13",
   "first_affected_version": "10.2.0",
   "affected_versions": "10.2.0, 10.5.2, 10.6.0 and main e1faeba08bd wrong; 9.12.2 and 10.1.0 correct [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-019.html",
   "repro": "repro/LFV-019/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-204",
   "priority": "medium",
   "priority_rank": 37,
   "novelty": "new",
   "withheld": false,
   "area": "document / geo shape fields (ShapeField triangle encoding; LatLonShape and XYShape CONTAINS queries)",
   "title": "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",
   "summary": "You index a polygon with LatLonShape or XYShape and run a CONTAINS query that asks whether the polygon fully contains a box (or another query shape); you expect a match exactly when the box lies inside the polygon. When ShapeField.encodeTriangle turns one of the polygon's clockwise tessellation triangles counter-clockwise, it swaps two vertices but gives the new first edge the 'belongs to the polygon boundary' flag of the wrong old edge, so a real boundary edge can lose its flag and an internal diagonal can gain one. CONTAINS then silently says yes for boxes that stick out of the polygon (in one executed case a box 99.9998% outside it) and no for boxes well inside it.",
   "impact_class": "silent wrong results",
   "introduced_commit": "ce667fdd2f9453f34c8dc393600565c425021fd1 (main line, first released in 9.0.0) and its branch_8x backport fd2294f585db65c6bb093ebde6a51ddd6cb986a5 (shipped in 8.8.0), the same patch: LUCENE-9642 'Rotate triangle points before checking triangle orientation (#2154)' by iverase (PR apache/lucene-solr#2154, issue #10681) [read]; the commit replaced the correct a<->c swap (ab = old bc, bc = old ab, ca = old ca, from LUCENE-8620 #771, 62001b9b965, released in 8.3.0) with a b<->c swap but kept 'ab = bc' and the comment 'ab becomes bc'",
   "introduced_date": "2021-01-04 (LUCENE-9642 / lucene-solr#2154 merged; PR opened 2020-12-17)",
   "first_affected_version": "8.8.0 [exec] (release tag 2021-01-29; on the main line 9.0.0, tag 2021-12-06); 8.3.0 to 8.7.0 map the flags correctly [exec]; 8.2.0 and earlier have no edge flags (the encoding probe does not compile on 8.2.0) [exec]",
   "affected_versions": "8.8.0 to 8.11.4, 9.0.0 to 9.12.3, 10.0.0 to 10.5.2, 10.6.0 (by reading) and main ea57360912ed. [exec] the canonical repro (or its import-only legacy copy) fails 4 of 4 on all 12 8.x releases from 8.8.0 to 8.11.4, on 9.0.0, 9.1.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) (follow-up history runs); the independent reproduction's own JUnit fails 6 of 6 on main (-ea, -da), 10.5.2 and 9.12.3, and its framework-free variant fails on 8.8.0 and passes on 8.7.0; the security probe fails the same way on main and 10.5.2. [read] every release tag in the history clone from 8.8.0 to 10.5.2 (35 tags) has the b<->c swap with 'ab = bc'; 8.8.2 to 8.11.4 are not in the clone and are covered by execution only. Not affected: 8.3.0 to 8.7.0 [exec]. Not executed: 10.6.0 (released 2026-10-29); upstream main, branch_10x and branch_10_6 still read 'ab = bc' [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-204.html",
   "repro": "repro/LFV-204/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-698",
   "priority": "medium",
   "priority_rank": 38,
   "novelty": "new",
   "withheld": false,
   "area": "geo / shape queries (Polygon2D intersectsLine/intersectsTriangle; LatLonShape and XYShape INTERSECTS and DISJOINT with a query polygon that has holes)",
   "title": "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",
   "summary": "You index a line or polygon with LatLonShape or XYShape and search with a query polygon that has holes, for example a region with two lakes cut out; a line from one lake to the other crosses the land between them, so INTERSECTS should return it and DISJOINT should not. Polygon2D.intersectsLine/intersectsTriangle report an intersection only when a vertex of the indexed shape is inside the polygon (holes excluded) or one of its edges crosses the outer ring; they never test the hole edges, so when every vertex lies in a hole the shape counts as not intersecting. The query returns the wrong documents with no error (repro: the square [0,10]^2 with holes [1,3]x[4,6] and [7,9]x[4,6]; of the line (2,5)-(8,5), the box [2,8]x[4.5,5.5] and the point (5,5), INTERSECTS returns only the point and DISJOINT returns the line and the box).",
   "impact_class": "silent wrong results",
   "introduced_commit": "f914e08b3647ad91eb97ada6ebefe1e96ebd5a89 (LUCENE-9273 'Speed up geometry queries by specialising Component2D spatial operations', apache/lucene-solr#1341, issue now apache/lucene#10313; author iverase, approved by nknize; branch_8x backport a001f135f229a4c08afe4b6eb3dc11da5db91605 with a byte-identical Polygon2D.java, the commit shipped in 8.6.0) [exec]. It replaced Polygon2D.relateTriangle, which checked the holes first (a hole relation of CROSSES returned CROSSES, a step from LUCENE-8435 in 7.5.0), with intersectsLine/intersectsTriangle, whose pre-test uses the hole-aware contains() and outer-ring crossings only. Later commits on Polygon2D (LUCENE-9570 reformat, LUCENE-9595, LUCENE-10003, LUCENE-10514, GITHUB#12655) leave these two methods unchanged [read].",
   "introduced_date": "2020-04-20",
   "first_affected_version": "8.6.0 [exec] (8.5.2 is the last correct release [exec])",
   "affected_versions": "Every release from 8.6.0 to 10.5.2, 10.6.0 (by reading) and main a9779ef3c193; 7.5.0 to 8.5.2 are correct. [exec] a main() port of the repro geometry on all 66 lucene-core releases from 7.5.0 to 10.5.2 (SHA-1-checked release jars, -ea; 7.5.0-8.1.1 with a LatLonShape-only port because XYShape did not exist yet): 8.6.0-8.11.4 (16), 9.0.0-9.12.3 (21) and 10.0.0-10.5.2 (12) fail with XYShape and LatLonShape INTERSECTS=1 and DISJOINT=2 (expected 3 and 0), 7.5.0-8.5.2 (17) pass; at commit level the parents of f914e08b364 and a001f135f229 pass and both commits fail; the finder's JUnit fails 2 of 2 on 9.12.3, 10.5.2 and main (-ea and -da); the independent reproduction's test fails on main, 10.5.2 and 9.12.3 and its 8.x port fails on 8.6.0 and passes on 8.5.2; the intended-behaviour check's test (one non-convex hole, three holes) fails on main, 10.5.2 and 9.12.3. Only the two-hole geometry was executed on releases before 8.6.0. Not fixed upstream: Polygon2D.java on main, branch_10x and branch_10_6 is byte-identical to the tested copy (checked 2026-10-27). All runs with JDK 25 on aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-698.html",
   "repro": "repro/LFV-698/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1128",
   "priority": "medium",
   "priority_rank": 39,
   "novelty": "known",
   "withheld": false,
   "area": "core / geo (Circle2D haversine segment test behind LatLonShape.newDistanceQuery)",
   "title": "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)",
   "summary": "You index a two-point LatLonShape line from (lat 60.38, lon 9.8) to (lat 59.78, lon 10.4) and run LatLonShape.newDistanceQuery with INTERSECTS and a 10 km circle around (lat 60, lon 10). The line passes 8.95 km from the centre, so you expect 1 hit, and the circle's own contains() accepts a point of the line; you get 0 hits and no error, and DISJOINT matches the line instead. When neither end is inside, Circle2D tests only the point of the segment closest to the centre in raw lon/lat degrees (here 11.19 km away), not the point closest by haversine distance, so diagonal edges that cross the outer part of the circle are missed.",
   "impact_class": "silent wrong results",
   "introduced_commit": "d48bafb2999542224c86f278d1fd0dcb949388cc on master and its branch_8x cherry-pick 50168ab5bc85c382a6d558553caa1f752bf5afc1 (LUCENE-8707 'Add LatLonShape and XYShape distance query', apache/lucene-solr#587 by iverase, opened 2019-02-25, merged 2020-02-19; JIRA LUCENE-8707 = apache/lucene#9753): the first version of Circle2D already projects the centre onto the segment with the Euclidean metric in raw degrees and calls the haversine contains() once at that point. git log -L on the method lists only LUCENE-9250 (988ce9bff7e / 16663db0996, 8.5.0: made it static with an explicit centre for the dateline shift, which is why git blame credits the vector lines to it), LUCENE-9570 (2d6ad2fee6d, formatting) and LUCENE-9870 (06114459ee4, the t range check), and none of them changed the metric; the introducing PR, its JIRA issue and the commit message do not mention the approximation [read]",
   "introduced_date": "2020-02-19 (author date 2020-02-19T16:03:30+01:00 of both commits; branch_8x commit date 2020-02-19T16:05:31+01:00)",
   "first_affected_version": "8.5.0 [exec]",
   "affected_versions": "every release since the API exists: 8.5.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT). Executed: the finder's test fails on 8.5.0, 8.8.2, 8.11.4, 9.0.0, 9.12.3, 10.0.0 and 10.6.0 (-da) and on main (-ea and -da), and isolation probes miss on 8.5.0 and 8.8.1; the independent reproduction's test fails on main (-ea and -da) and on 10.6.0, 10.5.2 and 9.12.3 (-da) [exec]; the other releases by reading (no commit changed the degree-space projection) [read]. In 8.5.0-8.8.1 the older range check (fixed by LUCENE-9870 in 8.8.2) also rejects the finder's short segment, so there the test fails for two reasons; the isolation probe separates them. Not new in 10.6 (10.5.2 fails). Not fixed upstream: Circle2D.java is the same blob (8fd98adbc55) at ea57360912ed, 5adff78bb168 and 10.6.0, its newest upstream commit is f22f2b70a7d (author date 2025-07-07, a typo fix, #14898), and upstream main 1c2072f0284 (author date 2026-11-02) has no later geo commit [read]. Runs used JDK 25.0.3 on Linux aarch64.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/10279",
    "https://github.com/apache/lucene/issues/10909",
    "https://github.com/apache/lucene/issues/10290",
    "https://github.com/apache/lucene/issues/9753",
    "https://github.com/apache/lucene/issues/10315",
    "https://github.com/apache/lucene-solr/pull/587"
   ],
   "doc": "bugs/LFV-1128.html",
   "repro": "repro/LFV-1128/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-291",
   "priority": "medium",
   "priority_rank": 40,
   "novelty": "new",
   "withheld": false,
   "area": "queries / intervals (Intervals.notContainedBy: NotContainedByIntervalsSource disjunction rewrite, LUCENE-8477)",
   "title": "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",
   "summary": "You index 'i love new york', 'york city is big' and 'york is here' and search notContainedBy(york, or(phrase(new, york), phrase(york, city))), meaning 'york that is not part of new york or york city'; you expect only the third document, which is what or(false, ...) and the nested form notContainedBy(notContainedBy(york, 'new york'), 'york city') return. Instead all three documents match: the default disjunction rewrite (LUCENE-8477) pulls the OR out of the excluded operand and builds or(NOT_CONTAINED_BY(york, 'new york'), NOT_CONTAINED_BY(york, 'york city')), which computes 'not inside B1 or not inside B2' where the javadoc promises 'not inside (B1 or B2)'. So adding a clause to the exclusion adds hits: notContainedBy(a, or(phrase(c, a), b)) matches 'c a' although notContainedBy(a, phrase(c, a)) does not.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f1782d0dd1195c823c79aab87529ebd7e8217b95 (main line, then master; first release 9.0.0) and its branch_8x backport 2571bf355f82e193d50ec2509f83ba698b262562 (the released one, 8.1.0), both 'LUCENE-8477: Automatically rewrite disjunctions when internal gaps matter' (apache/lucene-solr#620, issue migrated as apache/lucene#9523) by @romseygeek, approved by @jimczi [read]. A regression; no commit-level bisection was done (the parent of 2571bf355f8 was not built)",
   "introduced_date": "2019-03-27 (both commits; apache/lucene-solr#620 merged 2019-03-27T11:23:44Z)",
   "first_affected_version": "8.1.0 [exec] (last unaffected release 8.0.0 [exec], -ea and -da; intervals were in the sandbox module, package org.apache.lucene.search.intervals, until 8.1.x and in the queries module from 8.2.0). The notContainedBy API exists since 7.4.0 (LUCENE-8196); 7.4.0 and 7.7.3 are correct [exec]",
   "affected_versions": "every release from 8.1.0 through 10.6.0 (8.1.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2, and 10.6.0 by reading) and main ea57360912ed; not fixed upstream. [exec] wrong: the test-framework-free main() port NcbHistory fails on 8.1.0 (-ea, -da), 8.1.1, 8.2.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main; the finder's JUnit fails 2 of 2 on 9.12.3, 10.5.2 and main (-ea, -da); the independent reproduction's own main() variant fails on 8.1.0, 8.2.0, 8.11.4 and main. [exec] correct: 7.4.0, 7.7.3 and 8.0.0 (-ea, -da). [read] f1782d0dd11 is an ancestor of every releases/lucene 9.x and 10.x tag, and 2571bf355f8 of every 8.x tag from 8.1.0 to 8.8.1 in the local clone (the 8.9.0-8.11.4 tags are not in the clone; 8.11.4 was executed); upstream main e1c4184cb983 (2026-10-26) adds two commits after ea57360912ed and neither touches intervals. Caveats: release jars were run on JDK 25 only; the regression claim covers ORs whose clauses do not nest; for nesting clauses such as or(phrase(x,y,z), y), over-matching against the literal javadoc already happens on 8.0.0 (minimal-interval semantics) and the rewrite leaves it in place",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-291.html",
   "repro": "repro/LFV-291/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-287",
   "priority": "medium",
   "priority_rank": 41,
   "novelty": "known",
   "withheld": false,
   "area": "queries / intervals (NotContainingIntervalsSource, Intervals.notContaining)",
   "title": "Intervals.notContaining drops minuend intervals that a subtrahend interval overlaps on the right edge or encloses, though they contain no subtrahend interval",
   "summary": "You search with Intervals.notContaining(minuend, subtrahend), for example notContaining(phrase(a,b), phrase(b,c)) on the text 'a b c', or notContaining(term york, phrase(new,york)) on 'new york'. You expect the minuend interval back, because the javadoc says notContaining 'Returns intervals from the minuend that do not contain intervals of the subtrahend', and 'a b' does not contain 'b c' (and one position cannot contain two). Instead the iterator keeps a minuend interval only if the next subtrahend interval starts after its end, so both queries return no interval and the document is not a hit, while the mirror-image overlap on the left edge (notContaining(phrase(b,c), phrase(a,b))) is kept.",
   "impact_class": "silent wrong results",
   "introduced_commit": "00eab54f9d6232c68a93f10ff20e3a724ffeca14 on master and its branch_7x twin 974c03a6ca8eed3941e1414dd2ecb75132228d4f, 'LUCENE-8196: Add IntervalQuery and IntervalsSource to the sandbox' (romseygeek), which created Intervals.notContaining together with this keep test; LUCENE-8196 is now apache/lucene#9243; its review PR apache/lucene-solr#334 was closed unmerged and the change pushed directly [read]. Inside the PR, commit c6fa86096e (2018-02-25) wrote NotContainingIterator with CONTAINING's skip loop and NonOverlappingIterator's keep test b.start() > a.end(); the body is unchanged since (f1782d0dd11 LUCENE-8477 and 46cc24d77ec LUCENE-8856 moved it, 8ef6a0da568 LUCENE-9570 added braces). Present since the operator was created, not a regression",
   "introduced_date": "2018-04-03 (00eab54f9d6 and 974c03a6ca8; the iterator body dates from PR commit c6fa86096e, 2018-02-25)",
   "first_affected_version": "7.4.0 [exec] (release tag commit 2018-06-18; the first release with the intervals API, in the lucene-sandbox artifact, package org.apache.lucene.search.intervals; CHANGES 7.4.0 'LUCENE-8196, LUCENE-8300: A new IntervalQuery in the sandbox'); 7.3.1 has no intervals API [exec]; the one-line fix applied to the 7.4.0 source makes the 7.4.0 port pass [exec]",
   "affected_versions": "every release from 7.4.0 through 10.5.2 and main ea57360912ed. [exec] by the follow-up history sweep (public-API main() port with 8 controls that hold everywhere, and from 9.1.0 also the finder's JUnit): 7.4.0 (-ea and -da), 7.7.3, 8.0.0, 8.1.0, 8.2.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) all fail the same way; the independent reproduction also 8.11.3 (main()), the independent reproduction, the intended-behaviour check and the finder 10.5.2 and 9.12.3. [read] the NotContainingIterator body is identical at all 58 release tags in the history clone that contain the introducing commit (7.4.0-7.7.3, 8.0.0-8.8.1, 9.0.0-9.12.3, 10.0.0-10.5.2); 8.8.2-8.11.3 are not tagged there and were not run. Exposure: lucene-sandbox 7.4.0-8.1.x, lucene-queries (org.apache.lucene.queries.intervals) from 8.2.0 (LUCENE-8856), query strings through StandardQueryParser fn:notContaining from 9.1.0 (LUCENE-10223). Not affected: every release up to 7.3.1 (API absent) [exec]. Not fixed: main, branch_10x and branch_10_5 have the same keep test, and no open PR touches NotContainingIntervalsSource [read]; 10.6.0 (released 2026-10-29) was not checked. All runs on aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9523",
    "https://issues.apache.org/jira/browse/LUCENE-8477",
    "https://github.com/apache/lucene/issues/9243",
    "https://issues.apache.org/jira/browse/LUCENE-8196",
    "https://issues.apache.org/jira/browse/LUCENE-10407",
    "https://issues.apache.org/jira/browse/LUCENE-10406"
   ],
   "doc": "",
   "repro": "repro/LFV-287/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-457",
   "priority": "medium",
   "priority_rank": 42,
   "novelty": "new",
   "withheld": false,
   "area": "queries / intervals (Intervals.analyzedText: IntervalBuilder.analyzeGraph; flexible StandardQueryParser fn: interval functions)",
   "title": "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)",
   "summary": "You build an interval query with Intervals.analyzedText(\"wifi dog\", analyzer, \"f\", 0, true) (or the flexible StandardQueryParser's fn:or(\"wifi dog\")), where the query analyzer's SynonymGraphFilter has the rules wifi => 'wi fi' and dog => canine. You expect it to match 'wifi dog', 'wifi canine', 'wi fi dog' and 'wi fi canine', as QueryBuilder's phrase query with the same analyzer does and as analyzedText(\"dog\") alone does with or(canine,dog). Instead, because 'wifi' has a two-position synonym, the builder keeps only the first token stacked at the 'dog' position, builds or(BLOCK(wi,fi,canine),BLOCK(wifi,canine)) and misses the two 'dog' documents, including the one that holds exactly the query text; with assertions enabled it throws AssertionError.",
   "impact_class": "silent wrong results",
   "introduced_commit": "32d7f52446ae363b45817b16d8f8ac106e1b461c (main; first released in 10.0.0) and its branch_9x backport 5de05f3556224fc68302f38848d60fe208e9875b (first released in 9.1.0), both 'LUCENE-10220: Add an utility method to get IntervalSource from analyzed text (or token stream) (#427)' (apache/lucene#427 by @dweiss, approved by @romseygeek; issue migrated as apache/lucene#11256) [read]. Not a regression: present since the method was added. The issue says the code was adopted from the Elasticsearch 7.10 IntervalBuilder, which has the identical branch [read]. The branch's premise was already false when written: GraphTokenStreamFiniteStrings.hasSidePath has returned false for equal-length stacked tokens since LUCENE-7638 (e764d3e0590, 2017-02-07), and the same commit's test asserts it [read]. Second entry point: the flexible StandardQueryParser fn: interval functions, LUCENE-10223 (#429; f725b27e12a on main, ff9ee28c603 on branch_9x, 2021-11-11), also first released in 9.1.0.",
   "introduced_date": "2021-11-05",
   "first_affected_version": "9.1.0 [exec]. 9.0.0 is the last release without it: Intervals.analyzedText and IntervalBuilder do not exist there [exec]; the commit went to main and branch_9x after 9.0 was frozen [read]. First release from the main line: 10.0.0 [exec].",
   "affected_versions": "every release from 9.1.0 through 10.5.2 (9.1.0-9.12.3 and 10.0.0-10.5.2, 32 releases) and main ea57360912ed; not fixed upstream (IntervalBuilder.java on apache/lucene main 49483e82b357 and branch_10x is byte-identical to ea57360912ed [read]). [exec]: the follow-up's test-framework-free probe (AnalyzedTextGraphProbe, public API through reflection) fails 6 of 6 (maxGaps, ordered) modes, control passing, on all 32 releases and main, with -ea (AssertionError) and -da (2 of 4 hits); the finder's JUnit fails 3 of 3 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main with -ea and -da; the independent reproduction's JUnit fails 5 of 6 on 9.12.3, 10.5.2 and main with -ea and -da. [exec]: 9.0.0 (no API). [read]: Lucene 8.x and earlier have no IntervalBuilder. The AssertionError is reported at line 234 on 9.x and line 233 on 10.x and main (same statement).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-457.html",
   "repro": "repro/LFV-457/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-286",
   "priority": "medium",
   "priority_rank": 43,
   "novelty": "new",
   "withheld": false,
   "area": "queries / intervals (Intervals.atLeast: MinimumShouldMatchIntervalsSource)",
   "title": "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",
   "summary": "You index 'a b' and read the intervals of Intervals.atLeast(1, term a, term b), or search ordered(c, atLeast(1, a, b)) over 'a c b'; you expect [0,0] and [1,1], exactly what or(a, b) returns, and one hit. Instead atLeast returns only [0,0] and the ordered query finds nothing: when the sub-iterator just popped from atLeast's proximity queue has no further interval, nextInterval() does not pull a replacement from its background queue and ends, although the other source still has intervals. The same hand-over never advances waiting sub-iterators past the current start, so atLeast(1, b, phrase(a, b)) on 'a b b' returns [1,1] then [0,1] (out of order, and [0,1] contains [1,1]) and loses [2,2].",
   "impact_class": "silent wrong results",
   "introduced_commit": "e015afadaa698a0eb39574198dce31b9a7292a62 (master, which became 9.0) and its branch_8x copy bfbe80472ef330f3ad264eda7a9ef48eb91b58cc (the released one, 8.0.0), both 'LUCENE-8622: Minimum-should-match interval function' by @romseygeek; JIRA patch workflow, no GitHub PR, issue migrated as apache/lucene#9668 [read]. The loop was copied from the UNORDERED iterator of LUCENE-8196 (00eab54f9d6, 2018-04-03), where ending on an exhausted sub-iterator is correct because every sub-iterator is required; LUCENE-8622 adapted the second (minimising) loop to draw a replacement but left the first loop unchanged. Not a regression: wrong since the API was added",
   "introduced_date": "2019-01-07",
   "first_affected_version": "8.0.0 [exec] (intervals were then in the sandbox module, package org.apache.lucene.search.intervals; 8.2.0 [exec] is the first release with intervals in the queries module). 7.6.0 (last release before the commit) and 7.7.3 (last 7.x) have no atLeast API: the port fails to compile with only 'cannot find symbol: method atLeast' errors [exec]",
   "affected_versions": "every release from 8.0.0 through 10.6.0 (10.6.0 by reading) and main ea57360912ed; not fixed upstream. [exec] all 60 releases 8.0.0-10.5.2: a test-framework-free main() port fails its 4 bug checks (B1 atLeast(1,a,b) on 'a b' gives [[0,0]]; B2 ordered(c, atLeast(1,a,b)) on 'a c b' counts 0; B3 the stale case gives [[1,1],[0,1]]; B4 atLeast(2, ordered(a,c), b, d) on 'a b c d' gives [[0,2]]) with all 4 controls passing on each, and passes 8 of 8 on main with the fix shadowed; the finder's JUnit fails 3 of 3 on 9.1.0, 9.12.3, 10.5.2 and main (-ea and -da); the independent reproduction's JUnit fails 7 of 13 on main (-ea, -da), 10.5.2 and 9.12.3 and its separate main() fails on 8.11.3. [read] branch_10x and branch_10_6 have the same nextInterval() loop (they differ from main only in comparator syntax, #14761); upstream main e1c4184cb983 (2026-10-26) adds two commits after ea57360912ed and neither touches intervals. Caveats: JDK 25 only, old releases run on a modern JDK; 8.0.0-8.1.1 had intervals in the sandbox module; the introducing commit itself was not built",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-286.html",
   "repro": "repro/LFV-286/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-627",
   "priority": "medium",
   "priority_rank": 44,
   "novelty": "known",
   "withheld": false,
   "area": "core / search (NGramPhraseQuery rewrite), on n-gram fields built with analysis-common (NGramTokenizer, CJKAnalyzer / CJKBigramFilter)",
   "title": "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",
   "summary": "You wrap the analyzer's phrase query in NGramPhraseQuery, which its javadoc presents as a PhraseQuery optimized for n-gram fields that you may use 'rather than PhraseQuery' (the introducing review said 'the same results will be returned, scoring will differ'), and expect the same matching documents. Instead the rewrite keeps only the first gram, every n-th gram and the last gram at their relative positions (\"ab bc cd\" becomes \"ab ? cd\"), which is only correct when grams n positions apart always come from one unbroken run of text, and nothing checks that. So a 2-gram field with the two values 'xab' and 'zcd' (default gap 0), CJKAnalyzer text such as '東京。新大学' or '東京6大学野球', and a whitespace-pre-tokenized 2-gram field holding 'xab zcd' or 'multi long' all match a phrase ('abcd', '東京大学', 'tion') that the PhraseQuery itself does not match.",
   "impact_class": "silent wrong results",
   "introduced_commit": "4b3032e9e6c18388d257af9ddc4c1e9623127701 (trunk, svn r1170586, 'LUCENE-3426: add NGramPhraseQuery', ASF committer koji; JIRA LUCENE-3426 'optimizer for n-gram PhraseQuery', migrated as apache/lucene#4499; svn-era patch, no GitHub PR), backported to branch_3x the same day as 3b7f8099ab4355afb527977031b843eb35bc1d27 (svn r1170593), the copy first released in 3.5.0 [read]. Not a regression: the rule 'keep term i when i % n == 0 or it is the last term' is semantically unchanged since; later commits only copy the boost (LUCENE-4970, 2e7f226afe4, 2013), wrap an immutable PhraseQuery and use relative positions (LUCENE-6531, c397fe72346, 2015, a constant offset that a phrase ignores), move to the BoostQuery API (LUCENE-6590, 962313b83ba) and change the signature to rewrite(IndexSearcher) (GITHUB-11838, 6cde41c9fd8, 2022)",
   "introduced_date": "2011-09-14 (4b3032e9e6c on trunk and 3b7f8099ab4 on branch_3x)",
   "first_affected_version": "3.5.0 [exec] (tag dated 2011-11-25), the first release that has NGramPhraseQuery: the multi-valued gap-0 and CJKAnalyzer (then CJKTokenizer) triggers both fail with -ea and -da, controls pass. 3.4.0, the last release before, has no NGramPhraseQuery class [exec]. On the trunk line the first release is 4.0.0-alpha [read]",
   "affected_versions": "Every release from 3.5.0 to 10.5.2, and main a9779ef3c193; never fixed. [exec] (follow-up; SHA-1-verified release jars, JDK 25.0.3, each with -ea and -da): version-ported main() harnesses with controls fail on 3.5.0 and 3.6.2 (multi-valued gap 0 and CJK run break; isTokenChar does not exist before 4.4.0), and on 4.10.4, 5.3.0, 5.5.5, 6.0.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (3 of 3 scenarios, controls pass); the finder's JUnit fails 3/3 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main; the independent reproduction's JUnit fails 4 of 6 on main, 10.5.2 and 9.12.3 with its 2 controls passing; the intended-behaviour check 3/3 on 10.5.2. [read] 4.0.0-alpha..4.3.1, 5.0.0..5.2.1 and the intermediate minor releases by code reading (same rewrite rule); upstream main a95c754ee003 (2026-10-26) has the same rewrite and no open PR touches NGramPhraseQuery. Trigger availability: multi-valued gap and CJKAnalyzer from 3.5.0 (CJKTokenizer in 3.5.x, StandardTokenizer + CJKBigramFilter from 3.6.0, LUCENE-2906), isTokenChar pre-tokenization from 4.4.0 (LUCENE-5042, e021451d6c0). Not executed: x86 (all runs on aarch64; the logic is architecture-independent query rewriting)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/4499",
    "https://issues.apache.org/jira/browse/LUCENE-3426",
    "https://github.com/apache/lucene/issues/7225",
    "https://issues.apache.org/jira/browse/LUCENE-6163",
    "https://github.com/apache/lucene/issues/6034",
    "https://issues.apache.org/jira/browse/LUCENE-4970"
   ],
   "doc": "",
   "repro": "repro/LFV-627/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-220",
   "priority": "medium",
   "priority_rank": 45,
   "novelty": "new",
   "withheld": false,
   "area": "join / ToParentBlockJoinSortField nested sort (ToParentDocValues missing-child count, #15727)",
   "title": "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)",
   "summary": "You index blocks with two kinds of non-parent documents, for example P1 = [type:a s=y n=40, type:b s=x n=7, parent P1] and P2 = [type:a s=d n=10, parent P2], and sort the parents of a ToParentBlockJoinQuery with new ToParentBlockJoinSortField(\"s\", STRING, false, parents, childFilter type:a), expecting 'P2=d P1=y', which is what Lucene 10.4.0 returns. Instead 10.5.0 and later return 'P1=null P2=d', sorting P1 as if it had a child without the field although every document in both blocks has it, and a LONG sort with childMissingValue=0 gives 'P1=0 P2=10' instead of 'P2=10 P1=40'. The cause is that ToParentDocValues decides whether some child lacks a value by comparing the number of childFilter documents that have a value with the number of all documents in the block, so any document outside childFilter, with or without the field, forces the missing value.",
   "impact_class": "silent wrong results",
   "introduced_commit": "167503f6d84d8e43db4ec6ae3baf17337290393f on main and its branch_10x backport 0915f9cac54917269e58f952192b5b62a768ee47 (the same patch, git patch-id --stable 17a14d47ca74; the backport is the commit in the release tags): apache/lucene#15727 'Fix incorrect handling of missing values in ToParentBlockJoinSortField' by gmarouli, merged by romseygeek on 2026-03-03, milestone 10.5.0, closes #15548 [read]; before #15727 ToParentDocValues aggregated only over childFilter documents with a value, so an excluded document could not affect the parent",
   "introduced_date": "2026-03-03",
   "first_affected_version": "10.5.0 [exec] (10.4.0 passes [exec])",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2, 10.6.0 (by reading, see the branch_10_6 read below) and main ea57360912ed (11.0.0-SNAPSHOT) [exec]; not affected: 9.12.3, 10.0.0, 10.3.2 and 10.4.0 [exec]; the childMissingValue constructors were added by #15727, so the numeric variant does not compile on 10.4.0 [exec]; branch_10_6 and branch_10x (heads 2026-10-24) carry the same lines [read]; not fixed upstream: the last change to ToParentDocValues, ToParentBlockJoinSortField and BlockJoinSelector on main, branch_10x and branch_10_6 is #15727 itself [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-220.html",
   "repro": "repro/LFV-220/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-232",
   "priority": "medium",
   "priority_rank": 46,
   "novelty": "new",
   "withheld": false,
   "area": "grouping / two-pass grouping (TopGroupsCollector second pass, TopGroups.merge, TopGroupsCollectorManager, GroupingSearch)",
   "title": "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",
   "summary": "You run two-pass grouping (GroupingSearch, or the grouping collectors and collector managers) with setSortWithinGroup(new Sort(SortField.FIELD_SCORE)) or new Sort(), both of which equal Sort.RELEVANCE, and expect the same result as with the Sort.RELEVANCE constant: the top-scoring documents of each group, and GroupDocs.maxScore equal to the best score. Instead TopGroupsCollector tests 'withinGroupSort == Sort.RELEVANCE' (same object), so it collects each group with the field-sort collector, whose hits carry score NaN, while TopGroups.merge tests equals and merges those hits by their NaN scores. When results from 2 or more slices or shards are merged, each group's page then comes out slice by slice or shard by shard (the finder's test returns a score-1 document instead of the score-4 one), and since 10.5.0 the merged maxScore is NaN, on main even for a sequential GroupingSearch.",
   "impact_class": "silent wrong results",
   "introduced_commit": "caf329717ef643b2a5a8b7ef0bfb7bd5e096c849 (LUCENE-7701 'Refactor grouping collectors', a JIRA patch by romseygeek with a +1 from martijnvg, migrated as apache/lucene#8752, no GitHub PR; master only, first released in 7.0.0): it replaced the old second-pass collector's 'withinGroupSort.equals(Sort.RELEVANCE)' with 'withinGroupSort == Sort.RELEVANCE' in the new TopGroupsCollector, without comment [read]. git blame on main points line 129 at 331ccf39106 (LUCENE-8405), which only turned the ternary into an if/else and kept the test. Later changes widened what users see, none is wrong with the constant: 55bfadbce11 (LUCENE-8412, apache/lucene#9459, 8.0.0: field-collected hits always score NaN), #15879 (b90b9dec25c, 10.5.0: merged maxScore taken from scoreDocs[0].score), #15603 and #15574 (8e443458c2f, 5c701b3f553, 10.5.0: collector managers that reduce through TopGroups.merge) and #16247 (3afffeef5a8 on main, d60e550b47f on branch_10_6, released in 10.6.0: GroupingSearch runs on the managers)",
   "introduced_date": "2017-03-28 (author date of caf329717ef; committed to master 2017-04-10)",
   "first_affected_version": "7.0.0 [exec] (2017-09-08; there only for a hand-sharded TopGroups.merge with getScores=false and getMaxScores=false); 8.0.0 [exec] is the first release in which the default flags show it; 10.5.0 [exec] is the first with the NaN maxScore and the collector-manager path; last unaffected release 6.6.6 [exec] (6.6.1 is the last release before 7.0.0)",
   "affected_versions": "7.0.0-7.7.3: only a hand-sharded TopGroups.merge with getScores=false and getMaxScores=false [exec]; 8.0.0-10.4.0: every hand-sharded TopGroups.merge returns the wrong documents, maxScore correct [exec]; 10.5.0-10.5.2: also the collector managers (wrong documents with an executor, NaN maxScore even with one slice) and a NaN merged maxScore [exec]; main ea57360912ed: also GroupingSearch (wrong documents with an executor, NaN maxScore sequentially) [exec]; branch_10_6 (10.6.0, released 2026-10-29), branch_10x and branch_10_5 still have the identity test at line 129 [read], so 10.6.0 is very likely affected (not executed); not executed: 7.1.0-7.7.2, 8.1.0-8.11.3, 9.1.0-9.12.2, 10.1.0-10.3.2 and 10.5.1, each between executed releases with the same behaviour, and every one of them tagged in the history clone has the identity test [read] (8.8.2-8.11.3 are untagged there); unaffected: 5.5.0-6.6.6 (equals test on every tag) [read]; one-line swaps flip the result both ways [exec]; not fixed in any release or on main",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-232.html",
   "repro": "repro/LFV-232/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-660",
   "priority": "medium",
   "priority_rank": 47,
   "novelty": "known",
   "withheld": false,
   "area": "suggest / document suggester (NRTSuggester skipDuplicates, queue sizing) and util / FST (Util.TopNSearcher)",
   "title": "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",
   "summary": "You index suggestions through a CompletionAnalyzer with an index-time synonym (b => xb, keeping the original, so 'a b' is indexed as 'a b' and 'a xb'), add a second suggestion 'a xc', and call SuggestIndexSearcher.suggest(prefix 'a', 2, skipDuplicates=true); you expect the two distinct suggestions [a b/10, a xc/3], which n=3 does return. Instead you get only [a b/10]: Util.TopNSearcher sets its queue to null for the last result when maxQueueDepth == topN, assuming the last path always completes, but the duplicate filter (acceptPartialPath) rejects that path when it reaches 'a xb', so the sibling arc that leads to 'a xc' is never queued and the search ends early (called directly, TopNSearcher even reports isComplete=true for such a search). NRTSuggester makes the queue that small because it counts entries sharing one analyzed form, not the analyzed paths per suggestion that its javadoc describes, so a synonym never enlarges it; with two synonyms (b => {xb, yb}) the duplicate paths fill the queue and both n=2 and n=3 lose a suggestion even with the shortcut removed.",
   "impact_class": "silent wrong results",
   "introduced_commit": "4e2cf61ac76db33f35d3aceacaf1563a9bd5edb2 (master, 'LUCENE-7686: add efficient de-duping to the NRT document suggester', mikemccand, 2017-02-22; first released in 7.0.0) and its branch_6x backport 0d5a61b3df04593691796867ae3b32d05e66a0c0 (same day, identical Util.java hunks; the commit contained in 6.5.0); a JIRA patch, no PR (LUCENE-7686 = apache/lucene#8737) [read]. It added acceptPartialPath and its only caller, the skipDuplicates filter, on top of two older pieces that a fix has to touch: the last-path shortcut (a519b630eea, LUCENE-3714, 2012-02-19; its 'maxQueueDepth == topN' guard and the isComplete formula from dc49949558d, LUCENE-4481, 2012-10-21) and the per-analyzed-form count maxAnalyzedPathsPerOutput (b7adb6ac770, LUCENE-6339, 2015-03-27, first released in 5.1.0). Both were safe while nothing could reject a partial path.",
   "introduced_date": "2017-02-22 (4e2cf61ac76 and the branch_6x backport 0d5a61b3df0); the older ingredients are from 2012-02-19, 2012-10-21 and 2015-03-27",
   "first_affected_version": "6.5.0 [exec] (tag 2017-03-18, contains the backport 0d5a61b3df0). 6.4.2 and earlier have neither suggest(query, n, skipDuplicates) nor acceptPartialPath [exec]. On the master line the first release is 7.0.0.",
   "affected_versions": "Every release from 6.5.0 through 10.6.0 (10.6.0 by reading) and main a9779ef3c193; not fixed upstream (upstream main a95c754ee00, branch_10x 1309534296e and branch_10_6 2763db11b0a read 2026-10-27 still have the shortcut, the uncounted acceptPartialPath break and the per-analyzed-form count). [exec] the suggester repro and the Util repro each fail 1 of 2 with identical messages, controls pass, on 6.5.0 (-ea and -da), 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da); the two-synonym variant fails 3 of 5 on 6.5.0, 9.12.3, 10.5.2 and main. [read] all 74 release tags 6.5.0..10.5.2 in the history clone contain the shortcut, the uncounted acceptPartialPath break and doSkipDuplicates (8.8.2..8.11.4 are not tagged there; 8.11.4 was executed). Releases before 10.x ran API ports (imports, completion postings format class, FST builder API, Result fields) with unchanged test logic and assertions.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/10038",
    "https://issues.apache.org/jira/browse/LUCENE-8995",
    "https://github.com/apache/lucene-solr/pull/913",
    "https://github.com/apache/lucene/issues/913",
    "https://github.com/apache/lucene/issues/5547",
    "https://issues.apache.org/jira/browse/LUCENE-4481"
   ],
   "doc": "",
   "repro": "repro/LFV-660/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-691",
   "priority": "medium",
   "priority_rank": 48,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / document (NRT) suggester (RegexCompletionQuery automaton intersected with the NRTSuggester FST, including the internal END and dedup bytes; also inside ContextQuery)",
   "title": "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)",
   "summary": "You run a RegexCompletionQuery, which 'takes a regular expression as the prefix of the query term', over the suggestions foo (weight 5), food (1) and fox (2), and expect 'foo.' and 'foo[^x]' to return only food (the only suggestion with a matching four-character prefix) and 'foo..' to return nothing (no suggestion has five characters). Instead 'foo.' and 'foo[^x]' return [foo, food] with foo ranked first, and 'foo..' returns [food]. The document suggester stores every suggestion in its FST as the analyzed text followed by an internal end byte 0x00 and dedup bytes, and RegexCompletionQuery hands the regex automaton, whose '.' and negated classes include U+0000, to the FST intersection unchanged, so the pattern runs past the end of the suggestion into these internal bytes.",
   "impact_class": "silent wrong results",
   "introduced_commit": "be4d58c7740bea4e797eb1acff6355eb260e7c93 (trunk, svn r1682158, 'LUCENE-6459: add common suggest API for document based NRT suggester'; issue LUCENE-6459 = apache/lucene#7518; CHANGES credits Areek Zillur via Mike McCandless; svn era, no pull request) and the branch_5x backport 380bb29f39595de1c3947075296d1d0a36f02fd8 (svn r1682170, same day): the commit that created RegexCompletionQuery already passed new RegExp(text, flags).toAutomaton() unchanged to CompletionWeight, over an FST whose inputs already ended in END_BYTE 0x00 plus dedup bytes. Design origin, not the bug: that FST layout and the reservation of 0x00 in suggestion values come from LUCENE-6339 (b7adb6ac7704, 2015-03-27, apache/lucene#7400, release 5.1.0), whose only public lookup was a prefix lookup on the analyzed key, so no wildcard could reach the end byte before LUCENE-6459 [read]; not a regression: the bug is as old as the class",
   "introduced_date": "2015-05-28 (trunk be4d58c7740 and branch_5x backport 380bb29f395, same day)",
   "first_affected_version": "5.3.0 [exec]; 5.2.1 and older have no RegexCompletionQuery or CompletionQuery, so the probe does not compile [exec].",
   "affected_versions": "every release that has RegexCompletionQuery: 5.3.0-5.5.5, 6.0.0-6.6.6, 7.0.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2, and main a9779ef3c193 (unreleased 11.0) [exec]; the releases in between [read]. Not affected: 5.2.1 and older (no such API) [exec]. Not fixed upstream: upstream main a95c754ee003 (2026-10-26) and branch_10x have no fix, and no open PR touches the fix site (2026-10-27) [read]. Executed on Linux aarch64 with JDK 25 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-691.html",
   "repro": "repro/LFV-691/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-700",
   "priority": "medium",
   "priority_rank": 49,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / analyzing: BlendedInfixSuggester result collection",
   "title": "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",
   "summary": "You build a BlendedInfixSuggester with its default settings (POSITION_LINEAR, numFactor 10) from {the lake:1000, lake:950, lake:950, my lake:920} and call lookup(\"lake\", false, 2); blending gives lake 950, the lake 900 and my lake 828, num=3 returns [lake/950, the lake/900, my lake/828], so you expect [lake/950, the lake/900]. Instead you get [lake/950, my lake/828], and without 'my lake' only [lake/950]. When the bounded result set is full, boundedTreeAdd (BlendedInfixSuggester.java:294-306) removes the lowest result with pollFirst() before it calls results.add(result), and that add does nothing for the second 'lake' because LookUpComparator (:383-407) already holds an equal element, so 'the lake' is lost and a later, lower-ranked hit takes its slot.",
   "impact_class": "silent wrong results",
   "introduced_commit": "fb5fd910780d5862101cbd5f49f343b40eeca025 (trunk, svn r1556952) and 89a9302d5a743aca276621ba04196c1fc01d14a2 (branch_4x, r1556954): LUCENE-5354 'add new BlendedInfixSuggester' (issue #6418; a JIRA patch committed by mikemccand; Subversion era, no pull request). Both ingredients arrived in this commit: the evict-then-add order of boundedTreeAdd and a comparator under which equal text and value compare as 0; git log -L on boundedTreeAdd lists only this commit and the 2021 LUCENE-9570 reformat (2cbf261032d). Later changes narrowed or widened the trigger without touching boundedTreeAdd: LUCENE-6680 (#7738, 05363e169d9, 5.3.0) made the comparator also compare payloads, and LUCENE-8343 (#9390) added the small-weight x10 scaling [read]",
   "introduced_date": "2014-01-09",
   "first_affected_version": "4.7.0 [exec] (the class first shipped in 4.7.0; 4.6.1 has no BlendedInfixSuggester [exec])",
   "affected_versions": "Every release from 4.7.0 to 10.5.2 and main a9779ef3c193 [exec]; boundedTreeAdd is identical after whitespace normalization in all 110 local release tags that contain the class (8.9.0-8.11.3 are not tagged locally and are inferred) [read]. In 4.7.0-5.3.1 and 5.4.0 the 3-argument lookup also over-fetched (SOLR-7865, cap num*numFactor or num*numFactor^2), which hides the small repro on that path but not the eviction: with K = 20 or 200 distinct suggestions plus one duplicate, K-1 come back [exec]. Not fixed: upstream main a95c754ee003 (2026-10-26), branch_10x and branch_10_6 are unchanged, so 10.6.0 (released 2026-10-29 from branch_10_6) is affected too, and no open PR changes boundedTreeAdd [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-700.html",
   "repro": "repro/LFV-700/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-254",
   "priority": "medium",
   "priority_rank": 50,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / document (NRT) suggester (ContextQuery: ContextCompletionWeight.setNextMatch boost lookup over ContextSuggestField contexts)",
   "title": "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",
   "summary": "You index 'table lamp' (weight 5) under context 'redwood' and 'table cloth' (weight 4) under 'red' with ContextSuggestField, and query 'tab' with addAllContexts() (or a prefix context 're') plus the exact context 'red' with boost 10; you expect 'table cloth' to score 4 x 10 = 40 and 'table lamp' its plain weight 5, because an exact context matches only an indexed context equal to it. Instead 'table lamp' scores 50 and ranks first: the boost lookup takes the longest query context whose characters equal the start of the indexed context and never checks that the indexed context ends there, so exact 'red' lends its boost to 'redwood'. Filtering is still right (exact 'red' alone does not return 'table lamp'); only scores and order are wrong.",
   "impact_class": "silent wrong results",
   "introduced_commit": "be4d58c7740bea4e797eb1acff6355eb260e7c93 (LUCENE-6459 'add common suggest API for document based NRT suggester', by Areek Zillur (@areek), committed by Mike McCandless (@mikemccand), trunk, svn era with no pull request; issue now apache/lucene#7518; branch_5x backport 380bb29f39595de1c3947075296d1d0a36f02fd8 the same day) [read]. The commit that added ContextQuery already had the longest-prefix boost lookup over a boost-only map, so the defect is as old as the API; not a regression. LUCENE-6702 (f8ae631751ae98ca770d8f387793d9846db62c48, apache/lucene#7760, 2015-07-30, also in 5.3.0) rewrote createWeight and setNextMatch into today's form and kept both defective pieces",
   "introduced_date": "2015-05-28",
   "first_affected_version": "5.3.0 [exec] (the first release with ContextQuery; the repro fails 2 of 4 with -ea and -da, and passes 4 of 4 with the fix ported); 5.2.1 has no ContextQuery, ContextSuggestField or PrefixCompletionQuery, so the repro does not compile [exec]. Correction to the finder's first take ('code since 5.2'): the backport reached branch_5x after branch_5_2 was cut",
   "affected_versions": "every release from 5.3.0 through 10.5.2 and main ea57360912ed; not fixed in any release or on upstream main or branch_10x as of 2026-10-26 [exec]. Caveats: 8.8.2 to 8.11.3 are not tagged in the clone and are listed as affected because 8.8.1 [read] and 8.11.4 [exec] are; releases up to 7.7.3 ran on JDK 25 with a JUnit 4 runner, not the JVM they targeted (the controls pass in each run)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-254.html",
   "repro": "repro/LFV-254/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-087",
   "priority": "medium",
   "priority_rank": 51,
   "novelty": "new",
   "withheld": false,
   "area": "search / rescoring",
   "title": "RescoreTopNQuery lets deleted documents take top-n slots, and IndexSearcher#count counts them",
   "summary": "You wrap an ordinary query, for example a TermQuery, in RescoreTopNQuery to re-score its matches with a DoubleValuesSource and keep the best n, on an index where some matching documents are deleted but not yet merged away. You expect the n best live matches, and IndexSearcher#count to count only live documents. Instead a deleted document whose rescore value ranks in the top n takes one of the n slots, so the search returns fewer than n hits (n=2: [2] instead of [2, 1]) while IndexSearcher#count still reports 2; the deleted document itself is never returned.",
   "impact_class": "silent wrong results",
   "introduced_commit": "3404496b3d77 (#14009 'Add Query for reranking KnnFloatVectorQuery with full-precision vectors', main), released through its branch_10x backport 4fcb6d6d50de (#14860) [read]; not a regression: the missing live-docs check is in the class's first version",
   "introduced_date": "2025-06-28 (#14009 merged; backport #14860 merged 2025-06-29)",
   "first_affected_version": "10.3.0 [exec]",
   "affected_versions": "10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main ea57360912ed [exec]; not applicable to 10.2.2 and earlier, including 9.12.3 (RescoreTopNQuery absent, the repro does not compile) [exec]; branch_10_6 4ae946e5a9b (10.6.0 RC1) and branch_10x 657014b3c57 have a RescoreTopNQuery.java byte-identical to 10.5.2 [read]; main 645d4fe14a20, after #16926 [exec]; branch_11x f85446cb1af [read]; not fixed upstream as of main 645d4fe14a20",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-087.html",
   "repro": "repro/LFV-087/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-315",
   "priority": "medium",
   "priority_rank": 52,
   "novelty": "new",
   "withheld": false,
   "area": "search / rescoring",
   "title": "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",
   "summary": "You wrap a query in RescoreTopNQuery and re-score its matches with a values source that uses the query's own score, for example DoubleValuesSource.SCORES or an expression such as _score * popularity, keeping the best n. You expect the source to see each match's real score, so rescoring body:common OR body:rare by SCORES with n=1 should return the rare-term document 9 with its normal score. Instead RescoreTopNQuery runs the inner query in a mode that produces no scores, so the source reads 0 for every match and the result is doc 0 with score 0.0 (the first match by doc id); for a kNN inner query the scores are right until the query cache caches the inner query, and from then on (the 5th identical search with the usage-tracking policy) they read 0 too.",
   "impact_class": "silent wrong results",
   "introduced_commit": "3404496b3d77 (#14009 'Add Query for reranking KnnFloatVectorQuery with full-precision vectors', by GitHub dungba88, main), released through its branch_10x backport 4fcb6d6d50de (#14860 'Backport RescoreTopNQuery to 10.3') [read]; not a regression: both lines are in the class's first version, and #16705 (main only) added the inline path for score-reading sources but kept COMPLETE_NO_SCORES",
   "introduced_date": "2025-06-28 (#14009 committed to main 2025-06-28T07:34Z; backport #14860 committed 2025-06-29T21:08Z)",
   "first_affected_version": "10.3.0 [exec]",
   "affected_versions": "10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main ea57360912ed [exec]; not applicable to 10.2.2, 9.12.3 and earlier (RescoreTopNQuery absent, the repro does not compile) [exec]; upstream main (re-checked 2026-10-26) and branch_10x still create the inner Weight with COMPLETE_NO_SCORES [read]; branch_10_6 4ae946e5a9b (10.6.0 RC1) and branch_10x 657014b3c57: RescoreTopNQuery.java byte-identical to 10.5.2 [read]; main 645d4fe14a20 [exec]; branch_11x f85446cb1af [read]; not fixed anywhere",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-315.html",
   "repro": "repro/LFV-315/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1015",
   "priority": "medium",
   "priority_rank": 53,
   "novelty": "new",
   "withheld": false,
   "area": "search / rescoring (RescoreTopNQuery scores, consumed by MaxScoreBulkScorer dynamic pruning)",
   "title": "RescoreTopNQuery passes negative DoubleValuesSource values through as negative scores, so a top-k BooleanQuery that ORs it with another clause silently returns no hits",
   "summary": "You index 10 documents with a numeric doc-values field v = -2..-11 and run BooleanQuery(SHOULD RescoreTopNQuery(MatchAllDocsQuery, DoubleValuesSource.fromLongField(\"v\"), 1), SHOULD MatchAllDocsQuery) with searcher.search(q, 10), expecting all 10 documents, since each one matches the MatchAllDocsQuery clause and count(q) is 10. Instead it returns 0 hits and totalHits 0. RescoreTopNQuery copies the raw value -2 into the score, although Lucene requires non-negative scores (LUCENE-7996) and FunctionScoreQuery maps negative values to 0, so the clause reports a max score of -2, the two clauses' max scores sum to -1, below the initial minimum competitive score of 0, and MaxScoreBulkScorer skips the whole window as if no document could compete.",
   "impact_class": "silent wrong results",
   "introduced_commit": "3404496b3d77 (#14009 'Add Query for reranking KnnFloatVectorQuery with full-precision vectors', by GitHub dungba88, main), released through its branch_10x backport 4fcb6d6d50de (#14860 'Backport RescoreTopNQuery to 10.3') [read]. Not a regression: the rescore loop never clamped, while FunctionScoreQuery has clamped since LUCENE-7996 (8.0.0)",
   "introduced_date": "2025-06-28 (#14009 author date; backport #14860 merged 2025-06-29)",
   "first_affected_version": "10.3.0 [exec]; 10.2.2 and 9.12.3 are not applicable (no RescoreTopNQuery, the repro does not compile) [exec]",
   "affected_versions": "10.3.0 (-ea and -da), 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1 (-da), 10.5.2 (-ea and -da), branch_10x 657014b3c57 (-da), the 10.6.0 RC1 core jar (branch_10_6 4ae946e5a9b, main() twin, -ea and -da) and main 645d4fe14a20 (-ea and -da) [exec]; not applicable to 10.2.2 and 9.12.3 [exec]; not fixed upstream: main HEAD is still 645d4fe14a20 and rescoreInto inserts the raw value on main, branch_11x and branch_10_6 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1015.html",
   "repro": "repro/LFV-1015/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1016",
   "priority": "medium",
   "priority_rank": 54,
   "novelty": "known",
   "withheld": false,
   "area": "search / top-k dynamic pruning (ScorerUtil.minRequiredScore, called by MaxScoreBulkScorer)",
   "title": "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",
   "summary": "You run IndexSearcher.search(q, 10) on a 3-document index, where q ORs a clause that scores every document -1 and reports -1 as its max score with a MatchAllDocsQuery, and expect it to return the 3 documents or throw, as 10.2.2 does and as Lucene has promised since LUCENE-10428 (9.1.0: 'Queries with a misbehaving score function may no longer cause infinite loops in their parent BooleanQuery'). With assertions disabled it never returns: MaxScoreBulkScorer treats the -1 clause as non-essential at the initial minimum competitive score 0 and calls ScorerUtil.minRequiredScore(-1.0, 0f, 2), whose loop starts at 1.0 and subtracts Math.ulp(0f) = 1.4e-45, a step that is lost in double arithmetic, so its exit test never changes. The same happens without custom code through RescoreTopNQuery over negative values, and IndexSearcher#setTimeout does not stop it.",
   "impact_class": "hang",
   "introduced_commit": "bf848a9a3ab468e7b7e05ee52cb5550c284092f0 ('Fix test failures.', jpountz, pushed to main without a PR of its own; branch_10x 678b54f9147) gave the loop its exit test 'minRequiredScore > 0 && (float) sumUpperBound(...) >= minCompetitiveScore', which never becomes false for a negative maxRemainingScore at minCompetitiveScore 0 [exec]; it is a same-day follow-up to 62e02760321 (apache/lucene#14827 'Pre-calculate minRequiredScore to speedup filterCompetitiveHits', by HUSTERGS, merged by jpountz; branch_10x 5687ed5e8a0), which added the loop but exits at once for this input [exec]; the released form is the next follow-up 3f71b54c47a (branch_10x d0a4b104214), also hanging [exec]. Path enabler: b5e79a345fb (#14701, 2025-05-25) made MaxScoreBulkScorer.scoreNonEssentialClauses call filterCompetitiveHits, guarded only by an assert [read]. The LUCENE-10428 guard of the predecessor loop (44a2a82319c, #711, 9.1.0) was deleted with MaxScoreSumPropagator in 37a42219fc7 (#12490, 9.8.0) [read]",
   "introduced_date": "2025-07-03 (bf848a9a3ab 16:15:24Z; #14827 merged 11:26:29Z, PR opened 2025-06-21; 3f71b54c47a 21:05:02Z; author date = commit date for the follow-ups)",
   "first_affected_version": "10.3.0 [exec]; 10.2.2 returns the hits, as do 9.12.3 and 10.0.0 to 10.2.1 [exec]",
   "affected_versions": "10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 [exec]; 10.6.0 RC1, released as 10.6.0 on 2026-10-29 (branch_10_6 4ae946e5a9b9, core jar) [exec]; unreleased branch_10x 657014b3c57 [exec], main 645d4fe14a20 [exec]; the method text is byte-identical from 10.3.0 to main [read]. Not affected: 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.2.1 and 10.2.2 return the hits [exec]; 9.0.0 and 9.1.0 throw IllegalArgumentException 'Scores must be positive or null' from WANDScorer [exec]; minRequiredScore does not exist before 10.3.0 [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/11464",
    "https://github.com/apache/lucene/issues/711",
    "https://github.com/apache/lucene/issues/14827",
    "https://issues.apache.org/jira/browse/LUCENE-10428",
    "https://github.com/apache/lucene/issues/12490",
    "https://github.com/apache/lucene/issues/15413"
   ],
   "doc": "",
   "repro": "repro/LFV-1016/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1048",
   "priority": "medium",
   "priority_rank": 55,
   "novelty": "new",
   "withheld": false,
   "area": "join / block join iterator (ParentsChildrenBlockJoinQuery advance() and Weight#explain; reached through ConjunctionDISI, sorted-search competitive iterators and IndexSearcher.explain)",
   "title": "ParentsChildrenBlockJoinQuery: advance() does not count the matching children it skips, so conjunctions, sorted searches and explain return children beyond childLimitPerParent",
   "summary": "You index the blocks [a, b, p1] and [c, p2] and build a ParentsChildrenBlockJoinQuery with childLimitPerParent 1, which on its own matches a and c, the first matching child of each parent. You expect the BooleanQuery +join #id:b to match nothing and explain(join, b) to say it is not a match. Instead the conjunction returns b and explain reports b as a match: advance(target) starts counting the limit at the target instead of at the block's first child, so it returns a child that nextDoc() never returns, which breaks the DocIdSetIterator#advance contract.",
   "impact_class": "silent wrong results",
   "introduced_commit": "1584c05b27ac31fbccb0ab328bf9f8eb6a7de414 (main, squash merge of apache/lucene#14728 '[BlockJoin] Add ParentsChildrenBlockJoinQuery', author Jinny-Wang, reviewed by msfroh and karthi01ec; implements feature request #14565) and its branch_10x backport 61b32ff6d3772906b12b9e7f855b8607e9261371 (same file blob 0d14191bace) [read]",
   "introduced_date": "2025-06-13 (main squash merge); branch_10x backport committed 2025-09-04",
   "first_affected_version": "10.4.0 [exec] (the first release with the class; 10.3.2 and 9.12.3 do not have it and the repro does not compile there [exec])",
   "affected_versions": "[exec] main 645d4fe14a20 (-ea and -da: finder, adjudication, the independent reproduction, a separate re-run, the intended-behaviour check and the re-run) and every release with the class: 10.4.0 (-ea and -da), 10.5.0, 10.5.1, 10.5.2 (-ea and -da) and 10.6.0 (SHA-1-verified Maven Central jars, commit 4ae946e5a9b; -ea and -da). Released in 10.6.0: the tag releases/lucene/10.6.0 exists (tag object e29d290eeb05, peels to 4ae946e5a9b; git ls-remote 2026-10-29). [read] upstream main 716d6f216f5 (same file blob 4274dc5e8bb as 645d4fe) and branch_10_6 head 7e5aec4370e (same blob bc60a3f3331 as the 10.6.0 tag). Not applicable: 10.3.2, 9.12.3 and older (no such class). Not new in 10.6",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1048.html",
   "repro": "repro/LFV-1048/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-424",
   "priority": "medium",
   "priority_rank": 56,
   "novelty": "new",
   "withheld": false,
   "area": "search / rescoring (SortRescorer; expressions ExpressionRescorer inherits rescore())",
   "title": "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)",
   "summary": "You run a search, take its top hits and call new SortRescorer(sort).rescore(searcher, hits, topN), or Expression#getRescorer(bindings).rescore, with topN smaller than the number of hits, for example to re-sort the best 1,000 hits by popularity and keep the top 100 as the search package docs suggest. You expect the top N hits in sort order, each with its own first-pass score, which is what every release up to 7.7.3 returned and what you still get when topN is at least the number of hits. Instead the documents and their order are right, but the k-th smallest doc id among the returned hits gets the score of the k-th smallest doc id among all first-pass hits, so nearly every returned hit carries another hit's score (with 2 hits and topN=1, doc 1 comes back with doc 0's score), and with assertions enabled rescore throws AssertionError at SortRescorer.java:86.",
   "impact_class": "silent wrong results",
   "introduced_commit": "55bfadbce115a825a75686fe0bfe71406bc3ee44 (LUCENE-8412 'TopFieldCollector no longer takes a trackDocScores option', by jpountz, master only, 2018 JIRA patch workflow without a GitHub PR; the issue was later migrated as apache/lucene#9459) [read]. No commit-level bisect (building 55bfadbce11^ and 55bfadbce11 would need the 2018 build). Regression: SortRescorer and Expression#getRescorer exist since 4.8.0 (LUCENE-5545, cbd8cacc50c) and returned each hit's own score until 7.7.3",
   "introduced_date": "2018-07-23 (55bfadbce11 on master; first release tag containing it: 8.0.0, 2019-03-08)",
   "first_affected_version": "8.0.0 [exec]",
   "affected_versions": "all 60 releases from 8.0.0 to 10.5.2 (8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2) and main ea57360912ed [exec]; not affected: all 14 releases from 7.0.0 to 7.7.3 [exec] and 4.8.0-6.6.6 [read]; upstream main cf398bfb142c and branch_10x still have the assert and the copy loop [read]; branch_10_6 (10.6.0, released 2026-10-29) still has the assert and the copy [read]; not fixed anywhere",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-424.html",
   "repro": "repro/LFV-424/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-582",
   "priority": "medium",
   "priority_rank": 57,
   "novelty": "new",
   "withheld": false,
   "area": "search / IndexSearcher#termStats distributed-statistics hook (SynonymQuery, MultiPhraseQuery, CombinedFieldQuery, SpanWeight)",
   "title": "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)",
   "summary": "You search one shard of a collection with an IndexSearcher whose termStats and fieldStats overrides return the statistics of the whole collection, as their javadoc suggests, and run SynonymQuery(quick, fast) where 'fast' occurs only on another shard. You expect each document to get the score it gets when you search the whole collection, as TermQuery and PhraseQuery do. Instead the query asks the override only about 'quick', because it calls termStats only for terms whose local docFreq is above 0, so it scores the document 0.573 instead of 0.170 and ranks it above an equally relevant document on the other shard; MultiPhraseQuery, CombinedFieldQuery and SpanOrQuery are off the same way.",
   "impact_class": "silent wrong results",
   "introduced_commit": "a80534a589d20b9aacdcc8677b5b30747f3b893a (branch_8x backport, shipped in 8.3.0) and the master original fd0c8b9e810737a119868b8d18d4ed55d5e9c607 (first released in 9.0.0; git blame on main credits it with all four docFreq > 0 checks): LUCENE-8921 'IndexSearcher.termStatistics API change' (issue apache/lucene#9964, PR apache/lucene-solr#797, committed directly with 'Closes #797'; author bruno-roustant, committer dsmiley, 2019-09-17), which replaced the callers' 'termStats != null' checks (the LUCENE-8020 contract of 8.0-8.2, where the overridable hook itself decided that a term is absent by returning null) with 'if (ts.docFreq() > 0)' on the local TermStates before calling the hook [read]. The hook itself dates from LUCENE-3555 'add support for distributed stats' (b19a207c866, 2011-11-04, 4.0.0).",
   "introduced_date": "2019-09-17",
   "first_affected_version": "8.3.0 [exec] (tagged 2019-10-31); last unaffected 8.2.0 [exec]. For the core CombinedFieldQuery class, 10.2.0, its first core release [exec]; the same check was in the sandbox BM25FQuery/CombinedFieldQuery from 8.3.0, whose score cannot be compared before 9.3.0 because overridden statistics made it throw (LUCENE-10582, a different, fixed bug), but its hook call log already loses title:fox on 8.3.0 [exec]",
   "affected_versions": "every release from 8.3.0 through 10.6.0 (10.6.0 by reading) and main a9779ef3c193 (and the previous hunt main ea57360912ed: the gated files are byte-identical, checked by the cross-model review); the branch_10_6 head (2026-10-24, the line released as 10.6.0) and the unreleased branch_10x head (2026-10-24) have the same checks [read]. [exec] pass (shard score == whole-collection score, hook asked about the locally absent term) on 7.7.3, 8.0.0 and 8.2.0; fail (hook never asked) on 8.3.0, 8.11.4 and 9.0.0 (4 of 4 comparable families), 9.12.3, 10.2.0, 10.5.2 and main (5 of 5, with CombinedFieldQuery). [exec] the finder's JUnit fails 5 of 7 on main with -ea and -da (its 2 controls pass); the independent reproduction's JUnit fails 5 of 8 on main (-ea, -da), 10.5.2 and 9.12.3 (its 3 controls pass); the finder's release main() fails on 8.3.0, 8.11.4, 9.12.3 and 10.5.2 and passes on 8.0.0 and 8.2.0 with the pre-8.3 hook; separate runs: main -ea/-da and 10.5.2 fail, 8.2.0 passes. Not run: 8.1.x, releases before 7.7.3, and the 8.3.0-10.5.2 releases between the executed ones (inferred by commit containment). The hook did not exist before 4.0.0. The candidate's JUnit uses the main-only names termStats/fieldStats (#15929), so release runs use main() checks with each version's own hook signature. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-582.html",
   "repro": "repro/LFV-582/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-190",
   "priority": "medium",
   "priority_rank": 58,
   "novelty": "known",
   "withheld": false,
   "area": "search / similarities and top-k bulk scoring (IndriDirichletSimilarity, TermQuery bulk scorer, BatchScoreBulkScorer)",
   "title": "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",
   "summary": "You set IndriDirichletSimilarity on the writer and the searcher, run a plain TermQuery with IndexSearcher#search(query, 10), and expect the documents that count() and explain() report as matches. Since 10.3.0 you get no hits at all: the similarity scores are logarithms of probabilities and therefore negative, and the batch bulk scorer that TermQuery uses since 10.3.0 hands a hit to the collector only if its score is at least the minimum competitive score, which starts at 0. In the 4-document repro the term 'washington' matches 2 documents (explain value -1.098113) and search returns 0 of them; 10.2.2 returns both.",
   "impact_class": "silent wrong results",
   "introduced_commit": "12c3041d3907e300c3d57bf67bc638b555eb68a7 on main and its branch_10x backport adbf9a9e0110f05c997b1d1ee358b31f26af500a (the released copy), apache/lucene#14709 'Speed up TermQuery' by gf2121, merged 2025-05-26: it added BatchScoreBulkScorer, which collects a document only 'if (score >= scorable.minCompetitiveScore)' while SimpleScorable.minCompetitiveScore starts at 0f, and changed TermQuery's ScorerSupplier.bulkScorer() from 'return super.bulkScorer();' to 'return new BatchScoreBulkScorer(get(Long.MAX_VALUE));' for every score mode that needs scores; git blame on main gives BatchScoreBulkScorer.java:37-62 and TermQuery.java:175 to it, except the filter lines 53-56, last rewritten with the same text by the revert 46a4fee6558 of #14970 [read]; exec: release bracket (10.2.2 returns both hits, 10.3.0 none, with -ea and -da) and a one-line revert of the TermQuery change shadowed onto the stock 10.3.0 and main jars restores the hits; no commit-level build. Precondition, older: LUCENE-9537 (9cc5c9b7983 on main, a6125fb9385 on branch_8x, by cammiemw, 2021-01-29; apache/lucene#10577) added IndriDirichletSimilarity with score = log((freq + mu*P(t|C)) / (docLen + mu)) and exempted it from BaseSimilarityTestCase's non-negative checks, after LUCENE-7996 had required non-negative scores in 8.0.0 [read]",
   "introduced_date": "2025-05-26 (#14709, silent hit loss); 2021-01-29 (LUCENE-9537, negative scores)",
   "first_affected_version": "10.3.0 [exec] (10.2.2 returns both hits with -ea and -da [exec]; git tag --contains finds no release for the main commit and exactly 10.3.0-10.6.0 for the backport [read]); the underlying negative scores since 8.9.0, the first release with IndriDirichletSimilarity [exec]",
   "affected_versions": "Silent zero hits [exec]: 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main ea57360912ed, all with -da, and 10.3.0, 10.5.2 and main also with -ea. Not affected [exec]: 8.9.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.2.1 and 10.2.2 return the hits with -da; 10.1.0-10.2.2 also with -ea, while 8.9.0-10.0.0 with -ea fail on the production assertion (#13939 moved it to the test framework in 10.1.0), not by losing hits. The 9.x line never got BatchScoreBulkScorer; before 8.9.0 the similarity does not exist. Not fixed upstream: BatchScoreBulkScorer.java and IndriDirichletSimilarity.java unchanged on main, branch_10x and branch_10_6 (follow-up prior-report record, read 2026-10-26), so 10.6.0 is affected too (10.6.0 by reading).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene-solr/pull/2097",
    "https://github.com/apache/lucene/issues/463",
    "https://github.com/apache/lucene/issues/15239",
    "https://github.com/apache/lucene/issues/14709",
    "https://github.com/apache/lucene/issues/16542",
    "https://issues.apache.org/jira/browse/LUCENE-9537"
   ],
   "doc": "",
   "repro": "repro/LFV-190/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-484",
   "priority": "medium",
   "priority_rank": 59,
   "novelty": "known",
   "withheld": false,
   "area": "search / BlendedTermQuery cross-field statistics blending",
   "title": "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",
   "summary": "You build a BlendedTermQuery for \"lucene\" on the fields title and keywords, as its javadoc suggests for cross-field search, over an index where two titles contain \"lucene\" and only one document has a keywords field at all. You expect every matching document back with a non-negative score, and a field that no document has yet to simply match nothing. Instead the query gives keywords:lucene the largest docFreq of all its terms (2) although only 1 document has the keywords field, so BM25's idf turns negative and that document scores -0.10 and is ranked last, since 10.3 it is missing from search(q, 10) when it sits in a segment of its own (count(q) = 3, 2 hits returned), and when no document has the keywords field yet, search() throws NullPointerException.",
   "impact_class": "silent wrong results",
   "introduced_commit": "9dc862147e33fe7de65965bac7112d606615f197 (activating change: LUCENE-6711 = apache/lucene#7769, svn r1695744 on trunk, 2015-08-13, committed from an attached patch, no pull request, not backported to branch_5x), which switched the BM25, TF-IDF and SimilarityBase idf N from maxDoc to the field's docCount; BlendedTermQuery's older max-docFreq blending was not adapted, so a sparse field's term now gets docFreq > N and a negative BM25 idf [exec]. The defective blending itself is e1558fef1c1f02de488f13e5604152bc7529c778 (LUCENE-6695 = #7753, svn r1692848 trunk; branch_5x c6faa7076387, r1692864; 2015-07-27; first released in 5.3.0): df = max docFreq and ttf = sum totalTermFreq over all terms, applied to every term regardless of its field; the df line is unchanged on main (BlendedTermQuery.java:286) [read]; latent with the shipped similarities until LUCENE-6711 [exec]. Later symptom changes, same root cause [read]: e0bde579815 LUCENE-8020 (2017-10-30, 8.0.0: absent-field NullPointerException, because TermWeight now guards only termStates.docFreq() > 0, which the artificial docFreq defeats, while the field statistics are null); a8a63464e7d LUCENE-7996 (2017-12-06, 8.0.0: non-negative score rule and TopScoreDocCollector 'assert score >= 0', AssertionError under -ea); f8ea1305144 on main / ff03379eb6e on branch_10x, #13939 (2024-10-22, 10.1.0: that assertion removed); 12c3041d390 on main / adbf9a9e011 on branch_10x, #14709 (2025-05-26, 10.3.0: BatchScoreBulkScorer collects only score >= minCompetitiveScore, initially 0, so the negative-scored hit is dropped). Not a regression of a recent change: the fix belongs in BlendedTermQuery",
   "introduced_date": "2015-08-13 (activating change 9dc862147e3, LUCENE-6711); blending code 2015-07-27 (e1558fef1c1, LUCENE-6695); NullPointerException from 2017-10-30 (LUCENE-8020); dropped hit from 2025-05-26 (#14709)",
   "first_affected_version": "6.0.0 [exec] (negative scores; tagged 2016-04-07). BlendedTermQuery first appears in 5.3.0 (5.2.1 lacks it [exec]); 5.3.0 and 5.5.5 pass with BM25 and the default TF-IDF because their idf used maxDoc [exec]. The absent-field NullPointerException from 8.0.0 [exec]; the dropped hit from 10.3.0 [exec]",
   "affected_versions": "every release from 6.0.0 to 10.5.2 and main ea57360912ed; never fixed (upstream main a9779ef3c193, 2026-10-26, still blends without a per-field bound [read]). [exec] the follow-up's portable main() probe (BM25 set explicitly, both rewrite methods, 1 and 3 segments, absent field; its plain-BooleanQuery control passes on every version): 6.0.0 and 7.7.3 negative scores, hit returned; 8.0.0, 8.11.4, 9.0.0, 9.12.3 and 10.0.0 add the absent-field NullPointerException and, under -ea, AssertionError 'score >= 0' in TopScoreDocCollector (negative scores returned under -da); 10.1.0 and 10.2.2 negative score, hit returned, NullPointerException; 10.3.0, 10.5.2 and main the hit is dropped from search(q, 10) in the 3-segment layout (count 3, 2 hits), negative score in 1 segment, NullPointerException, with -ea and -da. Not affected with BM25 or the default TF-IDF: 5.3.0 and 5.5.5 [exec]. The finder's JUnit fails 3 of 3 on main (-ea, -da), 10.5.2 (-ea, -da), 10.3.0, 10.2.2 and 9.12.3 (-ea, -da); the independent reproduction's JUnit fails 3 of 4 (its control passes) on main (-ea, -da), 10.5.2, 10.3.0, 10.2.2 and 9.12.3 (-ea, -da). Other releases by commit containment [read]. Lucene's internal single-field use (TopTermsBlendedFreqScoringRewrite, e.g. FuzzyQuery) is not affected in any version [read]. Not checked: non-default 5.x similarities (LM, DFR, IB) on the already out-of-bounds 5.x statistics; similarities other than BM25 (only the finder's harness saw the NullPointerException with Classic, LM, DFR, IB, DFI, Axiomatic and MultiSimilarity); x86. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [
    "https://lists.apache.org/thread/mbfddo8d5bvw9h9ft39wdr18swnq0wn3",
    "https://github.com/apache/lucene/issues/9542",
    "https://github.com/apache/lucene/issues/13829",
    "https://github.com/apache/lucene/issues/7753",
    "https://issues.apache.org/jira/browse/LUCENE-6695",
    "https://github.com/apache/lucene/issues/7769"
   ],
   "doc": "",
   "repro": "repro/LFV-484/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-413",
   "priority": "medium",
   "priority_rank": 60,
   "novelty": "new",
   "withheld": false,
   "area": "misc / similarities (SweetSpotSimilarity) with core impacts-based TOP_SCORES pruning",
   "title": "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",
   "summary": "You score a field with SweetSpotSimilarity and setLengthNormFactors(10, 20, 0.5f), index mostly 10-term fields plus some shorter ones, and run searcher.search(new TermQuery(new Term(\"f\", \"t\")), 10) on a term with more than 1,000 matches, expecting the same top hits as an exhaustive search. Instead a 10-term document that contains the term twice (score 1.414) is missing and a document that contains it once (score 1.0) comes first. Below the plateau a 2-term field scores lower than a 10-term field although its norm is smaller, which breaks the rule that a greater norm never scores higher; the postings writer relies on that rule, keeps only the short field's (freq, norm) pair for the block, advertises a block maximum of 0.471, and top-k search skips the block.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f410df81136291f61b8deaace22bf4bb650de1ad (LUCENE-4198 'Give codecs the opportunity to index impacts', a JIRA patch by jpountz, migrated as apache/lucene#5270; no pull request): it added CompetitiveFreqNormAccumulator (today CompetitiveImpactAccumulator), which drops a (freq, larger norm) pair as dominated, and TermScorer block skipping under TOP_SCORES [exec]. Companion commits, same author, same 8.0 development line: 838c604b765 (LUCENE-8119, #9167) wrote the norm-monotonicity rule into Similarity and is the earliest commit with any plateau-specific wrong hit (explicit TOP_SCORES disjunctions; that exposure was removed by LUCENE-8135 before any release); 99dbe936818 (LUCENE-8060, #9108) made the default search(q, n) use TOP_SCORES after 1,000 hits [exec]. Latent precondition, harmless before 8.0: 06a6034d9bc (LUCENE-7730, 7.0.0) encodes the field length as the norm; the plateau formula dates from LUCENE-577 (2006)",
   "introduced_date": "2018-01-31 (f410df81136; the contract commit 838c604b765 is 2018-01-09 and the default-search commit 99dbe936818 is 2018-08-01)",
   "first_affected_version": "8.0.0 [exec]; 7.0.0 and 7.7.3 are not affected [exec]; none of the four 2018 commits was backported to 7.x [read]",
   "affected_versions": "Every release from 8.0.0 to 10.5.2 and main ea57360912ed; not fixed upstream (the last upstream commit to SweetSpotSimilarity.java is 7c056ab88c7, #13757, 2024-09-13, a refactor; no open PR touches the fix sites; read 2026-10-26). [exec] The history probe HistSweetSpotProbe (one public-API source for every version) misses the top hit of a TermQuery top-k search on 8.0.0, 8.11.4, 9.0.0, 9.1.0, 9.2.0, 9.3.0, 9.4.0, 9.6.0, 9.7.0, 9.8.0, 9.9.0, 9.10.0, 9.11.1, 9.12.0, 9.12.1, 9.12.2, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da on main), with its controls agreeing everywhere; on its data 2-clause disjunctions also miss the top hit on 9.3.0-9.7.0, 9.12.0-9.12.3, 10.0.0, 10.5.2 and main (the other releases' disjunction scorers did not prune those layouts, which does not show them safe); the finder's JUnit fails on 9.12.3, 10.5.2 and main (-ea and -da) and its portable main() on 8.0.0, 8.11.4, 9.0.0 and 9.1.0; the independent reproduction's JUnit fails on 9.12.3, 10.5.2 and main (-ea and -da). [read] Releases not executed (8.1.0-8.10.1, 9.5.0, 10.1.0-10.5.1) lie between affected ones with the same mechanism; unreleased branch_10x and 10.6.0 (released 2026-10-29) not checked separately",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-413.html",
   "repro": "repro/LFV-413/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-253",
   "priority": "medium",
   "priority_rank": 61,
   "novelty": "new",
   "withheld": false,
   "area": "search / CombinedFieldQuery (BM25F) max-score bound under dynamic pruning (CombinedFieldScorer.getMaxScore as used by MaxScoreBulkScorer)",
   "title": "CombinedFieldQuery computes its max score as score(+Infinity, 1), which is NaN under AxiomaticF2LOG/F2EXP, so top-k pruning silently drops the best hits",
   "summary": "You score a query with CombinedFieldQuery under the core AxiomaticF2LOG (or AxiomaticF2EXP) similarity, which the class javadoc counts as compatible because it keeps the default computeNorm, put it in a BooleanQuery next to another scoring clause such as a TermQuery, and expect IndexSearcher#search(q, 10) to return the same top hits as an exhaustive search. CombinedFieldScorer reports score(Float.POSITIVE_INFINITY, 1) as its max score, although SimScorer#score requires a finite freq and documents score(Float.MAX_VALUE, 1) as the bound; for the F2 similarities that is Inf/Inf = NaN, and MaxScoreBulkScorer, for which NaN is never below the minimum competitive score, then makes the other clause required. Documents that match only the CombinedFieldQuery are skipped: in a 3000-document index the default search returns doc 0 (score 2.1975672) as the top hit instead of doc 2000 (6.383921), and the upstream oracle CheckHits.checkTopScores fails.",
   "impact_class": "silent wrong results",
   "introduced_commit": "de1feea4013a74ab63a94155d9724b0b1892390c (apache/lucene#13999 'Make CombinedFieldQuery eligible for WAND/MAXSCORE.' by jpountz, merged 2024-11-22, milestone 10.1.0; branch_10x backport b12404b09b3a744323ceddff841dc2e39f1d5024, the commit contained in the 10.x release tags) [read]. #13999 replaced getMaxScore's 'return Float.POSITIVE_INFINITY' with score(Float.POSITIVE_INFINITY, 1L). apache/lucene#14236 (239059e69cf main / cddee429c70 branch_10x, 2025-02-19) moved the class, with the line, into lucene/core; it is not the cause",
   "introduced_date": "2024-11-22",
   "first_affected_version": "10.1.0 [exec] (the sandbox class org.apache.lucene.sandbox.search.CombinedFieldQuery: the repro fails 2 of 2, and passes 2 of 2 with only the #13999 hunk reverted); the core class org.apache.lucene.search.CombinedFieldQuery first shipped in 10.2.0 and is affected from the start [exec]; 10.0.0 and 9.12.3 are not affected [exec] (getMaxScore returned +Infinity there)",
   "affected_versions": "10.1.0 (sandbox class), 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2, 10.6.0 (by reading) and main ea57360912ed [exec]; not affected: 10.0.0 and 9.12.3 [exec], 9.12.0-9.12.2 and 8.x (then BM25FQuery) [read]; the branch_10x and branch_10_6 heads still contain the line [read]; not fixed upstream as of 2026-10-26 (the line is still at CombinedFieldQuery.java:416 on apache/lucene main and at :420 on branch_10x and branch_10_6). Caveats: each release was run with one seed on JDK 25.0.3 aarch64; x86 and a concurrent searcher with an executor were not run",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-253.html",
   "repro": "repro/LFV-253/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-874",
   "priority": "medium",
   "priority_rank": 62,
   "novelty": "known",
   "withheld": false,
   "area": "search / IndriAndQuery (IndriDisjunctionScorer iteration over two-phase clauses)",
   "title": "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()",
   "summary": "You build an IndriAndQuery from SHOULD clauses, for example the phrase \"a b\" plus the term c, or a doc-values range n in [1, 10] plus the term c, and expect the documents that match at least one clause, as its javadoc ('matches documents matching combinations of subqueries') says. Instead it also returns documents that are only cheap candidates of the phrase or range clause: 'b a' (both terms, no phrase) in the phrase case and the documents with n=50 and n=100 in the range case, and count() agrees with the wrong hits (3 instead of 2, and 4 instead of 2, in the 4-document repro). IndriDisjunctionScorer walks the approximations of its two-phase clauses and never runs their exact matches() check; a segment where only one clause has a scorer is exact, so the same document can be rejected in one segment and returned in another.",
   "impact_class": "silent wrong results",
   "introduced_commit": "9cc5c9b7983cf181280e18819f8516dc16ccf1ef (LUCENE-9537 'Add initial Indri search engine functionality to Lucene', author cammiemw, apache/lucene-solr#2097, feature issue now apache/lucene#10577), released through its branch_8x backport a6125fb938553fe2cd8cd035b8ffb329a7a1a288 (same author date) [read]; not a regression: the later commits d0d2aa274fb (#13440), f9869b54d54 (#14023), bc341f2b3e6 (#14052) and 54283150a81 (#16255) are mechanical and keep the approximation-only iterator",
   "introduced_date": "2021-01-29",
   "first_affected_version": "8.9.0 [exec] (first on the main line: 9.0.0 [exec]); the API does not exist before 8.9.0 [exec]",
   "affected_versions": "Every release that has the class: 8.9.0 to 8.11.4, 9.0.0 to 9.12.3 and 10.0.0 to 10.5.2, 41 releases, plus 10.6.0 (the branch_10_6 head 4ae946e5a9b9, released 2026-10-29). [exec] finder JUnit (or its 8.x/9.0 port, which differs only in two test-framework imports) fails with the same wrong hits on 8.9.0 (-ea and -da), 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da), branch_10_6 head 4ae946e5a9b9 (-da) and main a9779ef3c193 (-ea and -da, re-run at the registration check); the independent reproduction's own JUnit fails on main, 10.5.2 and 9.12.3, the intended-behaviour check's own JUnit on main and 10.5.2. [read] the other releases: the code is unchanged in this respect between the executed versions (10.0.0, before #14023/#14052, and 10.5.2, after them, give the same hits); upstream main c5ab3e57b9ba (2026-10-28) unchanged, the last commit on IndriDisjunctionScorer.java is 54283150a81 (author date 2026-06-14, typo check). Not applicable to 8.8.2 and earlier: no IndriAndQuery. All runs on aarch64 Linux with JDK 25.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/11194",
    "https://github.com/apache/lucene/issues/10577",
    "https://github.com/apache/lucene/issues/463",
    "https://github.com/apache/lucene/issues/11928",
    "https://github.com/apache/lucene/issues/11290",
    "https://github.com/apache/lucene/issues/7477"
   ],
   "doc": "",
   "repro": "repro/LFV-874/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-173",
   "priority": "medium",
   "priority_rank": 63,
   "novelty": "known",
   "withheld": false,
   "area": "search / score fusion (LogOddsFusionQuery: LogOddsFusionWeight#scorerSupplier)",
   "title": "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",
   "summary": "You combine two or more probability clauses (for example a BayesianScoreQuery over BM25 and a kNN query) with LogOddsFusionQuery and search an index that has more than one segment. You expect every document to get the documented fused score, sigmoid(n^alpha * mean of the gated log-odds over all n clauses), which is also what explain() reports, whichever segment holds the document. Instead, in a segment where only one clause has a scorer, the query hands back that clause's own scorer unchanged, so documents there get the raw clause score: in the repro two documents with identical content score 0.6386912 and 0.5532073, while explain() reports 0.6386912 for both.",
   "impact_class": "silent wrong results",
   "introduced_commit": "5af15dc4be5b (GITHUB#15827 'Add BayesianScoreQuery and LogOddsFusionQuery for probabilistic hybrid search', by jaepil; branch_10x backport 7f55b56a40de, plus e8d1a2a26d6e 'Adjusting for backport', which only adds throws IOException to setTopLevelScoringClause): the size() == 1 shortcut came with the class [read]; kept by d9aa7cbc47d4 (GITHUB#15948, which added weights and logit bounds that the shortcut also skips), 3c607cfb3882 (GITHUB#16106, rewrite only) and bc601411a316 (GITHUB#16519, cost() signature only) [read]",
   "introduced_date": "2026-03-27 (PR merge)",
   "first_affected_version": "10.5.0 [exec] (the first release with LogOddsFusionQuery; 10.4.0 and 9.12.3 do not have the class, so the repros do not compile there [exec])",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2 (the last release before 10.6.0) and main ea57360912ed [exec]; the shortcut is at line 232 on upstream main, branch_10x, branch_10_6 (so 10.6.0, by reading), branch_10_5 and the 10.5.2 tag [read]; not fixed upstream: open PR #16410 removes it but is not merged",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16410",
    "https://github.com/apache/lucene/issues/15827",
    "https://github.com/apache/lucene/issues/15948",
    "https://github.com/apache/lucene/issues/16106"
   ],
   "doc": "",
   "repro": "repro/LFV-173/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-443",
   "priority": "medium",
   "priority_rank": 64,
   "novelty": "known",
   "withheld": false,
   "area": "search / score fusion (LogOddsFusionQuery: LogOddsFusionScorer#score with per-signal logit bounds and null weights)",
   "title": "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()",
   "summary": "You combine two probability clauses with LogOddsFusionQuery(clauses, 0.5f, null, logitMin, logitMax), giving each clause its own logit bounds and no weights (null means uniform weighting). You expect each clause's logit to be normalized with its own bounds, as the constructor javadoc ('per-signal' bounds), explain() and getMaxScore() all do. Instead score() normalizes every clause with the first clause's bounds: in the repro a document that matches only the second clause (p = 0.6, bounds [-1, 1]) scores 0.50071675 while explain() reports the documented 0.6217322, and with the bounds the other way round a document that matches both clauses scores 0.76923805, above the scorer's own getMaxScore() of 0.6703954.",
   "impact_class": "silent wrong results",
   "introduced_commit": "d9aa7cbc47d4a67b7eb43d56c710c869d6e9e183 (apache/lucene#15948 'Improve BayesianScoreQuery and LogOddsFusionQuery with base rate prior, weighted Log-OP, and parameter estimation', by jaepil, co-authored and merged by benwtrent; branch_10x backport a68d7daad8965ac3d16a4c04fdb761cfbdc4ee75, whose LogOddsFusionScorer.java is byte-identical): it added the per-signal weights, the per-signal logit bounds, the public 5-argument constructor, the scorerIndexMap that is built only when signalWeights != null and the 'idx >= 0 ? idx : 0' fallback in score() [read] [exec]; present since the bounds were added, not a regression: the class itself came with #15827 (5af15dc4be5, 2026-03-27) without bounds or per-clause state, and both shipped first in 10.5.0",
   "introduced_date": "2026-05-27 (PR merge; the branch_10x backport was committed the same day)",
   "first_affected_version": "10.5.0 [exec] (the first release with LogOddsFusionQuery; 10.4.0 and 9.12.3 do not have the class, so the repro does not compile there [exec])",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2 (the last release before 10.6.0) and main ea57360912ed [exec]; LogOddsFusionScorer.java is byte-identical at the 10.5.0, 10.5.1 and 10.5.2 tags and on main, and upstream main and branch_10_6 have the same file [read], so the released 10.6.0 carries it; not fixed upstream: open PR #16410 would remove it but is not merged",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16410",
    "https://github.com/apache/lucene/issues/15948",
    "https://github.com/apache/lucene/issues/15827",
    "https://github.com/apache/lucene/issues/16106"
   ],
   "doc": "",
   "repro": "repro/LFV-443/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-322",
   "priority": "medium",
   "priority_rank": 65,
   "novelty": "known",
   "withheld": false,
   "area": "monitor / presearcher (RegexpQueryHandler custom query handler)",
   "title": "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",
   "summary": "You build a Monitor whose presearcher uses RegexpQueryHandler, register ordinary regexp queries such as /cat|dog/, /colou*r/ or /e.?mail/, and match documents containing 'dog', 'color' or 'email'. You expect Monitor.match to report each query, because the regexp matches the document and the presearcher may only skip queries that cannot match. Instead the handler indexes each query under a piece of its pattern text cut only at '.', '*' and '?' ('cat|dog', 'colou', '?mail'), no document term contains that piece, so the query is never run and the match is silently lost.",
   "impact_class": "silent wrong results",
   "introduced_commit": "251dbe7cea81 (LUCENE-8766 'Add monitor subproject', by GitHub romseygeek, main) and its branch_8x twin b8773d13ad8e (identical RegexpQueryHandler.java), released in 8.2.0 [read]; not a regression: the defective split is in the class's first version and the later commits 2cbf261032d (LUCENE-9570 reformat), 97464ebfcb9 (#13049 indexOf(char)) and b59848c7049 (#15842 instanceof pattern) are behaviour-neutral; the identical split predates Lucene (the donated luwak class RegexpNGramTermQueryTreeBuilder, luwak commits 5ede0ef760 of 2015 and 6c2679ba79 of 2018)",
   "introduced_date": "2019-06-13 (251dbe7cea8 on main and b8773d13ad8 on branch_8x the same day; first released in 8.2.0, tagged 2019-07-25)",
   "first_affected_version": "8.2.0 [exec] (the first lucene-monitor release; 8.1.1 and earlier have no monitor module: the 8.1.1 artifact does not exist, setup error [exec])",
   "affected_versions": "every published lucene-monitor release, 8.2.0 to 10.5.2 (57 versions) and 10.6.0 (by reading), and main ea57360912ed; no fixed release. [exec] 8.2.0, 8.3.1, 8.4.0, 8.4.1, 8.5.2, 8.6.3, 8.7.0, 8.8.2, 8.9.0, 8.10.1, 8.11.4, 9.0.0, 9.1.0, 9.2.0, 9.3.0, 9.4.2, 9.5.0, 9.6.0, 9.7.0, 9.8.0, 9.9.2, 9.10.0, 9.11.1, 9.12.3, 10.0.0, 10.1.0, 10.2.2, 10.3.2, 10.4.0, 10.5.2 and main (8.2.0, 9.12.3, 10.5.2 and main also with -da; 8.x and 9.0.0 with an import-only variant of the repro); the independent reproduction's own test fails on main (-ea, -da), 10.5.2 and 9.12.3; the intended-behaviour check's in-scope probe fails on main (-ea, -da) and 10.5.2; the case-insensitive form fails on main and 10.5.2 (security probe); [read] the split line is byte-identical at every release tag 8.2.0-8.8.1 and 9.0.0-10.5.2; 8.2.0-8.3.1 were slightly wider: single-string regexps such as /ab{2}c/ were also missed there [exec] until LUCENE-9062 (8.4.0) routed them to the exact-term path; upstream main, branch_10x and branch_10_6 still contain the split line (read-only check 2026-10-26); not fixed anywhere",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/149",
    "https://issues.apache.org/jira/browse/LUCENE-8766",
    "https://github.com/apache/lucene/issues/15842",
    "https://github.com/apache/lucene/issues/9811",
    "https://github.com/apache/lucene-solr/pull/648",
    "https://github.com/apache/lucene/issues/14427"
   ],
   "doc": "",
   "repro": "repro/LFV-322/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-347",
   "priority": "medium",
   "priority_rank": 66,
   "novelty": "new",
   "withheld": false,
   "area": "monitor / presearcher (RegexpQueryHandler document-side ngram filter SuffixingNGramTokenFilter)",
   "title": "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",
   "summary": "You build a Monitor whose presearcher uses RegexpQueryHandler, register the query /hel.*/ and match a document whose text is 'hello😀' (WhitespaceAnalyzer, one token). You expect a match, because the regexp matches that token and the presearcher may only skip queries that cannot match. Instead SuffixingNGramTokenFilter, which should emit every substring of the token with the suffix 'XX' so that the query's index term 'helXX' is found, starts its gram size at the token's UTF-16 length (7) but checks it against the token's code-point count (6), gives up on the token without emitting a single ngram, and the query is silently never run.",
   "impact_class": "silent wrong results",
   "introduced_commit": "251dbe7cea81 (LUCENE-8766 'Add monitor subproject', by GitHub romseygeek, main) and its branch_8x twin b8773d13ad8e (same date; SuffixingNGramTokenFilter.java and RegexpQueryHandler.java byte-identical), released in 8.2.0 [read]; not a regression: the defect is in the file's first Lucene version, and the later commits 2cbf261032dc (LUCENE-9570 reformat), 40f674c5d3d3 (#13413 imports) and c2825cfc4b2a (#16063 final modifiers) are behaviour-neutral; the same lines are in the donated Luwak class (flaxsearch/luwak master, file last changed 2016-11-28) [read]",
   "introduced_date": "2019-06-13 (251dbe7cea81 on main and b8773d13ad8e on branch_8x the same day; first released in 8.2.0)",
   "first_affected_version": "8.2.0 [exec] (the first lucene-monitor release; 8.1.1 has no monitor module: the lucene-monitor 8.1.1 artifact does not exist on Maven Central, setup error [exec]); 9.0.0 [exec] on the main line",
   "affected_versions": "every lucene-monitor release, 8.2.0 to 10.6.0 (57 versions to 10.5.2; 10.6.0 by reading), and main ea57360912ed; no fixed release. [exec] 8.2.0, 8.8.2, 8.9.0, 8.10.0, 8.10.1, 8.11.0, 8.11.1, 8.11.2, 8.11.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main; the finder's JUnit fails 2 of 2 on main (-ea, -da), 10.5.2 and 9.12.3; the independent reproduction's own JUnit fails on main (-ea, -da), 10.5.2 and 9.12.3 and its main() variant on 8.2.0 and 8.11.4; a separate JUnit fails on main, 10.5.2 and 9.12.3; the security probe gives identical results on main (-ea, -da), 10.5.2 (-da) and 9.12.3 (-da); [read] all four defect lines are present at each of the 48 release tags 8.2.0-8.8.1 and 9.0.0-10.5.2 in the history clone; the fix sketch makes 8.2.0 and main pass [exec]; upstream main, branch_10x and branch_10_6 have no behaviour change to either file (commits by path, read 2026-10-26), but those branches were not built",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-347.html",
   "repro": "repro/LFV-347/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1115",
   "priority": "medium",
   "priority_rank": 67,
   "novelty": "known",
   "withheld": false,
   "area": "monitor / persistent query index (WritableQueryIndex, ReadonlyQueryIndex, QueryDecomposer)",
   "title": "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)",
   "summary": "You register the query f:alpha OR f:beta in a persistent Monitor on 10.2.2, upgrade to 10.3.0 or later, open the same query index and match a document whose field f is 'alpha'; you expect the query to match, as it does on a freshly registered Monitor. It does not, with no error: the stored branch documents keep the 10.2.2 writer's hash order of the branches, which follows that JVM's hash seed (in the repro's index, cache ids q_0 = beta, q_1 = alpha), while 10.3.0 and later rebuild the cache in clause order (q_0 = alpha, q_1 = beta), so the presearcher selects branch q_1 and the Monitor runs f:beta on the document.",
   "impact_class": "silent wrong results",
   "introduced_commit": "251dbe7cea8 (LUCENE-8766, 2019-06-13: the monitor module, with the id_ordinal cache ids and HashSet decomposition) [read]; the upgrade gap itself comes from 2527992f266 / 89bd9f0ecd5 (#14885, 2025-08-18), which changed the decomposition order without migrating indexes written before it [read]",
   "introduced_date": "2019-06-13 (module); 2025-08-18 (#14885, order change without a migration of existing indexes)",
   "first_affected_version": "10.3.0 (first reader that rebuilds in clause order) [exec]; the affected indexes are those written by 9.0.0 to 10.2.2 [exec]",
   "affected_versions": "Readers 10.3.0 and 10.6.0 (4ae946e5a9b, the branch_10_6 head) and main e1faeba08bde (-ea and -da, two seeds) [exec]; 10.3.1 to 10.5.2 [read]. Writers 9.0.0, 9.12.3, 10.0.0 and 10.2.2 produce an affected index [exec]; every release with lucene-monitor before 10.3.0 decomposes with a HashSet [read], but indexes created by 8.x cannot be opened by 10.3.0 or later [read]. Indexes written by 10.3.0 and 10.6.0 are not affected [exec]. Re-registering the queries on the new version restores every match [exec].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/14886",
    "https://github.com/apache/lucene/issues/14885",
    "https://github.com/apache/lucene/issues/14967",
    "https://github.com/apache/lucene/issues/15087",
    "https://github.com/apache/lucene/issues/16713"
   ],
   "doc": "",
   "repro": "repro/LFV-1115/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-772",
   "priority": "medium",
   "priority_rank": 68,
   "novelty": "new",
   "withheld": false,
   "area": "monitor / query index updates versus matching (WritableQueryIndex.commitWithoutNotify versus search, reached through Monitor.register and Monitor.match)",
   "title": "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",
   "summary": "Query q = apple OR banana is registered in a Monitor; one thread re-registers q as cherry OR apple while another thread matches a document that contains apple. You expect the match to report q, because both versions of q match the document and every serial order of the two calls reports it. Instead the match can return no queries: register has already replaced the cache entry q_0 with the new first clause (cherry) while the searcher still holds the old index documents, so the old document for apple resolves to the cherry clause, which does not match, and the new apple clause is not searchable yet; once register returns, the same match reports q again.",
   "impact_class": "silent wrong results",
   "introduced_commit": "251dbe7cea8126cb7ecadc921ba444c63d06c618 (master, 'LUCENE-8766: Add monitor subproject', by GitHub romseygeek; JIRA LUCENE-8766, migrated as #9811; the review PR apache/lucene-solr#648 was closed as merged because the change was committed directly; first released in 9.0.0), shipped first through the same-day branch_8x backport b8773d13ad8e249a045862249bf476c30a444461 (8.2.0; its QueryIndex.java and QueryCacheEntry.java are identical to master) [read]. Not a regression: the defect is in the module as first committed. The predecessor project Luwak used the same put-before-commit order but keyed cache entries by an MD5 content hash of the query and its metadata plus '_' + position, so a new version never overwrote an entry the old searcher still used; the port switched to id + '_' + position keys when the Monitor began taking Query objects directly [read]",
   "introduced_date": "2019-06-13 (both commits)",
   "first_affected_version": "8.2.0 [exec] (first release with the monitor module; 9.0.0 is the first 9.x release); there is no unaffected earlier release: 8.1.1 has no monitor module (no lucene-monitor-8.1.1 artifact on Maven Central [exec])",
   "affected_versions": "Every release that ships lucene-monitor from 8.2.0 to 10.5.2 (the last release before 10.6.0, which was not checked), and main a9779ef3c193. [exec] the follow-up's version-portable main() check (public API; it parks register at IndexWriter 'commit: start' through the query index InfoStream, picks the clause terms with each release's own QueryDecomposer and carries a position-stable control) fails on 8.2.0, 8.11.4, 9.0.0, 9.1.0, 9.2.0, 9.8.0, 9.9.0, 9.12.3, 10.0.0, 10.2.2, 10.3.0, 10.5.2 and main with -ea (8.2.0, 9.12.3, 10.5.2 and main also with -da), always before=true, during=false, after=true, while the controls pass, and it passes on main with the fix sketch shadowed; these include the releases on either side of each later refactor (9.1.0/9.2.0 for #679, 9.8.0/9.9.0 for #12801, 10.2.2/10.3.0 for #14885); the candidate JUnit fails 2 of 2 on 9.1.0, 9.12.3, 10.2.2, 10.3.0, 10.5.2 and main (-ea; main also -da); it cannot run on 8.x (no org.apache.lucene.tests package before 9.1.0), and on 9.1.0-10.2.2 its fixed queries move the matching clause only for some hash seeds (they do with the fixed seed DEADBEEF); the independent reproduction's own JUnit fails on main (-ea, -da), 10.5.2 and 9.12.3; the intended-behaviour check's re-run fails on 10.5.2. [read] all 48 release tags with the module in the history clone show the same three facts (put before addDocument, commit and refresh; search pairs the searcher with the live map; position-based cache ids); 8.8.2-8.11.3 are not in the history clone and are inferred between 8.8.1 (same code) and the executed 8.11.4. Not fixed upstream: the last monitor commit on upstream main is df6f71a3729 (2026-09-25, formatting only), branch_10x and branch_10_5 carry no fix, and no open PR changes commitWithoutNotify or search (2026-10-27) [read]. Not examined: the read-only Monitor (ReadonlyQueryIndex, 9.2.0+), which has no register path. Not executed: x86, and each release's own JDK (all runs used JDK 25.0.3)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-772.html",
   "repro": "repro/LFV-772/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-817",
   "priority": "medium",
   "priority_rank": 69,
   "novelty": "known",
   "withheld": false,
   "area": "search / intra-segment concurrency (index / TermStates lazy per-leaf lookup)",
   "title": "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)",
   "summary": "You search with an IndexSearcher that splits one segment into several partitions (the documented intra-segment concurrency) and count a non-scoring PhraseQuery, expecting the same count as a sequential search (500). Instead, on aarch64 about once per 10^5 to 10^6 searches the count is 437, 438 or 375 with no error: all partitions share one lazily filled TermStates, and TermStates#get stores each freshly cloned TermState into a plain array slot that the other partitions read with plain loads, so a partition can see the object before its fields (docFreq 0, sometimes a zero docStartFP or posStartFP) and gets an empty or garbage postings list for its doc range. Publishing the slot with a release store and reading it with acquire loads removes the failure in every test (0 in 1.2M end-to-end searches, 0 in 122.9M root-cause lookups).",
   "impact_class": "silent wrong results",
   "introduced_commit": "fafd6af004e0c39582043b797555d6eeb9aa7638 (apache/lucene#13542 'Add support for intra-segment search concurrency', author javanna, merged 2024-09-10, closes #9721) made the race reachable: partitions of one segment call Weight#scorerSupplier concurrently on one shared Weight (MIGRATE.md 'Weight#scorer, Weight#bulkScorer and Weight#scorerSupplier contract') and so share one lazy TermStates; it did not touch TermStates.java. The racy code is older: d250a1463d87380420afc90e381623c0dc470695 (LUCENE-8113 / #9161 'Allow terms dictionary lookups to be lazy when scores are not needed', author romseygeek, committed 2018-01-05, first released in 8.0.0; its commit message says LUCENE-8133 by mistake) added the lazy path whose get() stores a cloned TermState into the shared plain TermState[] with a plain store; 026d661e5fd9 (#13359, 2024-07-10) and 8b1bad4fb1b4 (#15627, 2026-04-01, main only) reshaped get() and kept the plain stores and loads [read]",
   "introduced_date": "2024-09-10 (#13542 merged; first released in 10.0.0, tag 2024-10-09). Latent lazy plain store: 2018-01-05 (LUCENE-8113, authored 2018-01-02, first released in 8.0.0)",
   "first_affected_version": "10.0.0 [exec]: the end-to-end partition test fails 1 of 2 iterations (3 wrong counts in 300k, first 'count 437 instead of 500') and the root-cause test 3 of 3 (also 1 of 3 with -ea); the independent reproduction saw 4 wrong of 400k end to end there. 9.12.3 (latest 9.x) is the last release where it is not reachable through IndexSearcher: 8.0.0-9.12.3 have the same plain lazy store (reproduced at class level on 8.0.0, 9.12.0 and 9.12.3), but their IndexSearcher has no intra-segment partitions, so the end-to-end test does not compile there and Lucene's own search path never calls TermStates#get for one leaf from two threads (latent).",
   "affected_versions": "every release 10.0.0 through 10.5.2 [read], main a9779ef3c193 [exec], upstream main 20ced71c1e6e and the upstream branch_10_6 head 4ae946e5a9b9 [read], so the released 10.6.0 has it. Latent, not reachable through IndexSearcher, in 8.0.0-9.12.3 [exec]. All runs JDK 25.0.3 on Linux aarch64; x86 was not tested.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/13542",
    "https://github.com/apache/lucene/issues/13745",
    "https://github.com/apache/lucene/issues/9721",
    "https://github.com/apache/lucene/issues/13359",
    "https://github.com/apache/lucene/issues/15627",
    "https://github.com/apache/lucene/issues/15458"
   ],
   "doc": "",
   "repro": "repro/LFV-817/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-556",
   "priority": "medium",
   "priority_rank": 70,
   "novelty": "known",
   "withheld": false,
   "area": "queries / mlt (MoreLikeThisQuery.rewrite over MoreLikeThis.like(String, Reader...)) x queryparser / xml (LikeThisQueryBuilder)",
   "title": "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)",
   "summary": "You build a MoreLikeThisQuery for the text 'zebra quokka' with moreLikeFields {title, body} (or parse <LikeThisQuery fieldNames=\"title,body\">zebra quokka</LikeThisQuery>) on an index where those words occur only in body, and expect the documents whose body contains them, because the javadoc says moreLikeFields are the 'fields used for similarity measure' and the XML DTD calls fieldNames a 'Comma delimited list of field names'. Instead the query rewrites to terms of fieldName only (title, the first listed field on the XML path), here an empty query, so it matches 0 documents instead of 2; the field list changes nothing about matching or scoring (only equals and hashCode), and on the XML path the result depends on the order of the list ('title,body' 0 hits, 'body,title' 2). Up to 6.0.1 each word went to the listed field with the highest document frequency; LUCENE-6954 (6.1) made MoreLikeThis's Reader path use only the field it is given, and MoreLikeThisQuery, which uses that path, was never adapted.",
   "impact_class": "silent wrong results",
   "introduced_commit": "967f7d3492e17ef849892aed034de20ff6b01754 (branch_6x, first release 6.1.0), the cherry-pick of master commit e8dac9bfdf358fff3b484ed5cd9032c1fe4bae96 (master line, first release 7.0.0): LUCENE-6954 'More Like This Query: keep fields separated' (migrated as apache/lucene#8011; patch by @alessandrobenedetti, committed by @tteofili; JIRA-patch era, no pull request). It changed only MoreLikeThis.java and TestMoreLikeThis.java: createQueue lost the per-word loop over fieldNames that picked 'the largest document frequency' field, so like(String fieldName, Reader...) now builds every term on fieldName; MoreLikeThisQuery.java and LikeThisQueryBuilder.java were not touched and there is no CHANGES entry [exec]",
   "introduced_date": "2016-03-28",
   "first_affected_version": "6.1.0 [exec] (last unaffected release 6.0.1 [exec]; 5.5.x and 6.0.x do not contain the commit; on the master line the first release is 7.0.0)",
   "affected_versions": "every release from 6.1.0 through 10.5.2, and main ea57360912ed. [exec] the candidate JUnit and a version-independent probe fail on 6.1.0, 6.6.6, 7.0.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) and pass on 5.5.5, 6.0.0 and 6.0.1; the independent reproduction's JUnit fails on main (-ea, -da), 10.5.2, 9.12.3, 8.11.4 and 6.1.0 and passes on 6.0.1; re-runs fail on main (-ea, -da) and 10.5.2. [read] every release tag from 6.1.0 on contains the introducing commit, and no later commit restores a field choice from fieldNames; still present on upstream main a95c754ee003 (2026-10-26, GitHub contents API: MoreLikeThisQuery.java:63 and :71 unchanged; last change to the file 6cde41c9fd8c, 2022-10-19, a rewrite-signature change). aarch64 with JDK 25 only (pure query construction)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/8011",
    "https://issues.apache.org/jira/browse/LUCENE-6954",
    "https://github.com/apache/lucene/issues/4399",
    "https://issues.apache.org/jira/browse/LUCENE-3326",
    "https://github.com/apache/lucene/issues/7927",
    "https://issues.apache.org/jira/browse/LUCENE-6869"
   ],
   "doc": "",
   "repro": "repro/LFV-556/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-241",
   "priority": "medium",
   "priority_rank": 71,
   "novelty": "new",
   "withheld": false,
   "area": "replicator / NRT segment replication (CopyJob.transferAndCancel, ReplicaNode.newNRTPoint)",
   "title": "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",
   "summary": "You run Lucene's NRT segment replication with failover: replica A is promoted to primary (a higher primaryGen) while replica B is still copying an NRT point from the old primary and has already finished one of its files, for example _1_1.liv. You expect B, once it has installed the new primary's NRT point, to search exactly the new primary's documents, because the module discards pre-copied data on a primary change and treats two files as the same only if name, header and footer match. Instead CopyJob._transferAndCancel keeps the old primary's finished temp file because the new primary's file has the same name, so B, at the new primary's version, shows [a0, b1] instead of [a0, a1], commits that state, and CheckIndex reports the index clean.",
   "impact_class": "data corruption",
   "introduced_commit": "1ae7291429bad742715344f86cfa5200229b3698 ('current patch' by mikemccand, 2016-01-24, on the LUCENE-5438 feature branch; the commit that added the whole org.apache.lucene.replicator.nrt package, including the carry-over-by-name loop in CopyJob._transferAndCancel and the unconditional job.transferAndCancel(curNRTCopy) in ReplicaNode.newNRTPoint), merged into master by 12b8721a44db (2016-02-11); LUCENE-5438 'add near-real-time replication' (now #6501), no pull request, no CHANGES entry [read]; 9afa560054a (2016-02-08, same branch) later added the primary-change discard of pendingMergeFiles without covering the in-flight job",
   "introduced_date": "2016-01-24 (branch commit); 2016-02-11 (merge into master)",
   "first_affected_version": "6.0.0 [exec] (release tag 2016-04-07; the first release with the org.apache.lucene.replicator.nrt package): it reproduces with a ReplicaNode subclass whose close() override skips the call made from ReplicaNode's own constructor, as the module's SimpleReplicaNode test node does, because a separate 6.0.0-6.1.0 constructor bug (success = true missing) stops a plain subclass from starting; 6.2.0 is the first release that reproduces with no workaround [exec]; 5.5.0 and 5.5.5 have no nrt package (the repro does not compile) [exec]",
   "affected_versions": "every release from 6.0.0 through 10.5.2 and main ea57360912ed. [exec] 6.0.0 (-ea and -da, with the close() override), 6.1.0 (with the override), 6.2.0 (-ea and -da), 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da): both finder tests fail with the identical assertion on every one (replica at the new primary's version shows [a0, b1] instead of [a0, a1], carried-over file _1_1.liv, CheckIndex clean); the independent reproduction's independent test also fails on 10.5.2 and 9.12.3 (-ea and -da) and the intended-behaviour check's no-split-brain variant on 10.5.2 (-da). [read] all 83 release tags from 6.0.0 to 10.5.2 in the history clone contain the merge 12b8721a44db, and _transferAndCancel has had only non-semantic edits since 1ae7291429b. Not fixed on main [read]. Not affected: 5.x (API absent) [exec]. All runs on aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-241.html",
   "repro": "repro/LFV-241/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-145",
   "priority": "medium",
   "priority_rank": 72,
   "novelty": "new",
   "withheld": false,
   "area": "index / index sorting at merge time (IndexSorter.FloatSorter/DoubleSorter merge keys, MultiSorter) -> search / TopFieldCollector index-sort early termination",
   "title": "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",
   "summary": "You configure IndexWriterConfig#setIndexSort with a FLOAT (or DOUBLE) SortField over a FloatDocValuesField (DoubleDocValuesField), index a document whose value is a NaN with the sign bit set, for example the run-time negation of a NaN, and expect every flushed and merged segment to follow the sort, in which Float.compare puts every NaN after +Infinity. Flush gets this right, but a merge orders documents by NumericUtils.sortableFloatBits of the raw stored bits, which ranks that NaN below -Infinity, so the merged segment follows neither order: segments {3, 1, NaN} and {2, 0.5} sorted descending merge to [2.0, 0.5, NaN, 3.0, 1.0]. CheckIndex at level 2 or higher reports the segment as unsorted, and a top-1 search sorted by the index sort returns 2.0 instead of NaN, and 2.0 instead of 3.0 for a query that does not match the NaN document.",
   "impact_class": "data corruption",
   "introduced_commit": "37837133c357 (apache/lucene#13320 'Remove unnecessary bit conversion for IndexSorter', author bugmakerrrrrr, merged by jpountz; branch_9x backport b1470b945f91) replaced NumericUtils.floatToSortableInt(Float.intBitsToFloat(bits)) and doubleToSortableLong(Double.longBitsToDouble(bits)), which canonicalize NaN through floatToIntBits/doubleToLongBits, with sortableFloatBits(bits) and sortableDoubleBits(bits) on the raw stored bits in FloatSorter/DoubleSorter.getComparableProviders [read]; the PR has the empty description template, no reviews or review comments, no test change and no CHANGES entry",
   "introduced_date": "2024-05-14 (#13320 merged on main and branch_9x); first released 2024-06-06 (9.11.0)",
   "first_affected_version": "9.11.0 [exec]; first affected 10.x release 10.0.0 [exec]",
   "affected_versions": "every release from 9.11.0 through 10.5.2 (18 releases: 9.11.0, 9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2), 10.6.0 (by reading) and main ea57360912ed: the finder JUnit fails 4 of 4 on each of the 18 and on main with identical messages [exec], also with -da on 9.11.0, 10.5.2 and main [exec]; unaffected: 9.1.0 through 9.10.0 (14 releases, the JUnit passes 4 of 4 [exec], 9.10.0 also with -da) and 8.0.0, 8.6.0, 8.11.4 and 9.0.0 (a core-only probe passes and prints the correct merged order [exec]); 6.2.0 (first release with IndexWriter index sorting) through 7.7.3 by code reading only: their merge order goes through Float.compare (6.2.0-6.6.6) or the boxed compareTo (7.0.0-8.1.1), both of which treat every NaN alike [read]; upstream branch_10x, branch_10_6, branch_10_5 and branch_9_12 carry the same lines (read-only contents API, 2026-10-26) [read], so 10.6.0 (released 2026-10-29) is affected [not executed]; not fixed upstream [read]; main 645d4fe14a2 [exec]; branch_10x 657014b3c57 and branch_10_6 4ae946e5a9b (10.6.0 RC1) have the same IndexSorter.java blob as main [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-145.html",
   "repro": "repro/LFV-145/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-086",
   "priority": "medium",
   "priority_rank": 73,
   "novelty": "known",
   "withheld": false,
   "area": "search / FieldExistsQuery count",
   "title": "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",
   "summary": "You index a text field with norms turned off together with a doc-values field of the same name, some document's text analyzes to no tokens (for example an empty string), and you call IndexSearcher#count(new FieldExistsQuery(field)). You expect the count to equal the number of documents the query returns, because the query matches every document that has a doc value. Instead, on a segment without deletions, Weight#count returns Terms#getDocCount, which counts only documents with at least one term, so the count is 1 for 2 hits, or 0 for 1 hit when no document in the segment has a term.",
   "impact_class": "silent wrong results",
   "introduced_commit": "apache/lucene#445 (LUCENE-10085, 'Implement Weight#count on DocValuesFieldExistsQuery'): branch_9x 631d1ad74940 (the commit released in 9.1.0) and main merge commit 1a869c185b69 [read]; the doc-values branch was carried unchanged into FieldExistsQuery by #767 (LUCENE-10436, 9.2.0)",
   "introduced_date": "2021-11-19",
   "first_affected_version": "9.1.0 (through DocValuesFieldExistsQuery; FieldExistsQuery itself first ships in 9.2.0)",
   "affected_versions": "every release from 9.1.0 to 10.5.2 (32 releases: 9.1.0, 9.2.0-9.12.3, 10.0.0-10.5.2) and main ea57360912ed [exec]; 9.0.0 and 8.11.4 count correctly [exec] (no count() override in 9.0.0; Weight#count does not exist before 9.0.0 [read]); not fixed upstream [read]. Variations [exec]: in 9.1.0 a tokenized field with norms also undercounts; in 9.1.0-9.3.0 a segment where no document has a term throws NullPointerException from count() instead of returning a wrong 0 (changed by #11794 in 9.4.0); doc-values fields with a skip index also undercount before 10.5.0 (executed on 10.0.0, 10.2.2, 10.3.0 and 10.4.0) and count correctly from 10.5.0 on, a side effect of #16111",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16111",
    "https://github.com/apache/lucene/issues/477",
    "https://github.com/apache/lucene/issues/11299",
    "https://issues.apache.org/jira/browse/LUCENE-10263",
    "https://github.com/apache/lucene/issues/445",
    "https://github.com/apache/lucene/issues/11123"
   ],
   "doc": "",
   "repro": "repro/LFV-086/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-008",
   "priority": "medium",
   "priority_rank": 74,
   "novelty": "new",
   "withheld": false,
   "area": "index / soft deletes",
   "title": "Removing a document's soft-delete value brings a hard-deleted document back",
   "summary": "With a soft-deletes field configured, you hard-delete a document and then clear its soft-delete value. You expect the document to stay deleted. Instead PendingSoftDeletes.applySoftDeletes sets its live bit again, so it becomes visible; softDelCount can reach -1, which wedges the writer and gives a corrupt commit or merge.",
   "impact_class": "data corruption",
   "introduced_commit": "LUCENE-8298 (#9345, a3c86373e47d)",
   "introduced_date": "2018-05-07",
   "first_affected_version": "7.4.0",
   "affected_versions": "7.4.0, 8.11.4, 9.12.3, 10.5.2, main [exec]; 7.3.1 has no soft deletes",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-008.html",
   "repro": "repro/LFV-008/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-593",
   "priority": "medium",
   "priority_rank": 75,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter construction from a near-real-time reader (ReaderPool pre-enrollment, PendingSoftDeletes reader constructor, soft-deletes accounting)",
   "title": "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)",
   "summary": "You configure a soft-deletes field, soft-delete one document (for example with an ordinary softUpdateDocument), open a near-real-time reader, close the writer, and open a new IndexWriter from that reader with setIndexCommit(nrtReader.getIndexCommit()), as the setIndexCommit javadoc documents. You expect the new writer to start from the reader's point in time and commit every document, with the soft delete still soft. Instead it counts each deletion the reader sees again (a committed soft delete three times, an uncommitted hard delete twice), so its next commit drops a 3-document segment that has 2 live documents, writes a 2-document commit that DirectoryReader.open rejects with 'invalid deletion count: 3 vs maxDoc=2', or hard-deletes the soft-deleted document, and a later forceMerge can silently attach one document's terms to another document's stored fields.",
   "impact_class": "data corruption",
   "introduced_commit": "ecc17f9023309ca2c46eaf65fd031e4af0ef5a25 (master, 2018-04-04) and its branch_7x backport 02fa5a0b059 (the commit that shipped in 7.4.0): LUCENE-8233 'Add support for soft deletes to IndexWriter' (GitHub #9280, by s1monw; reviewed as JIRA patches and a pull request in the author's fork, no Apache PR). It added IndexWriterConfig#setSoftDeletesField and the PendingSoftDeletes(field, reader, info) constructor, and made the writer-from-reader pre-enrollment (LUCENE-6524, #7582, 5.3.0) call it; that constructor seeds both its soft count and its hard-delete tracker from the reader's soft-applied live docs [exec]. Three later 7.4 development commits made the effects worse before the first release: LUCENE-8253 (#9300, aeac55a6029, 2018-04-16) removed a reset that had hidden the double-counted hard delete; LUCENE-8290 (#9337, 8fdd3d7584b, 2018-05-02, bisected) started dropping segments that look fully deleted; LUCENE-8341 (#9388, 21f03a49532, committed 2018-06-04) recorded softDelCount in SegmentCommitInfo, so a committed soft delete is counted a third time and the -ea assertion fires [exec].",
   "introduced_date": "2018-04-04 (LUCENE-8233; escalated 2018-04-16, 2018-05-02 and 2018-06-04, all before 7.4.0)",
   "first_affected_version": "7.4.0 [exec]; 7.3.1, the last release before, has no soft-deletes API (no setSoftDeletesField, no softUpdateDocument) [exec]",
   "affected_versions": "every release from 7.4.0 through 10.6.0 (10.6.0 by reading) and main a9779ef3c193, never fixed. [exec] The portable history probe ran on all 67 releases from 7.4.0 to 10.5.2 with -da (identical per-case outcomes: segment dropped, commit unreadable, soft delete turned hard, rollback variant dropped; both controls pass) and with -ea on 7.4.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0 and 10.5.2; the candidate JUnit fails 4/4 on main (-ea and -da, 80/80 over 20 seeds with -da) and on 10.5.2 (-da); the independent reproduction's JUnit fails on main, 10.5.2 and 9.12.3 (-ea and -da). The silent document conflation after forceMerge was executed only on main and 10.5.2. The previous hunt main ea57360912ed is affected too (the unit's k=4 enumeration ran on its jars; none of the 7 commits in between touches ReaderPool, PendingDeletes or PendingSoftDeletes). [read] Upstream main a95c754ee003, branch_10x and branch_10_6 keep the 2018 constructor; no open PR changes it.",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-8458",
    "https://github.com/apache/lucene/issues/9504",
    "https://issues.apache.org/jira/browse/LUCENE-8384",
    "https://github.com/apache/lucene/issues/9431",
    "https://issues.apache.org/jira/browse/LUCENE-8233",
    "https://github.com/apache/lucene/issues/9280"
   ],
   "doc": "",
   "repro": "repro/LFV-593/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1062",
   "priority": "medium",
   "priority_rank": 76,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter opened from a reader's IndexCommit (ReaderPool pre-enrollment) with a leaf-sorted reader (DirectoryReader leaf sorter, IndexWriterConfig#setLeafSorter)",
   "title": "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",
   "summary": "You commit two one-document segments (_0 holds id=a, _1 holds id=b), open DirectoryReader.open(dir, newestFirst) so that its leaves are [_1, _0], open an IndexWriter with setIndexCommit(reader.getIndexCommit()), call deleteDocuments(new Term(\"id\", \"a\")) and commit. You expect the index to keep only b, as it does when the reader has no sorter or when the same commit is taken from DirectoryReader.listCommits. Instead the writer deletes b and keeps a: ReaderPool pairs segmentInfos.info(i) (segment order) with reader.leaves().get(i) (sorted order) by position, so each segment's pooled reader carries the other segment's documents, the delete matches a's data but is recorded under _1, and the commit writes _1's live docs, with CheckIndex clean.",
   "impact_class": "data corruption",
   "introduced_commit": "48715fe898bf (apache/lucene main, LUCENE-9507 'Custom order for leaves in IndexReader and IndexWriter', issue #10546, PR #32, author Mayya Sharipova, author date 2021-03-26), first released through its branch_8x backport 1cfd0df4e7bb (apache/lucene-solr#2473, author date 2021-03-30, in 8.9.0): it made a reader's leaves sortable (BaseCompositeReader Arrays.sort(subReaders, subReadersSorter)) and changed neither ReaderPool.java nor IndexWriter.java [read]. Latent precondition, not the introducing commit: the positional pre-enroll loop of 2d0ac9bb7f22 (LUCENE-6524 / #7582, author date 2015-06-28, first released in 5.3.0), moved unchanged into ReaderPool by 89756929537 (LUCENE-8260, 2018-04-23), which was correct while a reader's leaves always followed segment order",
   "introduced_date": "2021-03-26 (author date of 48715fe898b on main; the branch_8x backport 1cfd0df4e7bb is dated 2021-03-30)",
   "first_affected_version": "8.9.0 [exec]; 8.8.2 and earlier are not affected [exec]",
   "affected_versions": "every release from 8.9.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 645d4fe14a20; never fixed. [exec] 8.9.0 (-ea and -da), 8.11.4, 9.0.0 (8.x and 9.0.0 through a one-import port), 9.12.3, 10.0.0, 10.5.2 and 10.6.0 (-da) and main (-ea and -da) all fail with the same assertion; the independent reproduction's own JUnit fails on 10.6.0, 10.5.2 and 9.12.3 (-da); the round-18 skeptic's main() probes fail on 8.9.0, 8.10.0 and 9.0.0 (-da). [read] the remaining 8.10.x, 8.11.x, 9.x and 10.x releases are inferred: every 9.x and 10.x release tag contains both the positional loop and the leaf sort (git show per tag), and 8.10.1-8.11.3 lie between executed 8.x releases that fail. Upstream main 716d6f216f5, branch_11x and branch_10_6 still pair by position (the last ReaderPool.java commit is 9092bda09d6, #16570, author date 2026-09-01; re-checked 2026-10-30). Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1062.html",
   "repro": "repro/LFV-1062/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-006",
   "priority": "medium",
   "priority_rank": 77,
   "novelty": "new",
   "withheld": false,
   "area": "util / BKD points",
   "title": "PointInSetQuery silently misses most matches on selectively indexed points (fewer index dimensions than data dimensions)",
   "summary": "You index a point field with more data dimensions than index dimensions (FieldType.setDimensions(d, 1, bytes), selective indexing) and run a PointInSetQuery (newSetQuery) on it. You expect every document whose indexed value is in the set to match. Instead BKDWriter sorts leaves by a data dimension and the query's forward-only visitor skips matches: 189,088 of 207,884 expected hits (91%) were missed in the repro, and a 3-dim/2-index-dim field returned 0 hits instead of 2.",
   "impact_class": "silent wrong results",
   "introduced_commit": "LUCENE-8496: master 1118299c338 and 4cfa876d9d2 (first released in 8.0.0); branch_7x re-applied backport 804afbfd47c, which shipped in 7.6.0",
   "introduced_date": "2018-10-08 (1118299c338); 2018-10-10 (4cfa876d9d2); 2018-10-18 (804afbfd47c committed on branch_7x)",
   "first_affected_version": "7.6.0",
   "affected_versions": "all 65 lucene-core releases 7.6.0-10.5.2 [exec], branch_10_6 and main [exec]; 7.7.0-8.0.0 only the flush case (merge-built leaves sorted correctly there)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-006.html",
   "repro": "repro/LFV-006/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-475",
   "priority": "medium",
   "priority_rank": 78,
   "novelty": "new",
   "withheld": false,
   "area": "search / points queries (PointInSetQuery segment early exit)",
   "title": "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",
   "summary": "You subclass PointInSetQuery for a 2-D point field, as Lucene's own tests do, and search for the set {(0,1), (1,0)} in an index whose segment holds one document at (1,0). You expect that document to match, as it does for the one-point set {(1,0)}. Instead, since 10.3.0 the query keeps the first and last set points in sorted order, (0,1) and (1,0), as if they were the set's per-dimension minimum and maximum, concludes from dimension 1 (1 is above the segment's maximum 0) that the segment cannot match, and skips it, so count() is 0 with no error; adding a point to a set can thus remove hits.",
   "impact_class": "silent wrong results",
   "introduced_commit": "dba6c2c2fd98dce4a1348109ecad09cd3ba44e5f (main) and its branch_10x backport 0b1e2225f69a3ecc106259112d37d48980a1f74b (parent 7f4b775d7e4a), GITHUB#14268 'PointInSetQuery early exit on non-matching segments' (author hanbj, merged by gsmiller; CHANGES 10.3.0, Optimizations) [read] [exec]. The multi-dimensional protected constructor itself exists since 6.0.0 (013abeaa5b7, 2016); only the early exit is new",
   "introduced_date": "2025-04-01 (author date 2025-04-01T22:51:34+08:00, merged 2025-04-01T14:51:35Z; PR opened 2025-02-21)",
   "first_affected_version": "10.3.0 [exec]; 10.2.2 and earlier are not affected [exec]",
   "affected_versions": "10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main ea57360912ed [exec]; branch_10_6 (2763db11b0a, contained in the 10.6.0 tag commit 4ae946e5a9b, released 2026-10-29) and the unreleased branch_10x (1309534296e) carry the same constructor and early-exit lines [read], so 10.6.0 has them. Not fixed upstream: main f4cc6ac2097c, branch_10x 657014b3c579, branch_10_6 940768fb0cda and branch_10_5 still compare the first and last sorted points in every dimension [read]. Not affected [exec]: 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2; older releases by construction (no early exit). Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-475.html",
   "repro": "repro/LFV-475/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-144",
   "priority": "medium",
   "priority_rank": 79,
   "novelty": "new",
   "withheld": false,
   "area": "search / sorting (NumericComparator doc-values-skipper pruning for FLOAT/DOUBLE)",
   "title": "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",
   "summary": "You store float or double values as raw IEEE bits in a single-valued NUMERIC doc-values field with a skip index and no points (for example NumericDocValuesField.indexedField(\"f\", Float.floatToRawIntBits(v)), the layout of Lucene's own skip-index sort test) and sort on it with SortField.Type.FLOAT or DOUBLE. You expect the same hits as on the same values without a skip index, lowest value first. Instead, with 10,000 docs holding 0, -1, ..., -9999 and a TermQuery that matches all of them, the ascending top 3 is [-8191, -8190, -8189] instead of [-9999, -9998, -9997] and a descending searchAfter(-9000) returns no hits, because the pruning compares bounds in NumericUtils sortable order with skipper block min/max in raw-bit order, and the two orders disagree for values with the sign bit set.",
   "impact_class": "silent wrong results",
   "introduced_commit": "9a7bcc9b590 on main / e2fdc61ad32 on branch_10x (apache/lucene#14672 'Dynamic pruning with DocValueSkipper', by gf2121, closes #14666) [read]; later refactors kept the mismatch: #15397/#15410, #15632 (block-only SkipBlockRangeIterator), #15663, #15757",
   "introduced_date": "2025-06-06 (9a7bcc9b590 on main and e2fdc61ad32 on branch_10x)",
   "first_affected_version": "10.3.0 [exec]",
   "affected_versions": "10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main through e1faeba08bd [exec]; not affected: 10.0.0, 10.1.0, 10.2.0, 10.2.1 and 10.2.2 [exec]; not applicable: 9.x [exec]; 10.6.0 (released 2026-10-29) [exec]; affected by reading: branch_10_6 and branch_11x (11.0, unreleased; its comparator, SortField and collector files are identical to main) [read]; branch_10x was decommissioned on 2026-10-29 (#16911); the exact wrong hits differ by version (10.3.x scans only the first 4096-doc skipper block before the bad pruning, 10.4.0 and later the first 8192 docs) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-144.html",
   "repro": "repro/LFV-144/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1047",
   "priority": "medium",
   "priority_rank": 80,
   "novelty": "new",
   "withheld": false,
   "area": "search / doc-values range queries, index-sort shortcut (SortedNumericDocValuesRangeQuery.canUsePrimarySortShortcut, SortedSkipperScorerSupplier)",
   "title": "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",
   "summary": "You index the floats -1f and -2f as raw bits in a skip-indexed doc-values field (FloatDocValuesField.indexedField(\"f\", Float.floatToRawIntBits(v))), sort the index by that field with new SortField(\"f\", SortField.Type.FLOAT), and count the documents matching NumericDocValuesField.newSlowExactQuery(\"f\", Float.floatToRawIntBits(-1f)). You expect 1, which is what you get without the index sort or without the skip index. You get 0: the query's index-sort shortcut computes one contiguous doc-ID range as if the documents were in the order of their stored longs, but the FLOAT sort puts -2f (raw -1073741824) before -1f (raw -1082130432), the reverse of the long order, and the shortcut never checks the sort type.",
   "impact_class": "silent wrong results",
   "introduced_commit": "579427228d4297837c8c1794ddde98af0c9815fd (apache/lucene#13592 'Take advantage of the doc value skipper when it is primary sort', iverase; reviewed by gsmiller and jpountz) [exec]. The guard stayed name-only through #15083 (2ea7c9ed1fc), #16085 (195575956df, moved the range computation into SortedSkipperScorerSupplier), #16424 (693a7234bad, canUsePrimarySortShortcut via Sort.getPrimarySortField) and #16893 (ffa9d816eeb, adds hasBlocks() only)",
   "introduced_date": "2024-08-22 (#13592 merged into main as 579427228d4; PR opened 2024-07-19)",
   "first_affected_version": "10.0.0 [exec]",
   "affected_versions": "[exec] main 645d4fe14a20 (-ea and -da: finder 10/10 seeds, the independent reproduction, the cross-model review check, the intended-behaviour check, judge and the re-run) and every release from 10.0.0 to 10.6.0: 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2 and 10.6.0 (SHA-1-verified Maven Central jars; 10.6.0 = commit 4ae946e5a9b; -ea and -da on 10.0.0, 10.5.2 and 10.6.0). Released in 10.6.0: the tag releases/lucene/10.6.0 exists (tag object e29d290eeb05, peels to 4ae946e5a9b; git ls-remote 2026-10-29). [read] upstream main 716d6f216f5 (same file blob as 645d4fe14a20) and branch_10_6 7e5aec4370e (same blob as the 10.6.0 tag). Not applicable: 9.12.3 and older (no doc-values skip index; the repro does not compile). Not new in 10.6, except one same-fix layout: a FLOAT sort as the second sort field after a first one that is constant in the segment reaches the shortcut only since #16424 (finder's legs test on 645d4fe: 10.5.2 passes that layout, main fails it)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1047.html",
   "repro": "repro/LFV-1047/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1049",
   "priority": "medium",
   "priority_rank": 81,
   "novelty": "new",
   "withheld": false,
   "area": "search / IndexSortSortedNumericDocValuesRangeQuery (index-sort range shortcut: INT sort comparator path and 4-byte points path)",
   "title": "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",
   "summary": "You sort the index by SortField(\"f\", SortField.Type.INT), index the values -5, 3 and 20 in a NumericDocValuesField, and search new IndexSortSortedNumericDocValuesRangeQuery(\"f\", Long.MIN_VALUE, 10, fallback), where the fallback is NumericDocValuesField.newSlowRangeQuery(\"f\", Long.MIN_VALUE, 10) (f <= 10, written with the open-end convention that the fallback documents). You expect the 2 documents the fallback returns, as the class javadoc requires. You get 1: the doc-values binary search narrows the bound with (int) Long.MIN_VALUE, which is 0, so -5 is missed; (int) Long.MAX_VALUE is -1 in the same way, and the 4-byte points path has the same cast.",
   "impact_class": "silent wrong results",
   "introduced_commit": "737ce42c1c0a8697009b97d72386f2c165d07add on main (branch_9x 03dd543572c), LUCENE-10466 (#11502, PR #749 by reta): replaced a ClassCastException on INT sorts with the unguarded fieldComparator.setTopValue((int) topValue) in the then-sandbox class [read]. The points-path cast IntPoint.pack((int) lowerValue / (int) upperValue) came with 5b24a233bdf (branch_9x f31292c1441), LUCENE-10425 (PR #687) [read]; git blame shows 8671e29929c (#12003), which only moved the lines. #12078 (102622842bf, branch_9x f70530e5840) moved the class into core",
   "introduced_date": "2022-04-04 (author date of 737ce42c1c0; points-path cast 2022-09-22; move to core 2023-01-13)",
   "first_affected_version": "9.5.0 [exec] (first core release, after #12078 moved the class out of sandbox); the same code was in the sandbox module from 9.2.0 [exec]",
   "affected_versions": "[exec] main 645d4fe14a20 (-ea and -da: finder, the independent reproduction, the cross-model review check, the intended-behaviour check, judge and the re-run), 10.6.0 (Maven Central core jar, commit 4ae946e5a9b; the independent reproduction -ea and -da, follow-up -da), 10.5.2 and 9.12.3 (the independent reproduction -ea and -da, follow-up -da), 9.5.0 (-da); sandbox 9.2.0 and 9.4.2 fail (-da), sandbox 9.1.0 throws ClassCastException instead (the LUCENE-10466 bug), so no release ever handled these bounds correctly. [read] every core release from 9.5.0 to 10.6.0; upstream main (casts at lines 461, 462 and 633 via the contents API, 2026-10-29; last change to the file ffa9d816eeb, author date 2026-10-26, already in 645d4fe), branch_11x (same last commit) and branch_10_6 7e5aec4370e. Released in 10.6.0: tag releases/lucene/10.6.0 exists (tag object e29d290eeb05, peels to 4ae946e5a9b; git ls-remote 2026-10-29). Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1049.html",
   "repro": "repro/LFV-1049/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-751",
   "priority": "medium",
   "priority_rank": 82,
   "novelty": "new",
   "withheld": false,
   "area": "document / point query factories (BinaryPoint, PointRangeQuery)",
   "title": "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",
   "summary": "You write a one-dimensional binary key into a scratch byte[], build BinaryPoint.newExactQuery(field, scratch), write the next key into the same array, build a second query and OR the two; you expect each query to match the key it was built for, as BinaryPoint's two-dimension range queries and its one-value newSetQuery do. Instead both queries now mean the second key (they compare equal and print the same bounds) and the OR finds 1 document instead of 2; likewise a one-dimensional newRangeQuery whose lo/hi arrays the caller overwrites afterwards matches 0 documents instead of the range it was built for. BinaryPoint.pack returns new BytesRef(point[0]), a wrapper over the caller's array, when there is one dimension, and PointRangeQuery stores that array as its bounds, so matching, equals, hashCode and toString read whatever the caller's array holds at the time.",
   "impact_class": "silent wrong results",
   "introduced_commit": "e1a1dbfabcc9 (LUCENE-7117/LUCENE-7118 'Remove multidimensional arrays from PointRangeQuery', Robert Muir (rmuir), migrated as apache/lucene#8172 and #8173; JIRA era, no pull request; committed the same day on branch_6_0 as d8c4e6977b0e, the copy in 6.0.0, and on branch_6x as 51b109620be7) [read]: it made BinaryPoint.newRangeQuery(String, byte[][], byte[][]) pass pack(lowerValue).bytes and pack(upperValue).bytes to PointRangeQuery, so two or more dimensions get a private packed array while one dimension keeps the caller's array through pack()'s shortcut 'if (point.length == 1) return new BytesRef(point[0])', which LUCENE-6881 (f12cb52a3b8, 2015-11-08) had written for the field constructor (Field documents its byte[] values as not copied). In the unreleased code between LUCENE-7045 (099e0311398, 2016-02-23) and this commit the query kept the caller's byte[][] for every dimension count, so no released version ever copied the one-dimension bounds. The lines are unchanged on main apart from the 2020 reformat (2d6ad2fee6d, LUCENE-9570)",
   "introduced_date": "2016-03-20",
   "first_affected_version": "6.0.0 [exec]; 5.5.5 and older are not affected because BinaryPoint does not exist there (the repro does not compile) [exec]",
   "affected_versions": "Every release that has BinaryPoint, 6.0.0 through 10.5.2, and main a9779ef3c193; never fixed (unchanged on upstream main f7bcc0abd816, branch_10x and branch_10_5; no open PR touches BinaryPoint.java; read 2026-10-27). [exec] the finder's JUnit (or its pre-9.1 adaptation, which differs only in the test-framework packages and the IndexWriterConfig constructor) fails 2 of 2 with the same two messages on 6.0.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.5.2 and main (-ea and -da), and its two-dimension control passes in every one of them; the independent reproduction's JUnit fails 3 of 6 (the three bug legs; three controls pass) on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's probe fails 3 of 4 on main (-ea and -da) and 10.5.2. [read] the releases in between carry the same code. 10.6.x and later branches were not run. All runs with JDK 25.0.3 on aarch64; the behaviour is plain Java array sharing, independent of codec and platform",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-751.html",
   "repro": "repro/LFV-751/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-115",
   "priority": "medium",
   "priority_rank": 83,
   "novelty": "known",
   "withheld": false,
   "area": "search / IndexSearcher timeout reporting for vector queries (AbstractKnnVectorQuery rewrite, AbstractVectorSimilarityQuery scorerSupplier)",
   "title": "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",
   "summary": "You set a timeout with IndexSearcher#setTimeout and run a kNN query (KnnFloatVectorQuery or KnnByteVectorQuery) or an approximate FloatVectorSimilarityQuery/ByteVectorSimilarityQuery, and the timeout fires before the vector search has found its first hit. You expect what a TermQuery gives under the same timeout: 0 hits with IndexSearcher#timedOut() == true, the documented signal ('Returns true if any search hit the timeout') that the answer is incomplete. Instead the search returns 0 hits, TotalHits '0 hits' (EQUAL_TO) and timedOut() == false, so the timed-out search cannot be told apart from a search that has no matches; IndexSearcher#count of a kNN query behaves the same way.",
   "impact_class": "silent wrong results",
   "introduced_commit": "df154cdc2288 on main (branch_9x backport 3508be5b3ef3), PR #13202 'Add timeout support to AbstractKnnVectorQuery' (kaivalnp, merged by vigyasharma), for the kNN part: rewrite started to consume the searcher's timeout through TimeLimitingKnnCollectorManager(..., indexSearcher.getTimeout()) and kept the older empty-result shortcut to MatchNoDocsQuery (present since 9.0.0); e0e5d81df802 on main (#13285 'Add timeout support to AbstractVectorSimilarityQuery', kaivalnp, merged by vigyasharma; its code was never backported to 9.x) for the similarity part: createWeight reads the timeout and scorerSupplier returns null for an empty partial result [read]; the precondition in IndexSearcher.searchLeaf (partialResult is set only when a TimeLimitingBulkScorer throws, and none is built for a null ScorerSupplier) dates from LUCENE-10151 (#927/#996, 9.3.0) and did not change between 9.10.0 and 9.11.0; for kNN this is a behaviour regression: on 9.10.0 the same search reported timedOut() == true, because kNN ignored the timeout and the search loop caught it [exec]",
   "introduced_date": "2024-04-03 (#13202 merged on main; branch_9x backport committed 2024-04-17); 2024-08-06 (#13285 merged on main)",
   "first_affected_version": "9.11.0 [exec] for the kNN queries (9.10.0 not affected [exec]); 10.0.0 [exec] for the similarity queries (9.11.x and 9.12.x not affected [exec]: the #13285 code was never backported, although CHANGES.txt lists #13285 under 9.12.0 [read])",
   "affected_versions": "kNN (KnnFloatVectorQuery, KnnByteVectorQuery; by code also the join module's DiversifyingChildren*KnnVectorQuery, not executed): 9.11.0, 9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2 and main ea57360912ed; executed failing: 9.11.0, 9.11.1, 9.12.3, 10.0.0, 10.2.2, 10.3.2, 10.4.0, 10.5.2 and main (-ea; also -da on 9.12.3, 10.5.2 and main); the other releases contain df154cdc2288 by tag and lie between executed failing releases [read]. Similarity (FloatVectorSimilarityQuery, ByteVectorSimilarityQuery, approximate path): 10.0.0-10.5.2 and main [exec]. IndexSearcher#count of a kNN query: main, 10.5.2, 10.0.0, 9.12.3 and 9.11.x [exec]. Not affected: 9.10.0 [exec] and 9.3.0-9.9.2 [read]; the similarity part on 9.11.0, 9.11.1 and 9.12.3 [exec]. Not fixed upstream at main ea57360912ed [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/13202",
    "https://github.com/apache/lucene/issues/13285",
    "https://github.com/apache/lucene/issues/11677",
    "https://github.com/apache/lucene/issues/12275",
    "https://github.com/apache/lucene/issues/927",
    "https://github.com/apache/lucene/issues/11188"
   ],
   "doc": "",
   "repro": "repro/LFV-115/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-235",
   "priority": "medium",
   "priority_rank": 84,
   "novelty": "new",
   "withheld": false,
   "area": "index / FilterCodecReader reader lifecycle (IndexReader reference counting)",
   "title": "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",
   "summary": "You wrap a segment of an open DirectoryReader in a FilterCodecReader (for example to pass it to IndexWriter.addIndexes), take the usual extra reference with incRef(), and close the wrapper, expecting the DirectoryReader to keep working, because the IndexReader javadoc says a reader 'will not really be closed until decRef has been called for all outstanding references' and FilterLeafReader behaves exactly that way. Instead FilterCodecReader.doClose() calls the wrapped reader's internal close hook (in.doClose()) rather than releasing a reference (in.close()), so the segment's files are closed while the DirectoryReader still uses it: a TermQuery that matched 1 document now finds 0 with no error, reading stored fields throws AlreadyClosedException, and closing the DirectoryReader later releases the same resources a second time and throws.",
   "impact_class": "silent wrong results",
   "introduced_commit": "ae68e6cebc363e51cd68aee83830b5cb427b4799 (master, 2017-02-08, 'LUCENE-7676: Fixed FilterCodecReader to override more super-class methods', by cpoerschke; JIRA patch era, migrated as apache/lucene#8727, no pull request; on the issue rmuir wrote 'looks good' and jpountz '+1', both about the new test only), backported as 05e0250ee02816c1d0b8387dbaa777747bfeb6f0 (branch_6x, 2017-02-08, first released in 6.5.0) and e0653d96c61421c4b11b753c1afe6aac7e9bb087 (branch_6_4, 2017-02-22, first released in 6.4.2). It added 'doClose() { in.doClose(); }' together with TestFilterCodecReader#testDeclaredMethodsOverridden, a reflective test that requires FilterCodecReader to override every CodecReader method; before it FilterCodecReader inherited CodecReader#doClose, which never touches the delegate [read]",
   "introduced_date": "2017-02-08 (master and branch_6x); 2017-02-22 (branch_6_4 backport)",
   "first_affected_version": "6.4.2 [exec] (6.4.1 and 5.5.5 pass [exec]; FilterCodecReader exists since 5.0.0 (LUCENE-6165) and had no doClose override before 6.4.2 [read]; the first affected release on the main line is 7.0.0 [exec])",
   "affected_versions": "every release from 6.4.2 to 10.5.2 (the last before 10.6.0) and main ea57360912ed [exec]; not affected: 5.0.0 to 6.4.1 (no override) [exec] and every release before 5.0.0 (no FilterCodecReader); branch_10x 1309534296e3 and branch_10_6 2763db11b0a7 still contain the call [read], so 10.6.0 (released 2026-10-29) is very likely affected (not executed); not fixed in any release or on main",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-235.html",
   "repro": "repro/LFV-235/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-490",
   "priority": "medium",
   "priority_rank": 85,
   "novelty": "known",
   "withheld": false,
   "area": "search / FieldExistsQuery and index / FieldInfos field-schema consistency on Lucene-8-created indexes (SegmentInfos per-segment open gate, #14607)",
   "title": "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",
   "summary": "You have an index first created by Lucene 8 that Lucene 9 later rewrote completely (every live segment is 9.x), in which a field is indexed in every document but has a doc value in only some (Lucene 9 allowed that only for such 8.x-created indexes), and you open it with Lucene 10.4.0 or later, which accepts it since #14607. You expect FieldExistsQuery on that field to return only the documents with the doc value, as Lucene 9.12.3 does and Lucene 9's own TestFieldExistsQuery#testOldIndices asserts, and IndexWriter to open whatever DirectoryReader.open accepts. Instead, once the documents share a segment FieldExistsQuery silently rewrites to MatchAllDocsQuery and also returns the document without the doc value (hits [d1, d2] instead of [d1], count 2 instead of 1), while they sit in separate segments it throws IllegalStateException, and IndexWriter and FieldInfos.getMergedFieldInfos throw IllegalArgumentException 'cannot change field \"my_field\" from doc values type=BINARY to inconsistent doc values type=NONE'.",
   "impact_class": "silent wrong results",
   "introduced_commit": "dd70ed5801e3 on main (#14607 'Revise strategy for opening an index for reading', by rahulgoswami: the re-landing; the first landing 3bf1011a4e2 was reverted the same day by fb36f009b77 and never released) and fe59fdec5c56 on branch_10x (#15431, the backport, first released in 10.4.0), which replaced the created-major refusal in SegmentInfos.readCommit with a per-segment minVersion check [read]. Main became affected only together with #16741 (8476457b875, MIN_SUPPORTED_MAJOR lowered from 10 to 9). The misbehaving code is older and was unreachable on 10.0-10.3: LUCENE-9334 d03662c48bf (strict FieldNumbers / verifySameSchema, 9.0.0), LUCENE-10436 91e29405d8e on main / a42326b9ef9 on 9x (FieldExistsQuery rewrite and count proxies that rely on LUCENE-9334); the 9.x leniency for these indexes, LUCENE-10518 67e6e864bdf (PR #842), went to branch_9x only",
   "introduced_date": "2025-11-17 (#14607 on main); 2025-11-25 (#15431 on branch_10x; first released in 10.4.0, tagged 2026-02-25); main reachable since #16741 (merged 2026-10-15)",
   "first_affected_version": "10.4.0 [exec]",
   "affected_versions": "10.4.0, 10.5.0, 10.5.1, 10.5.2 and main ea57360912ed [exec]; branch_10_6 head 940768fb0cda has the same SegmentInfos check and no LUCENE-10518 gates [read]; not affected: 10.0.0, 10.2.2, 10.3.2 (index refused at open) [exec]; 9.12.3, the writing release, returns the right hits, does not throw and lets IndexWriter open the index, but its merged-segment count is also 2 (a pre-existing 9.x gap since 9.2.0: LUCENE-10518 did not guard count()'s terms/points proxy) [exec]; FieldExistsQuery does not exist before 9.2.0 (9.1.0 compile error) [exec]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/14607",
    "https://github.com/apache/lucene/issues/16741",
    "https://issues.apache.org/jira/browse/LUCENE-10518",
    "https://github.com/apache/lucene/issues/11554",
    "https://github.com/apache/lucene/issues/842",
    "https://github.com/apache/lucene/issues/852"
   ],
   "doc": "",
   "repro": "repro/LFV-490/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1109",
   "priority": "medium",
   "priority_rank": 86,
   "novelty": "new",
   "withheld": false,
   "area": "core / search: PointRangeQuery.rewrite (GITHUB#14609 full-coverage rewrite to FieldExistsQuery, new in 10.3.0) on composite readers",
   "title": "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",
   "summary": "You open a MultiReader over two separately built indexes, one whose document has field p only as a doc value (5000, no point) and one whose document has LongField p=100, and count LongPoint.newRangeQuery(\"p\", 0, 1000); you expect 1, which is what each index gives on its own (0 + 1) and what 10.2.2 returns. You get 2 with no error: since 10.3.0 (#14609) PointRangeQuery.rewrite sees that the reader-wide point range [100, 100] lies inside the query and, because every leaf has doc values, norms or vectors for p, replaces the query with FieldExistsQuery(p), which also matches the document that has no point. Under a MUST_NOT clause the same rewrite drops that document instead.",
   "impact_class": "silent wrong results",
   "introduced_commit": "b6851e1b37cbed68da83247110efa2da41d3b570 (branch_10x backport, the copy that shipped first, in 10.3.0) and its main-line merge commit 416dd2fe7c37ef76b2085ea25b0f54e5a6f32367 (same author date, identical PointRangeQuery.java diff), apache/lucene#14609 'Overrides rewrite in PointRangeQuery to optimize AllDocs/NoDocs cases' (author ebradshaw, reviewed and approved by jpountz and jainankitk, milestone 10.3.0, no linked issue). Before it, PointRangeQuery inherited Query.rewrite() and matched every leaf through its own points. [exec]",
   "introduced_date": "2025-05-09 (author date 2025-05-09 23:48:53 -0400 = 2025-05-10T03:48:53Z; merged on main 2025-05-10T03:48:54Z; branch_10x backport committed 2025-05-10T03:55:58Z)",
   "first_affected_version": "10.3.0 [exec]; a regression, not a day-one bug",
   "affected_versions": "10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and 10.6.0 (released 2026-10-29, 4ae946e5a9b), and main e1faeba08bde (12.0.0-SNAPSHOT). Executed, all failing 'expected:<1> but was:<2>': main -ea and -da, 10.6.0 -ea and -da, 10.5.2 -da (and -ea in the independent reproduction), 10.4.0 -da, 10.3.2 -da, 10.3.0 -ea and -da [exec]; 10.3.1, 10.5.0 and 10.5.1 by code identity of the rewrite()..relate() block [read]; upstream main head 3078a1ce833 (2026-11-02), branch_11x and branch_10_6 heads have the same condition [read]. Not affected: every 9.x release and 10.0.0-10.2.2, where PointRangeQuery does not override rewrite() (checked at all 26 tags); the repro passes unchanged on 9.12.3, 10.0.0, 10.2.0 and 10.2.2 [exec]. Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1109.html",
   "repro": "repro/LFV-1109/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-278",
   "priority": "medium",
   "priority_rank": 87,
   "novelty": "new",
   "withheld": false,
   "area": "index / addIndexes reorder path: SlowCompositeCodecReaderWrapper merged vector values (MergedDocIterator) over SortingCodecReader inputs",
   "title": "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",
   "summary": "You re-sort two or more segments with SortingCodecReader and pass them to one IndexWriter.addIndexes(CodecReader...) call on a writer that has no index sort but uses a merge policy that reorders addIndexes merges, such as BPReorderingMergePolicy (an identity OneMerge#reorder is enough), and you expect every document to keep the vector it was indexed with, as it does without the reorder. Instead the merged view that IndexWriter builds for the reorder (SlowCompositeCodecReaderWrapper) numbers vectors by iteration position, while each SortingCodecReader input reports and reads vectors by its original ordinal, so in each input the k-th document in sorted order is written with the vector at original ordinal k. Nothing throws, with or without assertions, CheckIndex reports the new index clean, and kNN search then scores documents by other documents' vectors, in an executed probe including the vector of a document deleted before the call.",
   "impact_class": "data corruption",
   "introduced_commit": "6053e1e31378378f6d310a05ea6d7dcdfc45f48b (apache/lucene#13779 'First-class random access API for KnnVectorValues', msokolov, for issue #13778) [exec]. The one commit added both halves: positional ordinal counting in the merged view and non-positional ordinals in SortingCodecReader; before it the merged view returned the current input's vector at the current document and SortingCodecReader copied vectors into new-document order. The addIndexes reorder path that reaches the code is older: f7cab164501 (#12622, jpountz, 2023-11-23, first released in 9.9.0)",
   "introduced_date": "2024-09-28",
   "first_affected_version": "10.0.0 [exec] (tagged 2024-10-14; branch_10_0 was cut from main after the commit, merge-base 22ac47c07ad, so 10.0.0 has the commit itself, not a backport)",
   "affected_versions": "all 12 10.x releases before 10.6.0 (10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2) and main ea57360912ed [exec]; not affected: the ten releases 9.9.0 to 9.12.3 and the parent commit 7b4b0238d70 [exec]; not applicable: 9.8.0 and older, which have no reorder hook, BPReorderingMergePolicy or SlowCompositeCodecReaderWrapper [exec]; float16 vectors exist only on main (#16383) and mismatched there in the finder's differential sweep [exec]; not fixed on main; release branches after 10.5.2 were not executed; 10.6.0 (released 2026-10-29) is affected by reading (the branch_10_6 head read on 2026-10-26 and the 10.6.0 revision 4ae946e5a9b keep ++ord and the ordStart - 1 reset)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-278.html",
   "repro": "repro/LFV-278/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-420",
   "priority": "medium",
   "priority_rank": 88,
   "novelty": "known",
   "withheld": false,
   "area": "codecs / quantized vector formats merge (Lucene104 scalar-quantized, Lucene102 binary-quantized) with index / addIndexes through SlowCodecReaderWrapper and memory / MemoryIndex",
   "title": "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",
   "summary": "You index a FLOAT32 field with Lucene104ScalarQuantizedVectorsFormat and EUCLIDEAN, DOT_PRODUCT or MAXIMUM_INNER_PRODUCT by calling IndexWriter.addIndexes(SlowCodecReaderWrapper.wrap(...)) on a MemoryIndex, or on a FilterLeafReader that serves new vectors from your own list through FloatVectorValues.fromFloats, and you expect the merge only to read its source, as it does for COSINE fields and for the older Lucene99 scalar-quantized formats. Instead the quantizer subtracts the merged centroid from the source's own arrays: afterwards the MemoryIndex vector {1,2,3,4} reads back as {0,0,0,0} when it is the only vector, and as {1.5,0.75,-2,1.5} when merged together with a second source holding {-2,0.5,7,1}, a second addIndexes of it stores that centered vector as the full-precision vector, and your list holds centered vectors. When two documents share one float[] in a single addIndexes, the second is quantized from the already-centered array, so it scores 0.160 against 0.066 for its identical copies (exact 0.066) and ranks first.",
   "impact_class": "data corruption",
   "introduced_commit": "8856a5f4eb7ec5b53c657f6c9c499fea52b9ee55 (#14078 'Binary vector format for flat and hnsw vectors', by GitHub benwtrent, merged 2025-03-04; branch_10x backport 39e7f0973ec1f217f219506bc78c36cf422cf7c4) added OptimizedScalarQuantizer, whose 'vector[i] = vector[i] - centroid[i]' lines still blame to it on main, and the Lucene102 binary-quantized writer, whose merge passes vectorValue(...) straight to scalarQuantize and multiScalarQuantize and copies only for COSINE [read]. Carried into 594eeb7e637 (#15169, Lucene104 formats, 2025-09-17, first released 10.4.0: QuantizedFloatVectorValues.quantize), 602bfbd9af0 (#15271, asymmetric encodings, 2025-10-02, in 10.4.0; that writer site was removed by #15732, 733141ec45e, 2026-04-28) and c80c9f53674 (#16696, 2026-09-23: writeVectorAndQueryData, the second site on main; backported to branch_10_6 as adfd05f831b, #16750)",
   "introduced_date": "2025-03-04 (8856a5f4eb7, #14078); carried into the Lucene104 formats on 2025-09-17 (#15169) and the second main site on 2026-09-23 (#16696)",
   "first_affected_version": "10.2.0 [exec]; 10.1.0 is not affected [exec]",
   "affected_versions": "[exec] main ea57360912ed (-ea, -da, Panama and default vector providers), 10.5.2 (-ea, -da), 10.5.1, 10.5.0 and 10.4.0 (-ea, -da) with the Lucene104 scalar-quantized flat and HNSW formats; 10.3.2, 10.3.1, 10.3.0, 10.2.2, 10.2.1 and 10.2.0 (-ea, -da on 10.2.0) with the Lucene102 binary-quantized flat format, the HNSW variant executed on 10.2.0, 10.2.2 and 10.3.2. Not affected [exec]: the Lucene99 scalar-quantized formats on 9.12.3, 10.1.0, 10.2.0 and 10.3.2, and COSINE fields; all 9.x and 10.0.0-10.1.0 lack the affected formats. [read] branch_10_6 (10.6.0, released 2026-10-29; head cb17f8f865c, 2026-10-26) has both merge sites; FLOAT16 fields are not affected (the merge inflates them into its own array). Not fixed upstream: main and branch_10x unchanged at the fix sites on 2026-10-26, and no open PR changes the default serial merge path",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16871",
    "https://github.com/apache/lucene/issues/16506",
    "https://github.com/apache/lucene/issues/16790",
    "https://github.com/apache/lucene/issues/14078",
    "https://github.com/apache/lucene/issues/16696",
    "https://github.com/apache/lucene/issues/16762"
   ],
   "doc": "",
   "repro": "repro/LFV-420/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-491",
   "priority": "medium",
   "priority_rank": 89,
   "novelty": "known",
   "withheld": false,
   "area": "facet / taxonomy (TaxonomyMergeUtils.merge, OrdinalMappingLeafReader)",
   "title": "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)",
   "summary": "You merge an index and its taxonomy into another index/taxonomy pair with TaxonomyMergeUtils.merge ('Merges the given taxonomy and index directories'); the source documents carry IntAssociationFacetField values a/x=5 and a/y=7 and the destination already holds b/1=100 and b/2=200 in the same association field. You expect TaxonomyFacetIntAssociations on the merged index to report a: y=7 x=5 and b: 2=200 1=100. Instead, on main and 10.x it reports nothing for a and b: 2=207 1=105, with no error, because association ordinals live in binary doc values that OrdinalMappingLeafReader copies unchanged (it re-maps only sorted-numeric doc values); on 9.x the merged values are dropped (a: nothing, b: 2=200 1=100).",
   "impact_class": "data corruption",
   "introduced_commit": "a7eee727cfd34b4debdeaf6a51ad2d7fb45125a7 (trunk, SVN r1607582, 'LUCENE-5801: add back OrdinalMappingAtomicReader', by shaie; JIRA LUCENE-5801, mirrored as apache/lucene#6863; no PR, it predates the GitHub workflow) and its branch_4x copy 6564ce68f8ff8bb17e00d5cb31b304d37a6aa5f1 (r1607586), which shipped in 4.10.0 [read] [exec]. Not a regression. The symptom changed twice through LUCENE-10062 (gsmiller) [read]: 5fe8f0e3f18 (PR #443, in 9.0.0) / 0ba310782fb (9.1.0 and later) rebuild facet binary values from sorted-numeric ordinals, which association fields lack, so the values become empty; 6ee69e06fbd (PR #264, main, first released in 10.0.0) removed getBinaryDocValues, so the bytes are copied with the source ordinals",
   "introduced_date": "2014-07-03 (a7eee727cfd and its branch_4x copy 6564ce68f8f, same day; 4.10.0 tag dated 2014-09-02); symptom changes 2021-11-19 (LUCENE-10062 for 9.x, PR #443) and 2021-11-23 (PR #264 on main, first released in 10.0.0, tag dated 2024-10-09)",
   "first_affected_version": "4.10.0 [exec], the first release with the merge utility for the FacetsConfig facet API; silent loss first in 9.0.0 [exec]; silent mis-attribution first in 10.0.0 [exec]. 4.9.1 has association facets but no TaxonomyMergeUtils [exec]. The pre-4.7 facet API was not examined",
   "affected_versions": "Every release from 4.10.0 and main ea57360912ed; no release ever re-mapped built-in association ordinals correctly [read]. 4.10.0 to 8.11.4: association bytes decoded as an ordinal list, ArrayIndexOutOfBoundsException during addIndexes, or a completed merge whose re-encoded values throw at aggregation [exec]. 9.0.0 to 9.12.3: merged association values silently lost [exec]. 10.0.0 to main: values silently credited to other categories [exec]. Not executed: an 8.x-created source index merged with 9.x takes the binary back-compat branch and by reading behaves like 8.x. Not fixed upstream: OrdinalMappingLeafReader.java, TaxonomyMergeUtils.java and FacetsConfig.java are unchanged since before ea57360912ed on upstream main a9779ef3c193, branch_10x and branch_10_6 (2026-10-26) [read]; no open PR touches either merge class [read]. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/264",
    "https://github.com/apache/lucene/issues/443",
    "https://github.com/apache/lucene/issues/6863",
    "https://issues.apache.org/jira/browse/LUCENE-5801",
    "https://github.com/apache/lucene/issues/5372",
    "https://issues.apache.org/jira/browse/LUCENE-4304"
   ],
   "doc": "",
   "repro": "repro/LFV-491/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-722",
   "priority": "medium",
   "priority_rank": 90,
   "novelty": "known",
   "withheld": false,
   "area": "facet / taxonomy (TaxonomyMergeUtils.merge, OrdinalMappingLeafReader; FacetsConfig default DimConfig)",
   "title": "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",
   "summary": "You subclass FacetsConfig so that getDefaultDimConfig() puts every unconfigured dimension into the index field myfacets, index color/red into a destination index and size/large into a source index (each with its own taxonomy), and merge the source in with TaxonomyMergeUtils.merge, passing that FacetsConfig. You expect facet counts over myfacets to show color: red=1 and size: large=1, as they do when the same field is set with setIndexFieldName. Instead the merged document keeps its source ordinal, which in the destination taxonomy is color/red, so color shows red=2 and size is missing, with no error, because OrdinalMappingLeafReader re-maps only the fields of getDimConfigs() plus the static DEFAULT_DIM_CONFIG field $facets, not the config's own default field.",
   "impact_class": "data corruption",
   "introduced_commit": "1f37d6b4486fd93a669d75b6fcaaa9c712e9c00e (trunk, SVN r1612079; branch_4x backport 95c159ea65a, r1612081; 'LUCENE-5801: OrdinalMappingAtomicReader should not wrap non-facet BinaryDocValues fields', by shaie; JIRA LUCENE-5801, migrated as apache/lucene#6863; no PR, it predates the GitHub workflow) restricted re-mapping to the index fields of srcConfig.getDimConfigs(); one day later 2bf04d03083f9e8ec2db8c5c516c1b2de19e1d30 (trunk r1612197; branch_4x 1efd0974ecf, r1612198; 'LUCENE-5801: add default indexFieldName to facetFields') added only the static FacetsConfig.DEFAULT_DIM_CONFIG.indexFieldName, not the config's overridable getDefaultDimConfig() (LUCENE-5479, 074923dda7e / 1ea87054f0d, 2014-03-01, in 4.8.0), which gave the defect its current form [exec]. Not a regression of a released version",
   "introduced_date": "2014-07-20 (1f37d6b4486 / 95c159ea65a); current form 2014-07-21 (2bf04d03083 / 1efd0974ecf); first shipped in 4.10.0 (tag dated 2014-09-02)",
   "first_affected_version": "4.10.0 [exec] (its OrdinalMappingAtomicReader.java and TaxonomyMergeUtils.java are byte-identical to branch_4x 1efd0974ecf). 4.7.0 to 4.9.1 ship no FacetsConfig-based merge reader or TaxonomyMergeUtils [exec]; 4.6.1's pre-rewrite reader (FacetIndexingParams API) re-maps a customized default CategoryListParams field correctly [exec]",
   "affected_versions": "Every release from 4.10.0 through 10.5.2 (latest 9.x 9.12.3), 10.6.0 (by reading) and main a9779ef3c193; never fixed. [exec] the follow-up's history harness (merged facet counts, with explicit-field and stock $facets controls that pass) fails on 4.10.0 (-ea and -da), 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the finder's JUnit fails on 9.12.3, 10.5.2 and main (-ea and -da); the independent reproduction's JUnit fails on 9.12.3, 10.5.2 and main (-ea and -da) and the independent reproduction's pre-9.0 main() variant on 7.7.3 and 8.11.4; branch_10x 1309534296e, branch_10_6 2763db11b0a and upstream main a95c754ee003 (2026-10-26) have the same lines. The ordinals moved from binary to sorted-numeric doc values in 9.0 (LUCENE-10062, #264 and #443) behind the same facetFields gate. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/6863",
    "https://issues.apache.org/jira/browse/LUCENE-5801",
    "https://issues.apache.org/jira/browse/LUCENE-5479",
    "https://github.com/apache/lucene/issues/6542",
    "https://github.com/apache/lucene/issues/11780",
    "https://github.com/apache/lucene/issues/149"
   ],
   "doc": "",
   "repro": "repro/LFV-722/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-284",
   "priority": "medium",
   "priority_rank": 91,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / classic QueryParser and MultiFieldQueryParser (QueryParser.jj MultiTerm run grouping, QueryParserBase.addClause conjunction step)",
   "title": "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)",
   "summary": "You parse 'apple banana the AND cherry' with the classic QueryParser at its default settings and an analyzer that drops 'the', and expect the same query as for 'apple banana AND cherry', namely body:apple +body:banana +body:cherry, which is what Lucene 10.5.2 returns and what main returns with splitOnWhitespace=true. On main you get +(body:apple body:banana) +body:cherry, so a document containing only 'apple cherry' now matches; with the AND default operator, 'apple banana the OR cherry' becomes (+body:apple +body:banana) body:cherry instead of +body:apple body:banana body:cherry, so a document with only 'cherry' matches and one with only 'apple' no longer does. The cause is #16446, which now adds the analysed run 'apple banana' as one clause: the stopword yields no clause, so the following conjunction's 'make the preceding clause required (or optional)' step in addClause changes the whole run instead of 'banana'.",
   "impact_class": "silent wrong results",
   "introduced_commit": "c71ef11c549d4fcf4126936ddc0066e60029cab2 ('MultiFieldQueryParser: default operator is not honored between term positions (#16446)'; PR apache/lucene#16446 by OlivierJaquemet with co-author epotyom, which fixes #16443 and supersedes PR #16442 for #16441; merged 2026-10-22 by msokolov, milestone 10.6.0), backported to branch_10_6 as 88c0bd4c346 (2026-10-22, parent aac3c7ae947). It changed one line of the MultiTerm production (QueryParser.jj:405, generated QueryParser.java:747) from addMultiTermClauses(clauses, firstQuery), which put each position of an all-TermQuery run into the clause list, to addClause(clauses, CONJ_NONE, MOD_NONE, firstQuery), and removed QueryParserBase.addMultiTermClauses; addClause itself, which applies a conjunction's adjustment to the last clause before returning on a null query, has had that order since the 2001 initial import bd3948c539e. [exec]",
   "introduced_date": "2026-10-22 (c71ef11c549 on main; backport 88c0bd4c346 on branch_10_6 the same day)",
   "first_affected_version": "10.6.0 (released 2026-10-29; 10.5.2, the last release before it, passes [exec]; the backport 88c0bd4c346 is on branch_10_6 and the PR milestone is 10.6.0; on main, CHANGES lists #16441/#16443 under 11.0.0)",
   "affected_versions": "main (11.0.0-SNAPSHOT) from c71ef11c549 through ea57360912ed [exec]; 10.6.0 (released 2026-10-29) [exec]; branch_10_6 from 88c0bd4c346 [exec]. Not affected: 7.0.0, 8.11.4, 9.12.3, 10.0.0 and 10.5.2 [exec]; 6.2.0 .. 6.6.6 [read]; before 6.2.0 the splitOnWhitespace=false path did not exist; branch_10x (10.7.0 in development) does not contain #16446 [read]. Not fixed upstream as of 2026-10-26. All runs on JDK 25.0.3, aarch64 Linux; x86 not checked (no vector or platform-dependent code is involved).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-284.html",
   "repro": "repro/LFV-284/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b): 2 of 2 fail with -ea and -da; 10.5.2 passes 2 of 2."
  },
  {
   "id": "LFV-860",
   "priority": "medium",
   "priority_rank": 92,
   "novelty": "new",
   "withheld": false,
   "area": "search / index-sort range-query shortcuts (Sort.getPrimarySortField; SortedNumericDocValuesRangeQuery, SortedSetDocValuesRangeQuery, IndexSortSortedNumericDocValuesRangeQuery)",
   "title": "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",
   "summary": "You sort an index by two fields, say (c, f), and then either read it through a FilterLeafReader that hides c from FieldInfos but, like every FilterLeafReader by default, still reports the index sort (c, f) in getMetaData(), or sort by a BinarySortField subclass whose key is derived from another doc-values field, as its javadoc allows; a doc-values range query on f should still match exactly the documents whose f is in the range, as it does on 10.5.2. On main and 10.6.0, Sort.getPrimarySortField (added by #16424) finds no FieldInfo for c (or for the BinarySortField's own name), concludes that sorting by it 'has no effect', and returns f as the primary sort, so the range queries' index-sort shortcuts binary-search a segment that is not ordered by f. The result: most ranges miss matching documents and some return documents outside the range (43 of 55 ranges wrong in an independent test; f:[1 TO 3] returns 0 hits instead of 2), and LongField.newRangeQuery can throw IllegalArgumentException 'minDoc must be < maxDoc'.",
   "impact_class": "silent wrong results",
   "introduced_commit": "693a7234bad2e03abc80c3dc9819aef493095aeb (#16424 'Smarter use of sort-field optimizations in DV range queries', by romseygeek; branch_10x backport a22c06400da, which reaches branch_10_6 through its 2026-10-14 fork) [read]",
   "introduced_date": "2026-07-30 (author date 2026-07-30T11:37:19+01:00; merged 2026-07-30T10:37:20Z)",
   "first_affected_version": "10.6.0 (released 2026-10-29; the 10.6.0 RC1 artifacts, rev 4ae946e5a9b, fail 5/5 [exec]; 10.5.2 is clean [exec])",
   "affected_versions": "main / 11.0.0-SNAPSHOT since 693a7234bad [exec]; branch_10x since a22c06400da [read]; branch_10_6 head = 10.6.0 RC1 4ae946e5a9b [exec]. Not affected [exec]: 10.5.2, 10.5.1, 10.5.0 (5/5 pass), 10.4.0 and 10.0.0 (the 3 hidden-field tests pass; BinarySortField is absent), 9.12.3 and 9.10.0 (a version-neutral LongField leg passes). Every release before 10.6.0 lacks getPrimarySortField; its range shortcuts used only getSort()[0]. Recheck 2026-11-02: main e1faeba08bd [exec]; branch_11x da3ea39fa59 [read]; the 10.6.0 release jars fail the minimal repro with -ea and -da [exec]; the early-termination leg is main/branch_11x only (10.6.0 passes it [exec]).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-860.html",
   "repro": "repro/LFV-860/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 artifacts (4ae946e5a9b): 5 of 5 fail with -ea and -da; 10.5.2 passes 5 of 5."
  },
  {
   "id": "LFV-1051",
   "priority": "medium",
   "priority_rank": 93,
   "novelty": "new",
   "withheld": false,
   "area": "index / doc-values overlays (OverlaySortedNumericDocValues over DocValuesOverlayMerger), seen through search / field sorting (SortedNumericSelector, LongComparator, TopFieldCollector)",
   "title": "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)",
   "summary": "You index three documents with a multi-valued SortedNumericDocValuesField m = {50,60}, {10,90}, {30,40}, set doc 2 to the single value 70 with IndexWriter.updateSortedNumericDocValue (default IndexWriterConfig on main), and sort all documents by new SortedNumericSortField(\"m\", LONG), which keys each document by its minimum value. You expect doc 1 first (minimum 10), which is what you get with overlays disabled. You get doc 2: the overlay view ignores a second advanceExact on the document it already sits on, so when the collector reads doc 1 again its value cursor continues at 90 instead of restarting at 10, and with a MAX sort the cursor can run past the end of the column and throw.",
   "impact_class": "silent wrong results",
   "introduced_commit": "169cbffd12f4579ad8bd2906a4b70e2e70130711 (apache/lucene#16581 'Allow single-valued updates for SortedNumericDocValues', by HoustonPutman for their issue #16580; merged on main 2026-09-21; branch_10_6 cherry-pick eaa3a7a9edb the same day) [exec]. The defective step is older: DocValuesOverlayMerger.advanceExact, which moves only layers behind the target, comes from #16418 (75eddfaff22, jimczi, 2026-08-13; 10.x backport #16554 = 3a6cd003aaf) and was harmless there because the NUMERIC and BINARY overlay views have no per-document value cursor [read]. #16581 added OverlaySortedNumericDocValues, whose nextValue() reads the winning layer's cursor [read].",
   "introduced_date": "2026-09-21 (#16581, author and merge date on main and branch_10_6; the merger logic dates from #16418, 2026-08-13)",
   "first_affected_version": "10.6.0 [exec] (only with the @lucene.experimental opt-in IndexWriterConfig#setMaxDocValuesOverlays(n > 0); the 10.6.0 default of 0 overlays is not affected). On main (11.0.0-SNAPSHOT, unreleased) overlays are on by default (DEFAULT_MAX_DOC_VALUES_OVERLAYS = 8).",
   "affected_versions": "[exec] main 645d4fe14a20 with the default IndexWriterConfig (-ea and -da; finder seeds DEADBEEF, 1, C0FFEE and 5EED42, seed 5EED7A11), the introducing commit 169cbffd12f, and 10.6.0 with setMaxDocValuesOverlays(8) (published jars, SHA-1 verified: the repro fails with -ea, the independent reproduction's two tests fail 2 of 2 with -da, the GPT intended-lens test 2 of 3; also a core jar built from 4ae946e5a9b). Released in 10.6.0: the tag releases/lucene/10.6.0 exists (tag object e29d290eeb05, peels to 4ae946e5a9b; git ls-remote 2026-10-29). [read] upstream main head 716d6f216f5 and branch_10_6 head 7e5aec4370e: DocValuesOverlayMerger.java and OverlaySortedNumericDocValues.java unchanged since #16581 (GitHub commit history re-checked 2026-10-29). Not affected [exec]: 10.6.0 at its default (0 overlays, passes); 10.5.2, 9.12.3 and main before 169cbffd12f (the update API does not exist: compile error). Not affected by this mechanism on any version [exec]: NUMERIC and BINARY overlays and all-single-valued SORTED_NUMERIC columns (singleton path), 12,846 re-read checks, 0 mismatches.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1051.html",
   "repro": "repro/LFV-1051/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 (4ae946e5a9b): with the opt-in setMaxDocValuesOverlays(8) the repro fails with -ea and an independent second test fails 2 of 2 with -da, while the 10.6.0 default of 0 overlays passes; 10.5.2 does not have the code (no updateSortedNumericDocValue)."
  },
  {
   "id": "LFV-229",
   "priority": "medium",
   "priority_rank": 94,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / Thai (ThaiTokenizer#incrementWord user-dictionary loop and re-anchor, GITHUB#16722; ThaiTokenizerFactory 'dictionary')",
   "title": "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",
   "summary": "You configure ThaiTokenizer with a user dictionary that contains an ordinary short word such as แม่น ('accurate') or ผล ('result') and expect it to change only where words split. Instead, when the dictionary word is followed in the text by a combining vowel or tone mark, as in แม่น้ำ ('river') or ผลิต ('produce'), the tokenizer cuts the character cluster and throws the mark away: แม่น้ำ becomes the single token แม่น, and ผลิต becomes [ผล, ต]. Because queries are analyzed the same way, a search for แม่น้ำ also matches documents that only contain แม่น, with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "6b44b4c2a3afadee94c035d680d8dc9856ee93d7 on main (GITHUB#16722 for issue #16721, 'Support user dictionary in ThaiTokenizer and ThaiTokenizerFactory', author kamthorn, merged by rmuir) and its backport 2ba75780cd6d on branch_10x and branch_10_6; the commit added the longest-prefix dictionary loop and the BreakIterator re-anchor [read]. The non-letter skip loop that finally discards the mark-initial remainder (ThaiTokenizer.java:173-180, LUCENE-4984, 2014) is harmless without a dictionary (no-dictionary control passes on 9.12.3, 10.5.2 and main [exec])",
   "introduced_date": "2026-09-28 (main, 00:58:58Z; branch_10x / branch_10_6 backport 2026-09-28T15:37:57Z)",
   "first_affected_version": "10.6.0 (released 2026-10-29; CHANGES.txt lists GITHUB#16722 under 10.6.0 New Features)",
   "affected_versions": "main ea57360912ed [exec]; branch_10_6 (10.6.0, released 2026-10-29) and branch_10x [read]; not affected: 10.5.2, 9.12.3 and every earlier release, which do not have the ThaiTokenizer(CharArraySet) API (the repro is a compile error [exec]); not fixed upstream: no commit on ThaiTokenizer.java after b304eeae024 (2026-09-29) on main, branch_10x or branch_10_6, and no open PR touches the Thai package or SegmentingTokenizerBase [read]. Executed only on JDK 25.0.3 (aarch64); the cut itself does not depend on the JDK's Thai segmentation, because the re-anchored text always starts with the mark",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-229.html",
   "repro": "repro/LFV-229/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b): 3 of 4 fail with -ea and -da; 10.5.2 does not have the ThaiTokenizer user dictionary."
  },
  {
   "id": "LFV-261",
   "priority": "medium",
   "priority_rank": 95,
   "novelty": "new",
   "withheld": false,
   "area": "search / similarities: StableTflSimilarity with SynonymQuery and CombinedFieldQuery",
   "title": "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",
   "summary": "You set StableTflSimilarity on the searcher, whose javadoc derives a term's rarity from the length |t| of the query term, and you search with a SynonymQuery (for example the one QueryBuilder builds when a synonym filter stacks 'dog' and 'dogs' at one position) or with a CombinedFieldQuery. You expect the real query terms' length to be used, so that SynonymQuery{ab, cd} on a document that contains 'ab' once scores like TermQuery(ab), and a one-field CombinedFieldQuery scores like a TermQuery on a copy field. Instead both queries hand the similarity a fixed placeholder term ('synonym pseudo-term', 19 code points; 'pseudo_term', 11 code points), so every synonym group is scored as an almost maximally rare 19-character term and every combined-field term as an 11-character one: SynonymQuery{ab, cd} scores 1.4050181 instead of 1.3490043, and in 200-token documents the group {dog, dogs} scores 2.13x TermQuery(dog) and outranks a document that matches 'elephant'.",
   "impact_class": "silent wrong results",
   "introduced_commit": "e3a7a733c8a9 (#16243 'StableTfl Similarity', author txwei, merged by mccullocht), which added StableTflSimilarity and its read getTermLength(termStats[i].term()) [read]; backport #16322 (8e40c912555b) to branch_10x, which branch_10_6 contains; an interaction bug: the placeholders it exposes are older and were harmless while no Similarity read TermStats.term(): SynonymQuery's 'synonym pseudo-term' from e0bde579815 (LUCENE-8020, 2017, replacing a null term) and CombinedFieldQuery's 'pseudo_term' from fd96bc5ca6b (LUCENE-8216, 2018, sandbox BM25FQuery), copied into core by 239059e69cf (#14236, 2025)",
   "introduced_date": "2026-07-01 (#16243 merged on main; backport #16322 merged the same day); the placeholders date from 2017-10-30 (LUCENE-8020) and 2018-11-21 (LUCENE-8216)",
   "first_affected_version": "10.6.0 (released 2026-10-29; CHANGES.txt lists GITHUB#16243 under Lucene 10.6.0 New Features, on main and on branch_10_6)",
   "affected_versions": "main 11.0.0-SNAPSHOT from e3a7a733c8a9 through ea57360912ed [exec]; branch_10_6 (10.6.0-SNAPSHOT, head 2763db11b0a7) and branch_10x (10.7.0-SNAPSHOT, head 1309534296e3) [exec]; identical failing values on all four builds; not affected: 10.5.2, 9.12.3 and every older release, and the parent commit d87b4f388151, because StableTflSimilarity does not exist there (the repro does not compile) [exec]; not fixed upstream as of 2026-10-26 (upstream main HEAD ea57360912ed, no later commits to the three files, no open PR changes the code) [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-261.html",
   "repro": "repro/LFV-261/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b): 3 of 3 fail with -ea and -da; 10.5.2 does not have StableTflSimilarity."
  },
  {
   "id": "LFV-628",
   "priority": "medium",
   "priority_rank": 96,
   "novelty": "new",
   "withheld": false,
   "area": "search / SynonymQuery pseudo-term statistics (SynonymWeight; reached through QueryBuilder with stock synonym parsers)",
   "title": "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)",
   "summary": "You search with a SynonymQuery that contains the same term more than once, built with SynonymQuery.Builder or produced by QueryBuilder when a synonym rule's entries coincide after analysis (the rule 'résumé, resume, cv' with ASCII folding gives Synonym(f:cv f:resume f:resume) for the query 'resume'), and expect the pseudo-term statistics it hands to the Similarity to stay within the field's totals, which TermStats lists as 'always true' (totalTermFreq <= sumTotalTermFreq of the field). Instead SynonymWeight takes the largest docFreq of the terms but adds the repeated term's totalTermFreq once per copy: on a field with the documents 'a' and 'a a b' (sumTotalTermFreq 4), SynonymQuery(a, a) passes totalTermFreq 6. With assertions enabled every SimilarityBase similarity throws AssertionError from fillBasicStats when the Weight is built; with assertions disabled they score from impossible statistics, for example LM Dirichlet uses a collection probability P(t|C) of 1.17 for SynonymQuery(x, x, x) where TermQuery(x) uses 0.5.",
   "impact_class": "silent wrong results",
   "introduced_commit": "a944ab17a712f58e8417639763a0c7267fa11e61 (svn r1703070; LUCENE-6789 'change IndexSearcher default similarity to BM25', migrated to GitHub as apache/lucene#7847, by rmuir; a patch attached to the JIRA issue, no pull request). It added SynonymQuery: SynonymWeight took the max docFreq but summed totalTermFreq over every terms[] entry, and the constructor only sorted the terms [read]. The bound it breaks: the SimilarityBase.fillBasicStats assertion dates from LUCENE-3723 (1b9e732beda, 2012-01-25, 4.0; then with a -1 escape for missing statistics), and LUCENE-8007 (ca5f9b34576, 2017-11-02, 8.0.0) added the TermStatistics 'always true' javadoc and the cross-check TODO and dropped the -1 escape. No commit ever deduplicated SynonymQuery terms (git log -G on SynonymQuery.java).",
   "introduced_date": "2015-09-14",
   "first_affected_version": "6.0.0 [exec] (released 2016-04-07), the first release with SynonymQuery; 5.5.5, the last 5.x release, has no SynonymQuery (its QueryBuilder builds a BooleanQuery whose per-term statistics stay in bounds) and is not affected [exec]",
   "affected_versions": "Every release from 6.0.0 to 10.6.0 (10.6.0 by reading) and main a9779ef3c193; never fixed. [exec] with -ea and -da: 6.0.0, 7.7.3, 8.0.0 and 8.11.4 (an API-adapted copy of the finder's test plus a distinct-terms control that passes everywhere), 9.12.3 and 10.5.2 (the finder's release variant and the independent reproduction's own test), main a9779ef3c193 (finder, the independent reproduction, the intended-behaviour check, the adjudication, the registration check); the cross-model reviews ran on the previous main ea57360912ed, where none of the involved files differ. [read]: upstream main a95c754ee003 (2026-10-26), branch_10x and branch_10_6 still sum per entry. Code reading, not executed: before 8.0, fields without frequencies reported totalTermFreq -1 and the assertion was skipped, so in 6.x-7.x only fields with frequencies can break the bound; since 8.0, DOCS-only fields report totalTermFreq = docFreq and can break it too.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-628.html",
   "repro": "repro/LFV-628/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1103",
   "priority": "medium",
   "priority_rank": 97,
   "novelty": "known",
   "withheld": false,
   "area": "search / BlendedTermQuery with IndexSearcher statistics overrides",
   "title": "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)",
   "summary": "You search a shard with an IndexSearcher whose termStats/fieldStats overrides add another shard's statistics, as the in-tree ShardSearchingTestBase does, and expect a BlendedTermQuery over 'apple' and 'pear' to score the two one-word documents identically, as the class javadoc promises. Instead BlendedTermQuery.rewrite blends the shard's own statistics (df = max, ttf = sum) and TermQuery passes those blended values as the docFreq/totalTermFreq arguments of termStats, which the override turns back into per-term values: 'apple' scores 0.630 and 'pear' 0.131.",
   "impact_class": "silent wrong results",
   "introduced_commit": "unknown (not bisected); BlendedTermQuery has blended in rewrite() since it was added (LUCENE-6695, 2015-07-27) and the statistics hooks take the passed-in values [read]; executed back to 8.0.0 by the first finder",
   "introduced_date": "unknown (not bisected)",
   "first_affected_version": "unknown (not bisected); oldest executed 8.0.0 [exec]",
   "affected_versions": "8.0.0 to 9.12.3 [exec]; 10.5.2 and 10.6.0 (released) [exec]; main 645d4fe14a20 and e1faeba08bde with -ea and -da [exec]",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-8840",
    "https://github.com/apache/lucene/issues/9884",
    "https://github.com/apache/lucene/issues/16847"
   ],
   "doc": "",
   "repro": "repro/LFV-1103/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-093",
   "priority": "medium",
   "priority_rank": 98,
   "novelty": "new",
   "withheld": false,
   "area": "misc / BP merge-time reordering",
   "title": "Merges through BPReorderingMergePolicy with BpVectorReorderer break document blocks even when a parent field is configured",
   "summary": "You index documents in blocks (children followed by their parent) with IndexWriterConfig#setParentField, and use BPReorderingMergePolicy with a BpVectorReorderer over a float vector field. You expect merges to keep every block together with its parent last, because IndexWriter only lets a merge reorder documents when the parent field identifies the blocks, and setParentField promises that IndexWriter does not alter the order of a block. Instead BpVectorReorderer moves each document on its own and puts every document without a vector after all documents with one, so the merged segment's blocks are silently scrambled and ToParentBlockJoinQuery joins children to the wrong parent (59 of 60 children in one run), with no exception and with assertions on or off.",
   "impact_class": "silent wrong results",
   "introduced_commit": "02a09f6ab124 (#14097 'HNSW BP reordering', main) [read]; #14097 added BpVectorReorderer without block handling and widened the BPReorderingMergePolicy constructor from BPIndexReorderer to IndexReorderer, inside the IndexWriter reorder gate that #13128 (4a3f4cfe974, 2024-03-29) had made conditional on a parent field; not a regression of BpVectorReorderer, which has broken blocks since it was added",
   "introduced_date": "2025-01-07",
   "first_affected_version": "unreleased (main only, 11.0.0-SNAPSHOT; no release tag contains 02a09f6ab12)",
   "affected_versions": "main from 02a09f6ab12 (2025-01-07) through ea57360912ed [exec]; no release is affected: 9.12.3, 10.1.0, 10.2.0 and 10.5.2 have no BpVectorReorderer or IndexReorderer, so the repro does not compile, and their BPReorderingMergePolicy (BPIndexReorderer only) keeps blocks under the same merge [exec]; branch_10x, branch_10_6 and branch_10_5 have neither class [read]; CHANGES.txt lists GITHUB#14097 under 11.0.0, so 11.0.0 ships it unless it is fixed first [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-093.html",
   "repro": "repro/LFV-093/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1022",
   "priority": "medium",
   "priority_rank": 99,
   "novelty": "new",
   "withheld": false,
   "area": "misc / index: BpVectorReorderer command line (main -> reorderIndexDirectory, an in-place rewrite through an OpenMode.CREATE IndexWriter and addIndexes)",
   "title": "BpVectorReorderer's in-place command-line reorder commits an empty or partial index over the original when reordering fails",
   "summary": "You run BpVectorReorderer's command line (main(path, field), which calls reorderIndexDirectory) to renumber the documents of an existing index in place, and expect that if the reorder fails you get the exception and the index still holds all its documents. Instead, when computing a doc map or addIndexes throws (for example the documented NotEnoughRAMException), the try-with-resources around the OpenMode.CREATE IndexWriter closes it, close() commits by default, and the new commit holds only the segments rewritten before the failure, while the original commit and its files are deleted. A 10-document index ends with 0 documents, and through main() with default options an index created by Lucene 9.x or 10.x, or one with a soft-deletes or parent field, is wiped to 0 documents.",
   "impact_class": "data corruption",
   "introduced_commit": "02a09f6ab124e994fd1af42965617c8b5ec67bcc, apache/lucene#14097 'HNSW BP reordering' (by msokolov; author date = commit date 2025-01-07, merged to main 2025-01-07T14:41:35Z): it added BpVectorReorderer with main() and reorderIndexDirectory (an OpenMode.CREATE IndexWriter on the input directory in try-with-resources, one addIndexes per leaf, no rollback) and AbstractBPReorderer with NotEnoughRAMException and setRAMBudgetMB [exec]. The same in-place pattern is already in the final patch of the author's earlier, unmerged PR #13683 'HNSW BP reorder tool'. Pre-existing mechanism, not the defect: close() commits by default (IndexWriterConfig.DEFAULT_COMMIT_ON_CLOSE, 872bd9145cd, LUCENE-5871, 2014-08-09).",
   "introduced_date": "2025-01-07",
   "first_affected_version": "unreleased (main only, 11.0.0-SNAPSHOT; CHANGES.txt lists GITHUB#14097 in the 11.0.0 section; BpVectorReorderer and AbstractBPReorderer are absent from every 9.x and 10.x release and from branch_10x, branch_10_6 (10.6.0) and branch_10_5 [exec]); the first affected release would be 11.0.0 unless it is fixed first",
   "affected_versions": "main from 02a09f6ab12 (2025-01-07) through 645d4fe14a20 (upstream main head, re-checked 2026-10-29) [exec]. Not affected, the API is absent: 9.12.3, 10.1.0, 10.2.0, 10.5.2 and the parent 72d93de50c2 [exec]; branch_10x 657014b3c57, branch_10_6 4ae946e5a9b (10.6.0 RC1) and branch_10_5 e85bb7b2c86 [read]. All runs on Linux aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1022.html",
   "repro": "repro/LFV-1022/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-211",
   "priority": "medium",
   "priority_rank": 100,
   "novelty": "new",
   "withheld": false,
   "area": "queries / FunctionScoreQuery block-max pruning (#16431)",
   "title": "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",
   "summary": "You index a popularity field with a skip index (NumericDocValuesField.indexedField(\"popularity\", v)) and search BooleanQuery(SHOULD FunctionScoreQuery(TermQuery(body:a), DoubleValuesSource.fromLongField(\"popularity\")), SHOULD TermQuery(body:b)) for the top hit, expecting the same hit as an exhaustive search, because the function query scores each matching document by its popularity value. Instead, with 5,000 documents that all match body:a, where only doc 4999 has popularity 100 (all others 1) and only doc 0 matches body:b, TOP_SCORES and the plain IndexSearcher.search(q, 1) return doc 0 (score 4.69) instead of doc 4999 (score 100). The cause is that the scorer's getMaxScore returns innerMaxScore * valueMaxScore * boost, where innerMaxScore is the max score of the wrapped TermQuery, which FunctionScoreQuery itself weighted without scores (so it reports 0), although score() is value * boost and never reads the wrapped score; every block therefore reports a bound of 0, and MaxScoreBulkScorer stops scoring documents that only the function clause makes competitive.",
   "impact_class": "silent wrong results",
   "introduced_commit": "0d4f93a9ff93ccc396c1323f26416b57d8dc08d9 on main (apache/lucene#16431 'Enable Block-Max WAND dynamic pruning for FunctionScoreQuery via DocValuesSkipper (+422% QPS)', by rajat315315 with uschindler as co-author, related issue #16429, merged 2026-08-22) [exec]; it replaced the scorer's +Infinity bound with innerMaxScore * valueMaxScore * boost, where the inner scorer comes from the COMPLETE_NO_SCORES weight that createWeight has used for score-independent sources since LUCENE-4100 (4fc5a872ded, 2017; the current lines 111-117 are from LUCENE-9393, e1a97a0f1ea, 2020), and a TermQuery weighted that way has reported a max score of 0 since #12383 (40ee6e583e1, 2023, a dummy no-score SimScorer); the silent wrong top hit became reachable end to end with #16697 (d150ba27d11, by easyice, 2026-10-09), which fixed a separate advanceShallow defect that made the tested SHOULD query throw first [exec]",
   "introduced_date": "2026-08-22 (0d4f93a9ff9 on main); silent wrong top hit reachable end to end from 2026-10-09 (d150ba27d11, #16697) for the executed SHOULD query shape",
   "first_affected_version": "unreleased (main only; 11.0.0 would be the first release with it) [exec]",
   "affected_versions": "main (11.0.0-SNAPSHOT) from 0d4f93a9ff9 (2026-08-22) through 645d4fe14a2 (upstream main head, re-run 2026-10-29) [exec]; not affected: 10.0.0 [exec] and 10.5.2 [exec] (FunctionScoreQuery's bound is +Infinity there) and the parent commit a1fcd50799f [exec]; not applicable: 9.12.3 [exec]; unreleased branch_10x, branch_10_6 and branch_10_5 do not contain #16431 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-211.html",
   "repro": "repro/LFV-211/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-435",
   "priority": "medium",
   "priority_rank": 101,
   "novelty": "known",
   "withheld": false,
   "area": "search / TermQuery equality and BooleanQuery clause de-duplication (blended and fuzzy TermStates)",
   "title": "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)",
   "summary": "You OR two fuzzy queries, FuzzyQuery('aaaab', 1) and FuzzyQuery('baaaa', 1), which both expand to the indexed term 'aaaa', and search with LMDirichletSimilarity; you expect each document to score the sum of the two clause scores, as it does under BM25 and as #12354 ('Do not merge term queries with different docFreq', the fix of #10309) set out to restore. Instead the blended rewrite gives both TermQuery(t:aaaa) clauses the same docFreq (the max, 3) but different totalTermFreq (the sum, 4 and 8); TermStates#equals compares only docFreq, so BooleanQuery merges them into (t:aaaa)^1.5 with the first clause's statistics, and docs 0-2 score 0.0011983 instead of 0.00059916, while the same query with the clauses swapped (equal per BooleanQuery#equals) scores them 0.0.",
   "impact_class": "silent wrong results",
   "introduced_commit": "3e077fdc076db88872d8cb6955e21907e8fe0c39 (apache/lucene#12354 'Fix docFreq in score calculation after rewrite of boolean query consisting of blended query and boosted term query', by rafalh, merged by stefanvodita into main, fixing #10309 = LUCENE-9269) added TermStates#equals/hashCode on docFreq only and made TermQuery equality delegate to it [read] [exec]. An incomplete fix, not a regression: before it the same input was mis-scored through the broader #10309 defect (TermQuery#equals ignored TermStates), since LUCENE-7386 (flattening of nested disjunctions, 8.1.0) for FuzzyQuery disjunctions and since LUCENE-7925 (collapsing duplicate SHOULD/MUST clauses, 7.1.0) for hand-built flat clause lists [exec]",
   "introduced_date": "2026-01-24 (#12354, the docFreq-only equality); symptom origins 2017-08-21 (LUCENE-7925) and 2019-04-18 (LUCENE-7386)",
   "first_affected_version": "unreleased (main / 11.0.0-SNAPSHOT only: #12354 is in no release tag, not in 10.5.2 and not on branch_10x or branch_10_6 as fetched 2026-10-26). The same inputs fail on 7.1.0-10.5.2 [exec], but through the original, broader #10309 defect",
   "affected_versions": "As a distinct defect: main ea57360912ed only [exec]; no release. The symptom through the original #10309 defect [exec]: 8.1.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0 and 10.5.2 (also -da) fail 5 of 6 for FuzzyQuery disjunctions, the docFreq control included; the finder's first, 2-test JUnit also fails on 10.3.2, 10.4.0 and 10.5.2; 7.1.0, 7.7.3 and 8.0.0 fail only the hand-built flat clause tests (flatTtf and the flatDf control); 7.0.1 passes 6 of 6; releases before 7.0.1 not executed. branch_10x and branch_10_6 heads: TermQuery#equals still compares the term only [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/10309",
    "https://issues.apache.org/jira/browse/LUCENE-9269",
    "https://github.com/apache/lucene/issues/12354",
    "https://github.com/apache/lucene/issues/16847",
    "https://github.com/apache/lucene/issues/9884",
    "https://issues.apache.org/jira/browse/LUCENE-8840"
   ],
   "doc": "",
   "repro": "repro/LFV-435/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-109",
   "priority": "medium",
   "priority_rank": 102,
   "novelty": "known",
   "withheld": false,
   "area": "index / DirectoryReader reopen with doc-values updates (generation numbers reused across writer sessions)",
   "title": "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",
   "summary": "You keep a reader open while a writer session updates doc values and then ends without committing (rollback(), or close() with commitOnClose=false), or while a writer opened on an older commit with setIndexCommit discards the newer commit; a later writer session updates doc values of the same segment and commits, and you reopen the old reader with DirectoryReader.openIfChanged. You expect the reopened reader to show the latest commit, as a fresh DirectoryReader.open on that commit does ('If the IndexCommit differs from what the provided reader is searching, open and return a new reader'). Instead it silently returns the discarded values (for example 99 11 instead of 10 300), because the later session wrote different files under the same doc-values generation number and the reopen reuses the old reader's doc-values producer for that number.",
   "impact_class": "silent wrong results",
   "introduced_commit": "1120e46961b2 (trunk, svn r1523461, 'LUCENE-5189: add NumericDocValues updates'; LUCENE-5189 = GitHub #6253, pre-GitHub, no PR), first released through the branch_4x merge 49684b82701b (svn r1537832, 'LUCENE-5189: add NumericDocValues field updates') [exec]; the bug came in with doc-values updates themselves. The sharing line on main (SegmentReader.java:153) blames to d37b2cb90b1 ('LUCENE-5189: factor out SegmentDocValues from SegmentReader', 2013-10-24) [read]. LUCENE-5931 (#6993; 664e39292bd / 6b0b119074f, first released in 6.2.0) changed the path to the stale producer, not the outcome [exec]",
   "introduced_date": "2013-09-15 (trunk 1120e46961b); 2013-11-01 (branch_4x 49684b82701); first release 4.6.0, tagged 2013-11-22",
   "first_affected_version": "4.6.0 [exec] (the first release with doc-values updates; 4.5.1 lacks the API [exec])",
   "affected_versions": "every release from 4.6.0 through 10.5.2, and main ea57360912ed. Executed with the follow-up history probe (public API, the finder's scenario and oracle: the reopened values must equal a fresh reader on the same commit): 4.6.0 (-ea and -da), 4.6.1, 4.8.1, 4.9.0, 4.10.0, 4.10.1, 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.1.0, 6.2.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) all print reopened 100 1 2 versus fresh 0 200 2; the finder JUnit fails unchanged on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea, -da); the independent reproduction's, the cross-model review's and the intended-behaviour check's own tests fail on main, 10.5.2 and 9.12.3; the setIndexCommit variant (no NRT reader, no rollback) fails on main, 10.5.2 and 9.12.3 [exec]. All 112 release tags from 4.6.0 to 10.5.2 in the history clone contain a LUCENE-5189 commit [read] (the clone has no 8.x tags after 8.8.1; 8.11.4 was executed). Two reader paths, same outcome [exec]: 4.6.0-6.1.0 reuse the whole old SegmentReader through the delGen/fieldInfosGen 'No change' check; from 6.2.0 the isNRT branch builds a new SegmentReader that shares the old generation-keyed SegmentDocValues. Not affected: 4.5.1 and earlier (no doc-values updates) [exec]. Not fixed upstream at ea57360912ed [exec]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9780",
    "https://issues.apache.org/jira/browse/LUCENE-8734",
    "https://github.com/apache/lucene/issues/9781",
    "https://issues.apache.org/jira/browse/LUCENE-8735",
    "https://github.com/apache/lucene/issues/10364",
    "https://issues.apache.org/jira/browse/LUCENE-9324"
   ],
   "doc": "",
   "repro": "repro/LFV-109/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-430",
   "priority": "medium",
   "priority_rank": 103,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter tryDeleteDocument (dropDeletedSegment, change accounting)",
   "title": "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",
   "summary": "You call tryDeleteDocument on the only live document of a segment, and closing that segment's pooled reader inside IndexWriter throws an IOException; the writer stays open and you keep using it. You expect what the writer serves to its NRT readers to be what commit() persists, and hasUncommittedChanges() to report the pending change. Instead the segment is already gone from the writer's SegmentInfos but checkpoint() and changed() were skipped, so new NRT readers no longer show the document while hasUncommittedChanges() is false, commit() returns -1 and, after close(), the committed index still contains the document.",
   "impact_class": "silent wrong results",
   "introduced_commit": "3a3a883a92e (branch_4x) / 21e7728e573 (trunk), LUCENE-4203 = apache/lucene#5275 'Add IndexWriter.tryDeleteDocument' (mikemccand): the fully-deleted branch was segmentInfos.remove, readerPool.drop, checkpoint() with no try/finally [read]. LUCENE-4521 (e78363069a3 / c898b447223, 4.1.0) added the change-count bump after that branch, which the same exception also skips. The order never changed (LUCENE-7868 58105a203a1 moved it into dropDeletedSegment; LUCENE-8043 b7d8731bbf2 added a finally there that repairs only pendingNumDocs; LUCENE-8297 b0b32931b28 moved it into tryModifyDocument). Realistic-trigger gate: LUCENE-7775 = #8826 (765d031c865 branch_6x / d9973a38db9 master), which stopped SegmentDocValues.decRef from swallowing close exceptions [exec]",
   "introduced_date": "2012-08-02 (LUCENE-4203, defective code); 2017-04-10 (LUCENE-7775, realistic trigger becomes reachable)",
   "first_affected_version": "6.6.0 for a realistic trigger [exec]. The defective code ships since 4.0.0-BETA (first GA 4.0.0), where only an artificial trigger (a leaf of an NRT reader the caller already closed) reproduces it [exec]; no realistic trigger before 6.6.0 was found, but none was proved impossible",
   "affected_versions": "every release from 6.6.0 through 10.5.2 and main ea57360912ed [exec]; branch_10_6 (10.6.0, released 2026-10-29) and the unreleased branch_10x (snapshots of 2026-10-24) have the same code [read]. Latent (artificial trigger only) in 4.0.0-BETA-6.5.x [exec]; not present in 4.0.0-ALPHA [exec]. Not fixed upstream: upstream main cf398bfb142c is unchanged in these files and no open PR touches the fix site [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9738",
    "https://issues.apache.org/jira/browse/LUCENE-8692",
    "https://github.com/apache/lucene/issues/5587",
    "https://issues.apache.org/jira/browse/LUCENE-4521",
    "https://github.com/apache/lucene/issues/6327",
    "https://issues.apache.org/jira/browse/LUCENE-5263"
   ],
   "doc": "",
   "repro": "repro/LFV-430/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-452",
   "priority": "medium",
   "priority_rank": 104,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter deleteAll (change accounting on the exception path, ReaderPool.dropAll)",
   "title": "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",
   "summary": "You commit two documents, open and close an NRT reader (so the writer keeps pooled segment readers), and call deleteAll(); closing one of the pooled readers throws (for example a core ClosedListener your cache registered throws its declared IOException, or closing a file fails), so deleteAll() throws an IOException and the writer stays open. You expect the writer to stay self-consistent: what its NRT readers show is what commit() persists, and hasUncommittedChanges() reports the pending change. Instead deleteAll has already removed every segment but skipped counting the change, so new NRT readers show 0 documents while hasUncommittedChanges() is false, commit() returns -1 and writes nothing, close() keeps both documents on disk, and the next unrelated addDocument plus commit silently applies the deleteAll that failed.",
   "impact_class": "silent wrong results",
   "introduced_commit": "64a55ede8b53e3d05ab4bafdb042e0d89a9385dc (svn r788785), 'LUCENE-1705: add deleteAll to IndexWriter' (committed by mikemccand, JIRA patch by Tim Smith; JIRA LUCENE-1705 = GitHub issue #2779; no pull request, it predates GitHub): deleteAll counted the change (++changeCount) after every fallible step and never in a finally, and that order never changed afterwards [read]. The reported trigger (an exception while closing a pooled segment reader) became reachable with e933942dc3436c6538f5a78b6a9bd8b3439011db (trunk, svn r1163568) / 571526c2795981557b3254c8a41250423608a441 (branch_3x, svn r1163594), 'LUCENE-3409: drop reader pool from IW.deleteAll' (GitHub #4482), first released in 3.4.0 [exec]",
   "introduced_date": "2009-06-26 (LUCENE-1705, the accounting order); 2011-08-31 (LUCENE-3409, the reported reader-close trigger)",
   "first_affected_version": "2.9.0 [exec], through the older trigger only (a failing directory listing in deleteAll's deleter refresh, removed in 4.3.1 by LUCENE-5002); 3.4.0 for the reported trigger, an exception while closing a pooled segment reader [exec]; 2.4.1 has no deleteAll [exec]",
   "affected_versions": "main ea57360912ed and every release from 4.5.1 to 10.5.2 through the reported reader-close trigger (from 7.0 also through a throwing core ClosedListener) [exec] [read]; 3.4.0-4.0.0 through both triggers [exec]; 2.9.0-3.3 and 4.1.0-4.3.0 through the directory-listing trigger only (4.1.0-4.5.0 swallowed reader-close failures in ReaderPool.dropAll, LUCENE-4657, until LUCENE-5263 in 4.5.1) [exec]; 4.3.1, 4.4.0 and 4.5.0: neither executed trigger reproduces although the order is unchanged [exec]. Not checked: 10.6.0 (released 2026-10-29). Not fixed: upstream main has the same deleteAll body (2026-10-26) and no open PR changes it.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16625",
    "https://github.com/apache/lucene/issues/16643",
    "https://github.com/apache/lucene/issues/6122",
    "https://issues.apache.org/jira/browse/LUCENE-5058",
    "https://github.com/apache/lucene/issues/9738",
    "https://issues.apache.org/jira/browse/LUCENE-8692"
   ],
   "doc": "",
   "repro": "repro/LFV-452/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-474",
   "priority": "medium",
   "priority_rank": 105,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter deleteAll versus a concurrent segment flush (DocumentsWriter.lockAndAbortAll, flush-ticket queue)",
   "title": "IndexWriter.deleteAll misses a segment flush that another thread is already running, so documents added before deleteAll survive it and are committed",
   "summary": "Several threads index into one IndexWriter, and one of them is in the middle of writing its full in-memory buffer out as a new segment when another thread calls deleteAll(). You expect deleteAll to drop every buffered document and every segment, like opening a new IndexWriter with OpenMode.CREATE, so the next commit is empty: every document was added with a smaller sequence number than deleteAll's, and some of those addDocument calls had already returned before deleteAll was called. Instead deleteAll returns without waiting for that segment to be published, the flushing thread then adds it to the freshly cleared index, and its documents survive deleteAll into the commit, still carrying the old field schema.",
   "impact_class": "silent wrong results",
   "introduced_commit": "75ab79f0aa3509192451c8acb77a4f4f1011fa2e (trunk, svn r1515459) and 8003cc7829823ba48bf67686c999b7fb7e4fd42f (branch_4x, svn r1515463), 'LUCENE-5006: Simplified DW and DWPT synchronization and concurrent interaction with IW' (s1monw; JIRA LUCENE-5006 = GitHub issue #6070, still open; no pull request, it predates GitHub): segment publishing moved out of DocumentsWriter.doFlush, where it ran before flushControl.doAfterFlush released waitForFlush, into an IndexWriter event processed after doAfterFlush, so deleteAll's waitForFlush can return before an in-flight flush has published [read]. Later changes kept the window open: LUCENE-7868 (58105a203a1, 7.0.0) added the ticketQueue.forcePurge at the start of lockAndAbortAll, before waitForFlush; LUCENE-8269 / LUCENE-8271 (6f0a884582a / d32ce909241, 7.4.0) made that purge discard tickets; LUCENE-9304 (2602269f3ec, 8.6.0) gave the backlog check its form ticketCount >= perThreadPool.size(); #12647 (268dd54a869, 9.9.0) reshaped doFlush.",
   "introduced_date": "2013-08-19",
   "first_affected_version": "4.5.0 [exec]; 4.3.1 and 4.4.0 are not affected [exec]; 4.3.0 deadlocks instead (the known LUCENE-5002, #6066, fixed in 4.3.1)",
   "affected_versions": "[exec] main ea57360912ed (-ea and -da) and the releases 4.5.0, 4.8.0, 4.8.1, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.0.0, 7.3.1, 7.4.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0 and 10.5.2 all keep documents after deleteAll plus commit (core-only main() probes per API era; the finder's JUnit on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main; the independent reproduction's JUnit on 10.5.2 and 9.12.3 with -ea and -da); releases between those were not run individually. The field-reuse consequence (merge and new IndexWriter fail) was executed only on 9.1.0 and later. Not affected [exec]: 4.3.1, 4.4.0; 4.3.0 deadlocks (LUCENE-5002). Not fixed: upstream main 49483e82b357 has lockAndAbortAll unchanged, no commit since 2026-09-01 touches DocumentsWriter*.java on main, branch_10x or branch_10_6, and no open PR changes it (2026-10-26)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/6070",
    "https://issues.apache.org/jira/browse/LUCENE-5006",
    "https://issues.apache.org/jira/browse/LUCENE-9617",
    "https://github.com/apache/lucene/issues/6066",
    "https://issues.apache.org/jira/browse/LUCENE-5002",
    "https://github.com/apache/lucene/issues/9829"
   ],
   "doc": "",
   "repro": "repro/LFV-474/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1074",
   "priority": "medium",
   "priority_rank": 106,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter addIndexes vs deleteAll (writer-wide field schema, FieldInfos.FieldNumbers)",
   "title": "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",
   "summary": "One thread imports an index with IndexWriter.addIndexes while another thread calls deleteAll() on the same writer. You expect the outcome of one of the two orders: either the imported documents are deleted, or they stay and their fields keep their doc-values types, and in both cases the committed index opens again in a new IndexWriter. Instead deleteAll can clear the imported fields from the writer's schema while addIndexes still publishes the imported segment, so a later document can give an imported field another doc-values type, the commit succeeds, and the next new IndexWriter on that index throws IllegalArgumentException ('cannot change field \"f\" from doc values type=NUMERIC to inconsistent doc values type=SORTED').",
   "impact_class": "index unusable",
   "introduced_commit": "041ff1140f3f207ab0a3571c92a738b328142e95 (author Michael McCandless, 'make DV strongly typed; fix solr', on the LUCENE-4547 feature branch, svn branches/lucene4547 r1412906; LUCENE-4547 'DocValues field broken on large indexes' = apache/lucene#5613; svn era, no pull request), released through the trunk merge a181dc07353 (2013-02-07) and the branch_4x commit 5cbaddcbc7f (2013-02-08), both 'LUCENE-4547: DocValues improvements' (CHANGES 4.2.0): that one commit made doc-values types strict per field, made deleteAll() call globalFieldNumberMap.clear(), and made addIndexes(Directory...) register incoming fields with globalFieldNumberMap.addOrGet outside the IndexWriter monitor, before the copy and before its synchronized(this) publication [read]. Not a regression: before it the property did not exist (no per-field doc-values type, no clear(), no registration in addIndexes(Directory...)).",
   "introduced_date": "2012-11-23 (author date of 041ff1140f3 on the feature branch); 2013-02-07 on trunk (a181dc07353), 2013-02-08 on branch_4x (5cbaddcbc7f)",
   "first_affected_version": "4.2.0 (2013-03-11) [exec]",
   "affected_versions": "every release from 4.2.0 through 10.6.0 and main 645d4fe14a20 [read]. Executed, all fail: main 645d4fe14a20 (-ea and -da), 10.6.0 (4ae946e5a9b), 10.5.2 and 9.12.3 with the claimed JUnit; 9.0.0 and 8.11.4 (import-only ports, -da); 7.7.3, 6.6.6 and 5.5.5 (core-only main() probe of a hunt unit, -ea); 4.2.0 and 4.10.4 (4.x port); 4.1.0 is not affected [exec]. Not fixed upstream [read]: upstream main e1faeba08bde (2026-11-02), branch_10_6 and branch_9_12 keep both lines; the last commit to IndexWriter.java on main is 169cbffd12f (#16581, author date 2026-09-21). The addIndexes(CodecReader...) overload fails the same way on main when deleteAll runs between its merge and its publication [exec]. Not new in 10.6.",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-9617",
    "https://github.com/apache/lucene/issues/6070",
    "https://issues.apache.org/jira/browse/LUCENE-5006",
    "https://github.com/apache/lucene/issues/9829",
    "https://issues.apache.org/jira/browse/LUCENE-8785",
    "https://github.com/apache/lucene/issues/10349"
   ],
   "doc": "",
   "repro": "repro/LFV-1074/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1137",
   "priority": "medium",
   "priority_rank": 107,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter deleteAll (IndexWriter-DocumentsWriter lock order)",
   "title": "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",
   "summary": "Three threads share one IndexWriter: one adds documents and its addDocument() flushes and publishes the new segment, one calls tryDeleteDocument() on an NRT reader (or addIndexes()), and one calls deleteAll(). You expect all three calls to return, because IndexWriter is documented as completely thread safe for concurrent calls of any of its methods. Instead they can deadlock for good: deleteAll() holds the DocumentsWriter monitor (in lockAndAbortAll) and waits for the flush-ticket purge lock, the publishing thread holds that purge lock and waits for the IndexWriter monitor (publishFlushedSegment), and tryDeleteDocument() (or addIndexes()) holds the IndexWriter monitor and waits for the DocumentsWriter monitor to get a sequence number (getNextSequenceNumber).",
   "impact_class": "hang",
   "introduced_commit": "18af6325ed98b50c23a1f026ab9d05f17039c731 (master, first released in 9.0.0) and its branch_8x copy 47ed21324c41d4414cd259ceaba15f5d45863ac6 (first released in 8.6.0), both 'LUCENE-9304: Fix IW#getMaxCompletedSequenceNumber() (#1427)' (s1monw; apache/lucene-solr#1427; JIRA LUCENE-9304 = apache/lucene#10344): to fix a sequence-number visibility race it made DocumentsWriter.getNextSequenceNumber synchronized and switched tryModifyDocument (behind tryDeleteDocument / tryUpdateDocValue) and both addIndexes methods to it, inside the IndexWriter monitor, which added the IndexWriter-monitor -> DocumentsWriter-monitor edge that closes the cycle [exec]. The other two edges are older [read]: DocumentsWriter monitor -> purge lock from 58105a203a19 (LUCENE-7868, 2017-06-21, first in 7.0.0), which added ticketQueue.forcePurge to the synchronized lockAndAbortAll; purge lock -> IndexWriter monitor by design since 4.0 (innerPurge publishes while holding the purge lock).",
   "introduced_date": "2020-04-14 (author date of 18af6325ed9 and 47ed21324c4)",
   "first_affected_version": "8.6.0 [exec]",
   "affected_versions": "Every release from 8.6.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT). Executed and deadlocked with the independent reproduction's one-test JUnit, an earlier and longer test of the same scenario as the minimal repro (for 8.x and 9.0.0 the same file with the pre-9.1 LuceneTestCase import): 8.6.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.6.0 and main (-ea, history runs), 10.5.2 (-ea, the independent reproduction), and main with -da (the independent reproduction, the adjudication and a separate re-run) [exec]; the minimal repro fails on main and on the 10.6.0, 10.5.2 and 9.12.3 release jars (-ea and -da) [exec]; the finder's test also deadlocks on main (-ea, -da), 10.6.0 and 9.12.3 [exec]; all three edges are present at every release tag from 8.6.0 to 8.8.1 and from 9.0.0 to 10.6.0 in the history clone [read]. Not affected: 8.0.0 and 8.5.2 [exec]; 7.0.0 to 8.5.2 take sequence numbers without the DocumentsWriter monitor [read]. Not new in 10.6. Not fixed upstream: upstream main 1c2072f0284 (2026-11-02) has no commit to DocumentsWriter.java or DocumentsWriterFlushQueue.java since 2026-10-01 [read].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/6070",
    "https://github.com/apache/lucene/issues/16571",
    "https://github.com/apache/lucene/issues/16847",
    "https://github.com/apache/lucene/issues/16948",
    "https://github.com/apache/lucene/issues/16810",
    "https://issues.apache.org/jira/browse/LUCENE-5006"
   ],
   "doc": "bugs/LFV-1137.html",
   "repro": "repro/LFV-1137/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-635",
   "priority": "medium",
   "priority_rank": 108,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter doc-values updates vs deleteAll (writer-wide field schema, FieldInfos.FieldNumbers)",
   "title": "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",
   "summary": "One thread calls deleteAll() on an IndexWriter while another thread updates a doc-values field with updateDocValues, updateNumericDocValue or softUpdateDocument. You expect the update either to be dropped with everything else (if it came first) or to apply to the documents indexed after deleteAll, as on a fresh writer. Instead, when the update checked its field before deleteAll cleared the writer's field schema and is queued just after, the writer can no longer commit, refresh or close (NullPointerException with assertions off, a tragic AssertionError with them on), and when a document added in between gives the field another doc-values type, the commit succeeds but writes a segment whose field cannot be read.",
   "impact_class": "data corruption",
   "introduced_commit": "1120e46961b242104410190b70d1f4e4e57d1a40 on trunk (LUCENE-5189 'add NumericDocValues updates', migrated as apache/lucene#6253; svn era, no GitHub PR), released through the branch_4x commit 49684b82701: updateNumericDocValue checks the field against globalFieldNumberMap and then queues the update, with nothing ordering the pair against deleteAll() [read]. Precondition: deleteAll() clears the writer-wide field numbers since LUCENE-4547 (5cbaddcbc7f, 4.2.0). The production symptom changed twice [exec]: LUCENE-9300 (b5c5ebe37cf and backports, 7.7.3 / 8.5.1 / 8.6.0) added the 'guaranteed to exist' assertion, so the missing-field form fails with assertions on; LUCENE-9334 (d03662c48bf, apache/lucene#11, 9.0.0) turned the missing-field form into a NullPointerException with assertions off and the type-conflict form into a silent wrong-type write that commits a broken segment. LUCENE-5680 (4.9.0) and LUCENE-8316 (7.4.0) widened the trigger (updateDocValues; new fields and soft updates)",
   "introduced_date": "2013-09-15 on trunk (1120e46961b); 2013-11-01 on branch_4x (49684b82701)",
   "first_affected_version": "4.6.0 [exec]; 4.5.1 is the last release without the bug (no doc-values update API: the repro does not compile). The worse production forms (NullPointerException on every commit for any racing update; a committed broken segment for the type-conflict form) start in 9.0.0 [exec]",
   "affected_versions": "every release from 4.6.0 through 10.5.2 and main a9779ef3c193 [exec]. Symptom by version: 4.6.0-8.11.x with assertions off only the type-conflict form fails (IllegalArgumentException on every commit and close until rollback; a merely missing field is silently re-created), with assertions on from 7.7.3 / 8.5.1 / 8.6.0 the missing-field form also fails (AssertionError on every commit); 9.0.0-main with assertions off the missing-field form throws NullPointerException on every commit, NRT reopen and close and the type-conflict form commits a broken segment, with assertions on an AssertionError (tragic from 10.0.0; on 9.x the writer stays open and every commit throws) [exec]. Not fixed upstream [read]: no commit after a9779ef3c193 up to upstream head a95c754ee003 touches IndexWriter.java, FieldInfos.java, ReadersAndUpdates.java or DocumentsWriter.java, and no open PR fixes it.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16810",
    "https://github.com/apache/lucene/issues/15338",
    "https://github.com/apache/lucene/issues/16578",
    "https://github.com/apache/lucene/issues/16872",
    "https://issues.apache.org/jira/browse/LUCENE-9617",
    "https://github.com/apache/lucene/issues/6070"
   ],
   "doc": "",
   "repro": "repro/LFV-635/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1090",
   "priority": "medium",
   "priority_rank": 109,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter delete queue (DocumentsWriterPerThread.finishDocuments, DeleteSlice failure handling)",
   "title": "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",
   "summary": "You add a document to an IndexWriter, then send a long run of doc-values updates (executed: 2.2 million updateNumericDocValue calls selected by one 1 KB term) and delete the buffered document; the next addDocument fails with ArithmeticException 'integer overflow' while the in-memory segment copies that backlog into its own buffer, and the writer stays open with no tragic exception. You expect either the writer to close itself or the next successful commit, whose sequence number is above the delete's, to reflect the delete. Instead the following addDocument finds no new deletes and resets the segment's delete slice past the operations the failed copy never reached, so the commit succeeds and the deleted document is still in the index.",
   "impact_class": "data corruption",
   "introduced_commit": "b88d3e19889f (main) and its branch_9x backport 445b30d421c7 (first released in 9.8.0), apache/lucene#12392 'Catch offset overflows in byte pool (#9660)' by stefanvodita: the exposing change, correct in itself. Its Math.addExact in ByteBlockPool.nextBuffer turns the 2 GiB overflow of this workload into a non-tragic ArithmeticException thrown inside the per-thread DeleteSlice.apply that finishDocuments calls [exec]. The handling defect itself is older [read]: DeleteSlice.apply resets only after every node succeeds since e95097a7c8d (LUCENE-2956 'Support updateDocument() with DWPTs', 2011-04-13, release 4.0.0), and finishDocument resets the slice when no new deletes arrived ('if we don't need to apply we must reset!') since 75ab79f0aa3 (LUCENE-5006, 2013-08-19, release 4.5.0); the current seqNo-based form comes from 76fb616bdf5 (2016-06-01) and bdb40fb1640 (#1350, 2020-03-17)",
   "introduced_date": "2023-06-28 (author date of b88d3e19889f and 445b30d421c7, the exposing change); the handling defect 2011-04-13 (e95097a7c8d) and 2013-08-19 (75ab79f0aa3)",
   "first_affected_version": "9.8.0 [exec]; the handling defect is latent from 4.5.0 through 9.7.0, with no legal-input, non-tragic exception out of DeleteSlice.apply known to us there [read]",
   "affected_versions": "[exec] the claimed JUnit fails on main e1faeba08bde (-ea and -da), 10.6.0 (released 2026-10-29, 4ae946e5a9b; -ea and -da), 10.5.2, 9.12.3, 9.9.0 and 9.8.0 (-da), always 'delete seqNo=2200002 must be in commit seqNo=2200005 ... expected:<0> but was:<1>'; the independent reproducer's own JUnit fails on main (-ea, -da), 10.6.0, 10.5.2, 9.12.3 and 9.8.0 (-da); 9.7.0 passes (-da: the writer closes itself). The second trigger (75,000 deletes of distinct 30,000-byte terms, 8 GB heap) fails on main (-ea, -da), 10.6.0, 10.5.2 and 9.9.0 and passes on 9.8.0 (#12573 moved the per-thread delete terms into a ByteBlockPool in 9.9.0). [read] every release tag from 9.8.0 to 10.6.0 has Math.addExact in ByteBlockPool.nextBuffer, the reset() in finishDocuments' no-new-deletes branch and a DeleteSlice.apply without failure handling. Not new in 10.6. Not fixed upstream: no commit on main (254ce48660d), branch_11x or branch_10_6 changes finishDocuments or DeleteSlice since 2026-09-01 (author dates checked), and no open PR changes those lines (2026-11-02)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16847",
    "https://github.com/apache/lucene/issues/16867",
    "https://github.com/apache/lucene/issues/9738",
    "https://github.com/apache/lucene/issues/15152",
    "https://github.com/apache/lucene/issues/15330",
    "https://github.com/apache/lucene/issues/14261"
   ],
   "doc": "",
   "repro": "repro/LFV-1090/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-842",
   "priority": "medium",
   "priority_rank": 110,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter merge registration (registerMerge, pendingMerges, mergingSegments)",
   "title": "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)",
   "summary": "You enable IndexWriter's InfoStream, and the logging call throws once (an exception from the logging backend, or an OutOfMemoryError) while forceMergeDeletes() registers its merge; forceMergeDeletes rethrows and the writer stays open, so you expect the index to stay as it was: a following forceMerge(1) and commit should leave the same 10 live documents. But registerMerge had already queued the merge and had not yet marked its segments as merging, so forceMerge(1) selects the same segments again, both merges run, and with -da the committed index holds 16 live documents with id:1 twice. With -ea the next merge fails 'assert merge.registerDone' in IndexWriter._mergeInit instead.",
   "impact_class": "data corruption",
   "introduced_commit": "299d6357dd296f87a099fadd0764292b28dbde47 (LUCENE-845, LUCENE-847, LUCENE-870 'factor MergePolicy & MergeScheduler out of IndexWriter ...', author Michael McCandless, svn r576798; no PR, pre-GitHub): it created registerMerge, pendingMerges, mergingSegments and OneMerge.registerDone in the order still on main (pendingMerges.add, then the 'add merge to pendingMerges' message, then mergingSegments.add, then registerDone = true) [read]. The duplicated-documents outcome came with LUCENE-1076 and LUCENE-2918 (branch_3x 91e03a1a15f and 84e182a3e05; trunk 295c8f84c73 and 07aca888bad), which replaced and then removed the commit-time contiguity check that had rejected the second merge with MergeException [read]; which of the two flipped the outcome is from code reading (no 2011-era intermediate build)",
   "introduced_date": "2007-09-18 (author and commit date of 299d6357dd2: the half-registration window, first released in 2.3.0); 2011-05-05 on branch_3x (author dates of 91e03a1a15f and 84e182a3e05) and 2011-01-29 / 2011-02-17 on trunk (295c8f84c73, 07aca888bad): the duplicated-documents consequence, first released in 3.2.0",
   "first_affected_version": "2.3.0 for the half-registered merge [exec]; 3.2.0 for the data-corrupting form [exec]. 2.2.0 is not affected (no registerMerge) [exec]",
   "affected_versions": "main a9779ef3c193 [exec]; duplicated documents with -da on 3.2.0, 3.6.2, 4.0.0, 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0 and 10.5.2 [exec]; the 'assert merge.registerDone' failure with -ea on 3.2.0, 4.0.0, 9.12.3, 10.5.2 and main [exec]; 2.3.0 to 3.1.0 have the half-registered merge but the follow-up merge is rejected with MergeException (no wrong data) [exec]; releases in between that were not run have the same registerMerge statement order [read]; branch_10x head 1309534296e and branch_10_6 head 2763db11b0a have the same order (IndexWriter.java is unchanged from 2763db11b0a to the 10.6.0 commit 4ae946e5a9b, so 10.6.0 has it by reading) and upstream main 20ced71c1e6 has no IndexWriter.java change after a9779ef3c193 [read]. With the default ConcurrentMergeScheduler on main -da: duplicates in 5 of 20 and 2 of 10 (finder's CMS repro re-run by the independent reproduction) iterations, otherwise a NullPointerException ('rld is null') that closes the writer tragically [exec]. All runs on aarch64 with JDK 25 (6.0.0 needs --add-opens java.base/java.nio on JDK 25, unrelated)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9738",
    "https://issues.apache.org/jira/browse/LUCENE-8692",
    "https://github.com/apache/lucene/issues/15761",
    "https://github.com/apache/lucene/issues/16226",
    "https://github.com/apache/lucene/issues/2628",
    "https://issues.apache.org/jira/browse/LUCENE-1554"
   ],
   "doc": "",
   "repro": "repro/LFV-842/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1082",
   "priority": "medium",
   "priority_rank": 111,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter flush publishing (IndexWriter.publishFlushedSegments, IndexWriter.publishFlushedSegment, DocumentsWriterFlushQueue.innerPurge)",
   "title": "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)",
   "summary": "You enable IndexWriter's InfoStream, add a document and commit, and the logging call for one of the 'publish' lines of that commit throws an unchecked exception (executed: a java.util.logging Handler behind Lucene's JavaLoggingInfoStream that fails once); commit() throws, and the writer stays open with no tragic exception. You expect either the writer to close itself, as it does when the segment flush itself fails or a published delete packet fails to apply, or the next successful commit to contain every operation its returned sequence number covers. Instead the segment was already fully written and its flush ticket is removed from the queue whether or not it was published, so the segment never joins the index: the retried commit returns seqNo 5, above the addDocument's seqNo 2, yet the committed index has 0 documents.",
   "impact_class": "data corruption",
   "introduced_commit": "e95097a7c8df (LUCENE-2956 'Support updateDocument() with DWPTs', realtime_search branch; landed on trunk by 2a969f828c1, LUCENE-3023): the new DWPT flush-ticket queue removed the head ticket before publishing it [read]; reshaped without changing the outcome by LUCENE-3692 (ed4894dd8fb: innerPurge's try { publish } finally { queue.poll() }) and LUCENE-8271 (d32ce909241: the publish moved into the IndexWriter.publishFlushedSegments consumer with ticket.markPublished()); no PR (svn-era commits; GitHub #4030, #4097, #4766, #9318)",
   "introduced_date": "2011-04-13 (author date of e95097a7c8df; trunk landing 2a969f828c1 authored 2011-05-01; reshaped 2012-01-16 and 2018-04-24)",
   "first_affected_version": "4.0.0 [exec] (4.0.0-alpha and -beta contain the introducing commits by tag check but were not executed); 3.1.0-3.6.2 lose the document the same way through an older, analogous window at a different fix site (DocumentsWriter.flush's 'flush time' log line before IndexWriter.doFlush adds the segment) [exec]; since 5.0.0 (LUCENE-5987, which made a failed segment flush tragic) the loss goes against Lucene's own rule that silent-loss failures close the writer",
   "affected_versions": "[exec] fails on 4.0.0, 4.10.4, 5.0.0, 7.3.1, 7.4.0, 8.11.4 and 9.0.0 (main() ports of the JUnit scenario, each with a passing no-throw control), 9.1.0, 9.12.3, 10.5.2 and 10.6.0 (released 2026-10-29, 4ae946e5a9b; release jars) with -da, and main e1faeba08bde with -ea and -da (the JUnit; the independent reproducer's own JUnit also fails on main -ea/-da, 10.6.0, 10.5.2 and 9.12.3); [read] every 4.x-10.x release in between (the same unconditional poll in innerPurge); the analogous older window in 3.1.0-3.6.2 [exec]. Not new in 10.6. Not fixed upstream: upstream main HEAD is still e1faeba08bd (checked 2026-11-02), the last commits to DocumentsWriterFlushQueue.java (b85f030c6cc, #15134, 2025-10-09) and IndexWriter.java (169cbffd12f, #16581, 2026-09-21) do not change the publish failure handling, and no open PR touches it",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9738",
    "https://issues.apache.org/jira/browse/LUCENE-8692",
    "https://github.com/apache/lucene/issues/9091",
    "https://issues.apache.org/jira/browse/LUCENE-8043",
    "https://github.com/apache/lucene/issues/6438",
    "https://issues.apache.org/jira/browse/LUCENE-5374"
   ],
   "doc": "",
   "repro": "repro/LFV-1082/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1083",
   "priority": "medium",
   "priority_rank": 112,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter commit failure handling (IndexWriter.startCommit, prepareCommitInternal and rollback; IndexFileDeleter reference counts)",
   "title": "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",
   "summary": "You enable an InfoStream on an IndexWriter, commit one document, add a second one and call commit() again, and the InfoStream throws a RuntimeException on the 'done all syncs' message that Lucene logs after it has written and fsynced pending_segments_2; commit() fails without closing the writer, so you call rollback(), whose javadoc says the index will then be as it was when commit() was last called. Instead, startCommit has kept the half-finished commit as its pending commit while prepareCommitInternal's catch has already released that commit's file references, and rollback() releases them a second time, so the file deleter removes _0.cfe, _0.cfs and _0.si, which segments_1 still needs. DirectoryReader.open(dir) then fails with CorruptSegmentInfoException (NoSuchFileException _0.si), close() with commitOnClose=false does the same, and with -ea rollback() throws AssertionError 'RefCount is 0 pre-decrement' instead.",
   "impact_class": "index unusable",
   "introduced_commit": "60e2a6c89b944e48b7c157b2729a186d2017ba9f (branch_4x, svn r1580557, first released in 4.8.0; the same change on trunk is ef3973c58900c03f765ae8581c4e2dde149339b5, svn r1580540), LUCENE-5543 'Remove Directory.fileExists' (migrated as apache/lucene#6606; svn era, no pull request; author mikemccand). Besides its topic it moved the startCommit(toCommit) call in prepareCommitInternal into the try block whose failure path releases filesToCommit (guarded by 'if (filesToCommit != null)'); startCommit nulls filesToCommit only when it fails before pendingCommitSet = true, so a failure after that point is now released there and again by rollback() [exec]. The window itself is older and was harmless before: the 'done all syncs' message after pendingCommitSet = true has its current form since LUCENE-4055 (2012) and rollback() has released pendingCommit since at least LUCENE-1347 (2008), so 4.7.2 released the references once [read]. Later rewrites kept the shape: LUCENE-5919 (2014), sequence numbers (2016), LUCENE-8217 (2018), LUCENE-8962 (2020) [read]",
   "introduced_date": "2014-03-23 (author date of 60e2a6c89b9 on branch_4x, 2014-03-23T18:03:55Z; trunk ef3973c5890, 2014-03-23T17:05:36Z)",
   "first_affected_version": "4.8.0 [exec]; last unaffected release 4.7.2 [exec]",
   "affected_versions": "every release from 4.8.0 to 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main e1faeba08bde (unreleased 12.0.0-SNAPSHOT). [exec] the independent reproducer's JUnit TestRollbackAfterFailedCommitKeepsLastCommit fails on main with -ea and -da (run by the independent reproduction, the adjudication, the version-history check and the registration check), on 10.6.0 (-da, version-history check, released Maven jars whose core carries 4ae946e5a9b), 10.5.2 and 9.12.3 (-da, the independent reproduction); the finder's JUnit fails on main (-ea, -da), 10.6.0, 10.5.2 and 9.12.3 (-da); version-port main() probes fail on 4.8.0 (-ea and -da), 4.10.4, 5.0.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.6.0 and main (-da) and pass on 4.7.2 (-ea and -da). [read] every release tag from 4.8.0 to 5.5.5 contains 60e2a6c89b9 and every one from 6.0.0 to 10.6.0 contains ef3973c5890 (git tag --contains). Not new in 10.6. Not fixed upstream: upstream main e1faeba08bd (2026-11-02) has the same startCommit, prepareCommitInternal and rollbackInternalNoCommit code; the newest upstream commit to IndexWriter.java is 169cbffd12f (2026-09-21), already in e1faeba; none of the 410 open apache/lucene PRs changes this path",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9738",
    "https://issues.apache.org/jira/browse/LUCENE-8692",
    "https://github.com/apache/lucene/issues/6981",
    "https://issues.apache.org/jira/browse/LUCENE-5919",
    "https://github.com/apache/lucene/issues/7020",
    "https://issues.apache.org/jira/browse/LUCENE-5958"
   ],
   "doc": "",
   "repro": "repro/LFV-1083/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-013",
   "priority": "medium",
   "priority_rank": 113,
   "novelty": "new",
   "withheld": false,
   "area": "index / doc-values updates",
   "title": "Concurrent doc-values updates can make a merge throw NullPointerException and close the writer",
   "summary": "You update a doc-values field that is new to a segment while that segment is being merged. You expect the merge to finish. Instead writeFieldUpdates records the not-yet-applicable field as NUMERIC with dvGen=-1, the merge throws NullPointerException in DocIDMerger, and the IndexWriter closes tragically.",
   "impact_class": "crash",
   "introduced_commit": "LUCENE-7868 (58105a203a19)",
   "introduced_date": "2017-06-21",
   "first_affected_version": "7.0.0",
   "affected_versions": "every release run from 7.0.0 to 10.5.2, and main [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-013.html",
   "repro": "repro/LFV-013/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-652",
   "priority": "medium",
   "priority_rank": 114,
   "novelty": "new",
   "withheld": false,
   "area": "core / index (ParallelLeafReader stored fields x StoredFieldsWriter.MergeVisitor, on addIndexes and wrapForMerge copies)",
   "title": "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",
   "summary": "You build two indexes in lockstep, as ParallelLeafReader requires (index A stores title='Lucene in Action', index B stores price='42'), wrap them in a ParallelLeafReader, which itself returns both fields correctly, and copy it into a new index with IndexWriter.addIndexes(SlowCodecReaderWrapper.wrap(reader)), expecting the copy to hold title and price. Instead the copy holds title='Lucene in Action' and title='42' and no price field, with no error and a clean CheckIndex: storedFields() lets B report price with B's own field number 0, the parallel reader's getFieldInfos() numbers price 1, and because the target's merged numbers equal the parallel reader's, the stored-fields merge skips its remap-by-name step and writes the value under number 0, which is title. A merge whose OneMerge.wrapForMerge adds a parallel index with stored fields behind each segment goes wrong the same way (a 'summary' value stored as a second 'id').",
   "impact_class": "data corruption",
   "introduced_commit": "d249f8bc3378d7a349a78fd53ae6e86c695475a5 (LUCENE-6133 'improve default stored fields merge algorithm', migrated as GitHub issue #7195, svn r1648327, by Robert Muir; SVN/JIRA era, no PR; a performance change) on trunk, and its same-day branch_5x backport 52b13f1946b582d5ff7edc718e38f3198260058b (svn r1648332), which the released 5.x builds contain: it replaced the by-name stored-fields merge (DocumentStoredFieldVisitor plus fieldInfos.fieldInfo(field.name())) with StoredFieldsWriter.MergeVisitor and its 'if field numbers are aligned, we can save hash lookups' shortcut [exec]. The reader side (FieldInfos.Builder renumbering in getFieldInfos(), the visitor passed unchanged to each sub-reader) dates from ParallelAtomicReader (LUCENE-3736, 2012) and was harmless while the merge matched fields by name; the only later edit to the shortcut lines is the behaviour-preserving #12116 (2023)",
   "introduced_date": "2014-12-29",
   "first_affected_version": "5.0.0 [exec]; 4.10.3 and 4.10.4 copy correctly [exec] and no 4.x release tag contains either commit [git]",
   "affected_versions": "Every release from 5.0.0 through 10.6.0 (10.6.0 run at its RC1 revision 4ae946e5a9b) and main a9779ef3c193 and 645d4fe14a2 [exec]; never fixed. [exec] follow-up history runs: 5.0.0, 5.1.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0 and 9.12.3 fail the version-independent main() repro (copy = title twice, no price), the finder's JUnit fails 2 of 2 on 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da), and the finder also ran 9.4.2 (fails); the independent reproduction's JUnit fails 2 of 3 on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check re-ran the finder's repro on main and 10.5.2; not affected: 4.10.3 and 4.10.4 (a ParallelAtomicReader variant of the repro passes) and the parents of the introducing commits on trunk and branch_5x. [read] the 15 5.x tags contain the branch_5x commit and the 83 tags 6.0.0 to 10.5.2 contain the trunk commit; entry points: addIndexes(CodecReader...) with SlowCodecReaderWrapper since 5.0.0 (LUCENE-6165), OneMerge.wrapForMerge since 6.2.0 (LUCENE-6766, executed on 9.12.3, 10.0.0, 10.5.2 and main); no later commit to ParallelLeafReader.java, StoredFieldsWriter.java or SlowCodecReaderWrapper.java on upstream main through 645d4fe14a2 (2026-10-29) and no open PR changes the relevant code; 10.6.0 (released 2026-10-29; branch_10_6 RC1 4ae946e5a9b) [exec] and branch_10x 657014b3c579 [read]. JDK 25.0.3, aarch64; pure Java logic.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-652.html",
   "repro": "repro/LFV-652/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-018",
   "priority": "medium",
   "priority_rank": 115,
   "novelty": "new",
   "withheld": false,
   "area": "index / readers",
   "title": "ParallelLeafReader.termVectors() no longer honours 'the first reader having the field wins'",
   "summary": "You wrap several readers in a ParallelLeafReader where more than one has term vectors for the same field. You expect term vectors from the first reader that has the field, as documented. Instead, since #14373, they come from the wrong reader, and an index written from it with addIndexes fails CheckIndex.",
   "impact_class": "data corruption",
   "introduced_commit": "#14373 (9272d4d29a1)",
   "introduced_date": "2025-03-24",
   "first_affected_version": "10.2.0",
   "affected_versions": "10.2.0-10.5.2 and main [exec]; 10.6.0 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-018.html",
   "repro": "repro/LFV-018/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-233",
   "priority": "medium",
   "priority_rank": 116,
   "novelty": "known",
   "withheld": false,
   "area": "analysis / SegmentingTokenizerBase buffer refill (smartcn HMMChineseTokenizer and SmartChineseAnalyzer; ThaiTokenizer and ThaiAnalyzer)",
   "title": "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",
   "summary": "You index a Chinese paragraph of more than 1024 chars with no line break through the stock SmartChineseAnalyzer, and it contains an emoji or a rare ideograph such as U+20000; you expect that character to be searchable wherever it falls, as it is one position earlier or later. Instead, when its first UTF-16 half is the last char of the tokenizer's 1024-char buffer, SegmentingTokenizerBase cuts the pair in two: smartcn emits the halves U+D840 and U+DC00 as two terms, which the index stores as U+FFFD, and ThaiTokenizer drops the character. A TermQuery for U+20000 then finds 0 documents instead of 1, with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "6e2f6a69eb0adbefe90798b178e51539ab81aeca (trunk, svn r1579846; LUCENE-4984 / GitHub #6048 'Fix ThaiWordFilter, smartcn WordTokenFilter', patch by rmuir, +1 from rjernst and s1monw; pre-GitHub, no PR) and its branch_4x backport 72a0e1d09e421b3cb76dbadd743ec9449ad701d8 (svn r1579855), which shipped in 4.8.0. The commit restored SegmentingTokenizerBase, with refill()'s no-safe-end fallback 'if (usableLength < 0) usableLength = length;', from the unreleased 2012 Kuromoji version (LUCENE-3305 / #4378, cd372bdc838; removed before any release by LUCENE-3889 / #4962), added ThaiTokenizer and HMMChineseTokenizer on top of it and switched ThaiAnalyzer and SmartChineseAnalyzer to them [read]",
   "introduced_date": "2014-03-21 (trunk commit and branch_4x backport); the same fallback first existed on 2012-01-12 in the unreleased Kuromoji base class (LUCENE-3305) and was removed on 2012-03-20, before any release",
   "first_affected_version": "4.8.0 [exec] (4.7.2, the last release before, has neither SegmentingTokenizerBase nor the two tokenizers [exec]; through smartcn the boundary-only split is visible from 7.4.0 on, because 4.8.0-7.3.1 split every supplementary character wherever it appeared (LUCENE-8325) [exec])",
   "affected_versions": "every release from 4.8.0 to 10.5.2 (the last release before 10.6.0), 10.6.0 (by reading: SegmentingTokenizerBase.java is the same as on main, see the #16727 note below) and main ea57360912ed (unreleased 11.0): a public-API main() probe affected on 4.8.0, 4.8.1, 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.3.1, 7.4.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main with -ea and -da [exec]; the finder's JUnit fails 3 of 4 on main, 10.5.2 and 9.12.3 [exec]; the other 90 release tags in that range have a token-identical refill() [read]. ThaiTokenizer and ThaiAnalyzer drop the character at the boundary from 4.8.0 on; HMMChineseTokenizer and SmartChineseAnalyzer show a boundary-only split from 7.4.0 on (in 4.8.0-7.3.1 the older LUCENE-8325 defect split every supplementary character and masks this one) [exec]. Not affected: 4.7.2 and earlier [exec]. Not fixed upstream: no commit on main or branch_10x touches SegmentingTokenizerBase.java after #16727, and none of the 413 open PRs touches it [read]. The bufferSize constructors from #16727 (main, branch_10x and 10.6.0, released 2026-10-29) let ThaiTokenizer users move the cut much closer and accept bufferSize = 1, which cannot hold a pair at all (main and 10.6 only). OpenNLPTokenizer extends the same class (since 7.3.0) but was not executed (it needs model files).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/8559",
    "https://issues.apache.org/jira/browse/LUCENE-7508",
    "https://github.com/apache/lucene/issues/10153",
    "https://issues.apache.org/jira/browse/LUCENE-9112",
    "https://github.com/apache/lucene/issues/16727",
    "https://issues.apache.org/jira/browse/LUCENE-8325"
   ],
   "doc": "",
   "repro": "repro/LFV-233/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-707",
   "priority": "medium",
   "priority_rank": 117,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-smartcn / HHMM segmenter character classes (Utility.getCharType -> HHMMSegmenter DELIMITER token -> SegTokenFilter ',' -> default stop list; SmartChineseAnalyzer and HMMChineseTokenizer)",
   "title": "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",
   "summary": "You index Chinese text with the stock SmartChineseAnalyzer, whose javadoc says its default stop list is 'simply a list of punctuation', so you expect only punctuation to disappear. Instead Utility.getCharType returns DELIMITER for four whole code-unit ranges (0x0021-0x00BB, 0x2010-0x2642, 0x3001-0x301E, 0xFE30-0xFF63) that also hold 248 letters and letter-numbers, among them U+3007 〇 and the Roman numerals Ⅰ-Ⅻ; each one becomes ',' and the stop list removes it. So 二〇〇八年 ('2008') analyzes to [二, 八, 年], 第Ⅲ章 and 第Ⅳ章 ('chapter III', 'chapter IV') give the same terms and positions, and the phrase query for 第Ⅲ章 matches both documents (2 hits, 1 expected), with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "e01aad89fe24f2482eb2e8c0e39f8272704abe80 (LUCENE-1629 'contrib intelligent Analyzer for Chinese', GitHub #2703: the original SmartChineseAnalyzer contribution, a JIRA patch committed by mikemccand as svn r774718; no GitHub PR exists) [read]. The four DELIMITER ranges, HHMMSegmenter's DELIMITER token, SegTokenFilter's ',' and the punctuation stop list all arrive in it; the original comment over the ranges reads (translated) 'the other ones at the front are all punctuation marks'. Not a regression: the later commits on getCharType (5265dc1bb20 LUCENE-1722 comment translation, 55858d7ba72 LUCENE-8325 surrogate check in 7.4.0, 7f8b7ffbcad LUCENE-9570 reformatting) left the ranges unchanged",
   "introduced_date": "2009-05-14 (first release 2.9.0)",
   "first_affected_version": "2.9.0 [exec] (the first release with the org.apache.lucene.analysis.cn.smart package; 2.4.1, the release before, has no such package [exec], so no release ever shipped an unaffected SmartChineseAnalyzer)",
   "affected_versions": "Every release from 2.9.0 to 10.5.2, 10.6.0 (by reading), and main a9779ef3c193; not fixed. [exec] a version-portable driver reports the bug with identical term lists on 24 releases (2.9.0, 2.9.4, 3.0.0, 3.0.3, 3.1.0, 3.6.2, 4.0.0, 4.7.2, 4.8.0, 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.3.1, 7.4.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2) and on main, with -ea and (9.12.3, 10.5.2, main) -da, its controls hold everywhere, and it reports the bug absent on main with the fix shadowed; the behaviour is the same on both sides of the two later boundaries 4.7.2/4.8.0 (LUCENE-4984, HMMChineseTokenizer) and 7.3.1/7.4.0 (LUCENE-8325); the finder's JUnit fails 3 of 3 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (it cannot compile on 9.0.0, which predates org.apache.lucene.tests); the independent reproduction's test fails 5 of 6 on 10.5.2, 9.12.3 and main (-ea and -da). [read] the ranges are unchanged since e01aad89fe2; branch_10_6, branch_10x and upstream main a95c754ee00 have the same getCharType (read 2026-10-27).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/2802",
    "https://issues.apache.org/jira/browse/LUCENE-1728",
    "https://github.com/apache/lucene/issues/6626",
    "https://issues.apache.org/jira/browse/LUCENE-5564",
    "https://github.com/apache/lucene/issues/3098",
    "https://issues.apache.org/jira/browse/LUCENE-2023"
   ],
   "doc": "",
   "repro": "repro/LFV-707/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-557",
   "priority": "medium",
   "priority_rank": 118,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-morfologik / language analyzers (UkrainianMorfologikAnalyzer normalization: Analyzer#normalize and initReaderForNormalization, used by the query parsers for multi-term queries)",
   "title": "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",
   "summary": "You index Ukrainian text with UkrainianMorfologikAnalyzer, which maps typographic apostrophes to ', removes stress marks and soft hyphens, maps ґ to г and lower-cases every token before lemmatizing, so the document 'м’ясо Lucene' is stored as the terms м'ясо and lucene. A prefix, wildcard, regexp, range or fuzzy query built by a query parser sends its term through Analyzer.normalize, documented to return 'the representation that it would have in the index', but this analyzer overrides neither normalize(String, TokenStream) nor initReaderForNormalization, so normalize returns the text unchanged. As a result 'м’яс*', 'Luc*', 'Luce?e' and '[Lucene TO Lucene]' find nothing while \"м'яс*\" and 'luc*' find the document, and normalize(\"Lucene\") returns 'Lucene' although the index holds 'lucene'.",
   "impact_class": "silent wrong results",
   "introduced_commit": "7c2e7a0fb80a5bf733cf710aee6cbf01d02629eb on branch_6x (first released in 6.2.0) and its master twin e92a38af90d12e51390b4307ccbe0c24ac7b6b4e (first released in 7.0.0): LUCENE-7355 'Add Analyzer#normalize() and use it in query parsers' (GitHub issue apache/lucene#8409, JIRA patch, no PR), which created Analyzer#normalize, normalize(String, TokenStream) and initReaderForNormalization and added overrides to 42 stock analyzers but not to UkrainianMorfologikAnalyzer, which the parent of both commits already contains [read]. The analyzer came one week earlier with LUCENE-7287 (6ef174f5273 on master / 4a71e03a32f on branch_6x, 2016-06-21, apache/lucene#8342), with the MappingCharFilter in initReader and the LowerCaseFilter from the start. The master commit also removed the parsers' lowercaseExpandedTerms (MIGRATE.txt), which exposed the case half in the classic parser from 7.0.0; LUCENE-7785 (2017-04-19) and LUCENE-7841 (effd3766e7f, 2017-05-25) later widened the map in initReader only",
   "introduced_date": "2016-06-28 (LUCENE-7355, both branches; the analyzer itself 2016-06-21)",
   "first_affected_version": "6.2.0 [exec] (Analyzer.normalize and the simple parser's prefix query fail; with the back-ported two-method fix they pass on 6.2.0 and 6.6.6); the classic-parser case symptom and the ґ symptom start in 7.0.0 [exec] (6.x classic parsers lower-cased expanded terms themselves, and the ґ mapping first shipped in 7.0.0); 6.1.0 has neither the class nor Analyzer.normalize [exec]",
   "affected_versions": "Every release 6.2.0 to 10.5.2 and main ea57360912ed. [exec] the follow-up's portable history probe (-ea, seed DEADBEEF) on 6.2.0, 6.6.6, 7.0.0, 8.11.4, 9.12.3, 10.5.2 and main, every control passing; the finder's JUnit (2 of 2 fail) on main (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit (3 of 4 fail, its control passes) on main (-ea and -da), 10.5.2 and 9.12.3, and the independent reproduction's cross-version runs on 6.2.0, 6.6.6, 7.0.0 and 8.11.4; the fix back-ported to 7.0.0 makes every bug group pass, and back-ported to 6.2.0 and 6.6.6 the normalize and simple-parser groups. [read] the other 75 release tags 6.2.1 to 10.5.1 in the history clone (the file lower-cases and char-maps and has no normalization override); 8.8.2 to 8.11.3 inferred (not tagged in the history clone, between 8.8.1 [read] and 8.11.4 [exec]). In 6.x the classic parser's apostrophe miss is a limitation of the 6.x parser (the fix does not change it there), not this bug. Upstream apache/lucene main ffa9d816eeb4 (2026-10-26) is unchanged [read]. Not affected: 6.1.0 (API absent) [exec]. Not executed: x86",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-557.html",
   "repro": "repro/LFV-557/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-534",
   "priority": "medium",
   "priority_rank": 119,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / language analyzers (SerbianAnalyzer.normalize, used by the query parsers for multi-term queries)",
   "title": "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",
   "summary": "You index Serbian text with SerbianAnalyzer, which lower-cases, stems and then maps Cyrillic to Latin and removes diacritics (SerbianNormalizationFilter), so 'Београд' is stored as 'beograd' and 'Čačak' as 'cack', and you search with a prefix, wildcard, fuzzy, regexp or range query through a query parser, which passes the term through Analyzer.normalize, documented to give 'the representation that it would have in the index'. SerbianAnalyzer.normalize only lower-cases, so 'Беогр*' becomes the prefix 'беогр' and 'Čač*' becomes 'čač', and both find nothing while 'Beogr*' and 'Cac*' find the documents. Directly, normalize(\"Ђак\") returns 'ђак' while the index holds 'djak', even with stemming switched off.",
   "impact_class": "silent wrong results",
   "introduced_commit": "c7029b12541d908e9c86f1f9946a3369aea5236a (LUCENE-9313, GitHub issue apache/lucene#10353 'Analyzer for Serbian language based on Snowball stemmer'; committed by rmuir on 2020-08-26 from the contributor's JIRA patch LUCENE-9313.patch, no PR) [read]. Not a regression: no later commit changed normalize(); the Analyzer#normalize contract (LUCENE-7355, 6.2.0) and the factory's normalize() -> create() (LUCENE-8497, 8.0.0) predate it",
   "introduced_date": "2020-08-26",
   "first_affected_version": "9.0.0 [exec] (the first release that contains SerbianAnalyzer; the class javadoc's '@since 8.6' is wrong: 8.6.3 and 8.11.4 do not have the class [exec], and 54a5dc2e6e3 moved the CHANGES entry to 9.0)",
   "affected_versions": "main ea57360912ed (-ea and -da), 10.5.2, 10.0.0, 9.12.3, 9.1.0 and 9.0.0 [exec]; the other 28 release tags 9.2.0 to 10.5.1 [read]; not affected: 8.x (API absent; 8.6.3 and 8.11.4 [exec]); upstream apache/lucene main unchanged [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-534.html",
   "repro": "repro/LFV-534/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1063",
   "priority": "medium",
   "priority_rank": 120,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / CustomAnalyzer conditional blocks (ConditionalTokenFilterFactory, ProtectedTermFilterFactory) and Analyzer.normalize, which the query parsers use for multi-term queries",
   "title": "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",
   "summary": "You build a CustomAnalyzer whose lowercase filter sits inside a conditional block (withTokenizer(\"whitespace\").whenTerm(t -> t.length() > 2).addTokenFilter(\"lowercase\").endwhen(), or a ProtectedTermFilterFactory wrapping lowercase as in that factory's javadoc), index 'Lucene' (stored as the term 'lucene') and search with the classic QueryParser range [Lucene TO Lucene]. You expect Analyzer.normalize(\"f\", \"Lucene\") to return 'lucene', 'the representation that it would have in the index', and the query to find the document, as both do for the same chain without the condition. Instead normalize returns 'Lucene' unchanged and the query finds 0 documents with no error, and Apa*, Apach?, APACHE~1 and /Apa.*/ miss 'Apache' the same way, because ConditionalTokenFilterFactory overrides create() but not normalize(), so CustomAnalyzer.normalize never reaches the normalize() of the wrapped filters.",
   "impact_class": "silent wrong results",
   "introduced_commit": "7f13e5642924aa7f97e21b059553cfd6b5b56c21 (branch_7x, first released in 7.4.0) and its master twin 1ce3ebadbd60d4485145c71b48330d0aabde77ad (first released in 8.0.0), both 'LUCENE-8273: Add ConditionalTokenFilter', author romseygeek, author date 2018-05-11 (JIRA patch workflow, migrated as apache/lucene#9320, no PR) [read]. In 7.x CustomAnalyzer.normalize applied only MultiTermAwareComponent factories and ConditionalTokenFilterFactory was not one; LUCENE-8497 (65486442c4a, 2018-11-19, apache/lucene#9543, 8.0.0) replaced that with TokenFilterFactory.normalize(), whose default is the identity, and added no override here, so the outcome stayed the same. ProtectedTermFilterFactory (renamed from TermExclusionFilterFactory in 97490ac7c66 / d91273ddf0b, 2018-05-20, also LUCENE-8273) shipped in the same release",
   "introduced_date": "2018-05-11",
   "first_affected_version": "7.4.0 [exec]; 7.3.1 and earlier are not affected [exec]",
   "affected_versions": "every release from 7.4.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 645d4fe14a20; never fixed (upstream main 716d6f216f52 has no change at the fix site). [exec] the JUnit repro (seed DEADBEEF) fails 1 of 1 on main (-ea and -da), 10.6.0 (-ea and -da, SHA-1-verified release jars), 10.5.2, 10.0.0 and 9.12.3 (-da); the main() form fails on 7.4.0, 7.7.3, 8.0.0, 8.11.4 and 9.0.0 (the JUnit cannot compile on 9.0.0, which has no org.apache.lucene.tests.util); the independent reproduction's own JUnit fails on main (-ea and -da), 10.6.0, 10.5.2 and 9.12.3. [read] the fix-site code has no functional change between these releases (reformatting, SPI-name, package-split, @since and instanceof-pattern commits only). Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1063.html",
   "repro": "repro/LFV-1063/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1053",
   "priority": "medium",
   "priority_rank": 121,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-icu / collation (ICUCollationKeyAnalyzer vs Analyzer#normalize; classic QueryParser range bounds)",
   "title": "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",
   "summary": "You index the values a, b, c, d and e in a TextField analyzed with new ICUCollationKeyAnalyzer(Collator.getInstance(ULocale.ROOT)) and parse \"[b TO d]\" with the classic QueryParser on the same analyzer; you expect the 3 documents b, c and d, which is what the java.text twin CollationKeyAnalyzer gives. You get 0: the parser builds both range bounds with Analyzer.normalize, which takes its term attribute from attributeFactory(fieldName), and ICUCollationKeyAnalyzer gives its collation attribute factory only to its KeywordTokenizer and does not override attributeFactory, so normalize(\"b\") is the UTF-8 byte [62] while the index holds the ICU collation key [2d 1 5 1 5 0]. With other inputs the same range both misses documents inside it and matches documents outside it.",
   "impact_class": "silent wrong results",
   "introduced_commit": "7c2e7a0fb80a5bf733cf710aee6cbf01d02629eb (branch_6x, first released in 6.2.0) and e92a38af90d12e51390b4307ccbe0c24ac7b6b4e (master, first released in 7.0.0), LUCENE-7355 'Add Analyzer#normalize() and use it in query parsers' (JIRA, migrated as apache/lucene#8409; pre-GitHub, no pull request), by Adrien Grand (jpountz): it moved the classic QueryParser's analyzed range bounds from analyzeMultitermTerm (tokenStream, which yields the ICU key) to the new Analyzer#normalize, and in the same commit added the attributeFactory override (then without an argument; LUCENE-7429 later added the fieldName parameter) to CollationKeyAnalyzer and the test MockBytesAnalyzer but not to ICUCollationKeyAnalyzer; the master commit also removed setAnalyzeRangeTerms, so from 7.0.0 every classic-parser range bound goes through normalize [read]. ICUCollationKeyAnalyzer has never had the override (git log --all -G attributeFactory over all six of its historical paths: empty). A regression: the same user scenario (an ICU collation analyzer plus a query-parser range) had been fixed at a different site by LUCENE-4176 (apache/lucene#5248, 2012).",
   "introduced_date": "2016-06-28 (author date of both commits; committed 2016-07-12)",
   "first_affected_version": "6.2.0 [exec]; 7.0.0 in the default configuration [exec]",
   "affected_versions": "[exec] main 645d4fe14a20 (-ea and -da: finder, the independent reproduction, the intended-behaviour check, adjudication, the cross-model refute review and the re-run); 10.6.0, released (tag releases/lucene/10.6.0 -> 4ae946e5a9b; release jars, -da: finder, the independent reproduction, the intended-behaviour check); 10.5.2 and 9.12.3 (JUnit, -da: finder, the independent reproduction); 9.1.0 (JUnit, -da); 9.0.0, 8.11.4, 7.7.3 and 7.0.0 (main() probe, default configuration); 6.6.6 and 6.2.0 (main() probe with setAnalyzeRangeTerms(true)). Not affected: 6.1.0 with setAnalyzeRangeTerms(true) (3 hits, bounds are the ICU keys). [read] every release in between; upstream main 716d6f216f5, branch_11x 603af870375 and branch_10_6 7e5aec4370e still lack the override. Not new in 10.6. Executed on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1053.html",
   "repro": "repro/LFV-1053/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1064",
   "priority": "medium",
   "priority_rank": 122,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-kuromoji / sutegana (small kana) token filter factories (JapaneseKatakanaUppercaseFilterFactory, JapaneseHiraganaUppercaseFilterFactory) and Analyzer.normalize via CustomAnalyzer, which the query parsers use for multi-term queries",
   "title": "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",
   "summary": "You build a CustomAnalyzer with the kuromoji small-kana filters (withTokenizer(\"keyword\").addTokenFilter(\"japaneseKatakanaUppercase\").addTokenFilter(\"japaneseHiraganaUppercase\")), and indexing キャットちょっと stores the term キヤツトちよつと. You expect Analyzer.normalize(\"f\", \"キャットちょっと\") to return キヤツトちよつと, 'the representation that it would have in the index', as it does for the similar cjkWidth filter. Instead it returns the input unchanged, because both factories override create() but not normalize() and CustomAnalyzer.normalize only chains each factory's normalize(), so query-parser multi-term terms keep their small kana and silently miss: a document キャット is found by the term query キャット but not by the prefix query キャ* or the range [キャット TO キャット].",
   "impact_class": "silent wrong results",
   "introduced_commit": "d393b9d03952c69d9641cd4a38bbe83939a25942 on main (#12915 'Add new token filters for Japanese sutegana (捨て仮名)', author daixque, squash-merged by benwtrent, author and committer date 2024-03-18T12:50:36Z) and its branch_9x backport 04dd8d32afcdc4f0798647f173db2924a3d38b42 (committed 2024-03-18T12:51:27Z, first released in 9.11.0) [read]. The hook they should override, TokenFilterFactory.normalize, is older (LUCENE-8497, 65486442c4a, 2018-11-19), so this is an omission at birth, not a regression",
   "introduced_date": "2024-03-18",
   "first_affected_version": "9.11.0 [exec]; 9.10.0 and earlier are not affected [exec]",
   "affected_versions": "every release from 9.11.0 through 10.6.0 (9.11.0, 9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2, 10.6.0, released 2026-10-29, 4ae946e5a9b) and main 645d4fe14a20; never fixed (upstream main f815e679bf6c and branch_10_6 unchanged at the fix site, checked 2026-11-01). [exec] the JUnit repro (seed DEADBEEF) fails 1 of 1 on main (-ea and -da), 10.6.0 (-ea and -da, SHA-1-verified release jars), 10.5.2, 10.0.0, 9.12.3 (-da) and 9.11.0 (-ea and -da); the independent reproduction's own JUnit fails 2 of 2 on main (-ea and -da), 10.6.0, 10.5.2, 9.12.3 and 9.11.0. [read] both factory files are byte-identical in all 19 release tags from 9.11.0 to 10.6.0 and on main. Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1064.html",
   "repro": "repro/LFV-1064/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-663",
   "priority": "medium",
   "priority_rank": 123,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-common / Brazilian Portuguese stemmer (BrazilianStemmer.step1; BrazilianStemFilter, BrazilianAnalyzer and the 'brazilianStem' factory)",
   "title": "BrazilianStemmer throws away the result of its \"logias\" -> \"log\" rule, so plural -logias nouns stay unstemmed and stop matching their singular",
   "summary": "You index Brazilian Portuguese text with the stock BrazilianAnalyzer (or BrazilianStemFilter), one document says 'metodologia' and a query says 'metodologias'; you expect both words to stem to 'metodolog' and match, as the stemmer's own rule table says ('logias' in R2 is replaced by 'log', exactly like the singular 'logia'). Instead step1 calls replaceSuffix(CT, \"logias\", \"log\") without assigning the result and still returns true, which also makes stem() skip step2 and step4, so the plural is indexed as the whole word 'metodologias' and the search finds 0 hits. Long -logias plurals such as metodologias, antropologias, terminologias, epistemologias, fenomenologias and odontologias are hit; shorter ones such as tecnologias, ideologias and biologias are not, because the rule does not fire for them and step2 stems them.",
   "impact_class": "silent wrong results",
   "introduced_commit": "950991783af0f4e20e2fd1470dd1c72e98c76f95 (SVN r150897, '- Initial commit (from contributed patches)', 2003-12-23, path sandbox/contributions/analyzers/.../br/BrazilianStemmer.java, line 427: 'replaceSuffix(CT,\"logias\",\"log\"); return true;'); a contributed patch, no issue or PR named. It entered the released tree unchanged with 0955eef89f1 (2005-02-05, 'move parts of the sandbox over to contrib area'). Not a regression: the result was never assigned in any commit on any ref [read]. git blame on main line 401 names 8ef6a0da568 (LUCENE-9570 reformatting, 2020-12-28), which only split the statement over two lines.",
   "introduced_date": "2003-12-23 (first released 2006-02-27 in 1.9)",
   "first_affected_version": "1.9 [read] (tags releases/lucene/1.9-rc1 2006-02-21 and 1.9 2006-02-27, contrib/analyzers; the first release that contains BrazilianStemmer: none of the 18 tags 1.0.1 to 1.4.3 has the file). 1.9.1 [exec] is the oldest executed release (1.9 itself is not on Maven Central; its BrazilianStemmer.java blob is identical to 1.9.1's).",
   "affected_versions": "Every release that ships BrazilianStemmer, 1.9 through 10.6.0 (10.6.0 by reading), and main a9779ef3c193; not fixed. [exec] a version-independent main() check through the public BrazilianAnalyzer (4 of 4 -logias plurals not conflated with their singular, controls conflated) fails on 1.9.1, 2.0.0, 2.4.1, 2.9.4, 3.0.3, 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da), and passes on main with the one-line fix shadowed; the JUnit fails 2 of 3 on 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da). [read] all 147 release tags (RC, alpha and beta tags included) that contain the file have the unassigned call; upstream main a95c754ee003, branch_10x, branch_10_5 and branch_10_6 still have it (read 2026-10-27).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16911",
    "https://github.com/apache/lucene/issues/6569",
    "https://issues.apache.org/jira/browse/LUCENE-5506"
   ],
   "doc": "",
   "repro": "repro/LFV-663/",
   "triage_status": "fix_in_progress",
   "triage_by": "sjs004 (PR #16972)",
   "triage_date": "2026-11-03",
   "triage_link": "https://github.com/apache/lucene/pull/16972",
   "triage_note": "PR #16972 references this bug.",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-594",
   "priority": "medium",
   "priority_rank": 124,
   "novelty": "known",
   "withheld": false,
   "area": "analysis / QueryAutoStopWordAnalyzer (analysis-common query package; AnalyzerWrapper reuse strategy, Analyzer.ReuseStrategy)",
   "title": "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)",
   "summary": "You wrap a stock analyzer such as StandardAnalyzer in QueryAutoStopWordAnalyzer, which computes a separate set of very common words (stop words) for each field from the index, and use that one analyzer for queries on several fields. You expect each field to lose only its own stop words, as the class's per-field design and its upstream test testNoFieldNamePollution say ('Filter should not prevent stopwords in one field being used in another'). Instead the analyzer reuses the analysis chain it built for the first field it analysed on the thread, so a word that is common in one field is removed from queries on another field (MultiFieldQueryParser parses 'boring' to an empty query instead of variedField:boring), and in the other order a field's own stop words stay in.",
   "impact_class": "silent wrong results",
   "introduced_commit": "8bac549ce35181839740c7e220c4d35e8eb06a66 (trunk, svn r1513903) and its branch_4x merge 5a68e5107782 (svn r1513908, the commit that shipped in 4.5.0): LUCENE-5170 'Add getter for reuse strategy to Analyzer, make AnalyzerWrapper's reuse strategy configurable, fix strategy to be stateless' (GitHub issue #6234, by uschindler; JIRA patch, no pull request). It added super(delegate.getReuseStrategy()) to the QueryAutoStopWordAnalyzer constructor (also to ShingleAnalyzerWrapper and LimitTokenCountAnalyzer, whose components do not depend on the field); before it, the implicit AnalyzerWrapper() constructor was hard-wired to new PerFieldReuseStrategy(), and 3.x kept its own per-field cache [read]",
   "introduced_date": "2013-08-14",
   "first_affected_version": "4.5.0 [exec]; 4.4.0, the last release before, passes [exec]",
   "affected_versions": "every release from 4.5.0 through 10.6.0 (10.6.0 by reading) and main a9779ef3c193, never fixed. [exec] probe: 4.4.0 passes (-ea/-da); 4.5.0 (-ea/-da), 4.5.1, 5.0.0, 6.0.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main fail; the finder's JUnit fails 4/4 on 9.12.3, 10.5.2 and main (-ea/-da), and its earlier sweep also failed on 5.5.5 and 6.6.6; the independent reproduction's JUnit fails on main (-ea/-da), 10.5.2 and 9.12.3; a separate probe on main (-ea/-da) and 10.5.2; the intended-behaviour check's probe on main (-ea/-da), 10.5.2 and 9.12.3. [read] a source check of all 114 tagged releases 4.5.0-10.5.2 finds the line in each (8.8.2-8.11.3 are untagged in the history clone and inferred; 4.10.4 not executed because the 4.x probe does not compile there). Releases were run on JDK 25. Not fixed on upstream main a95c754ee003, branch_10x or branch_10_6 (2026-10-26) [read].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/14154",
    "https://github.com/apache/lucene/issues/14430",
    "https://issues.apache.org/jira/browse/LUCENE-5170",
    "https://github.com/apache/lucene/issues/6234",
    "https://issues.apache.org/jira/browse/LUCENE-5803",
    "https://github.com/apache/lucene/issues/6865"
   ],
   "doc": "",
   "repro": "repro/LFV-594/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-311",
   "priority": "medium",
   "priority_rank": 125,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / HTMLStripCharFilter (JFlex grammar: SCRIPT_COMMENT, STYLE_COMMENT, SINGLE_/DOUBLE_QUOTED_STRING and the %eof exclude list; also the 'htmlStrip' char filter SPI)",
   "title": "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>",
   "summary": "You strip '<script><!--\\n// Don't remove\\nvar x = 1;\\n//--></script><p>Welcome to our store</p>' with HTMLStripCharFilter and expect 'Welcome to our store', which is what you get without the apostrophe and what the filter's own tests expect after wrapped script and style blocks. Instead the output is empty: inside the <!-- --> section the apostrophe opens a quoted-string state that ignores '-->' and '</script>', and because the input ends in that state everything after the quote is dropped, so the text is never indexed and a TermQuery for a word after the block misses the document. The same happens with an apostrophe in a CSS comment of a wrapped <style> block or with a lone '\"', with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f3a363708ff95f28b5f29fe2cc27c1cd9fd0fca9 (trunk, svn r1234452; LUCENE-3690 / GitHub #4764 'JFlex-based HTMLStripCharFilter replacement', by GitHub sarowe; SVN/JIRA era, no PR) and its branch_3x backport d387ae60fcf7ecb65596b756a0f8fc79923d0370 (svn r1235308), which shipped in 3.6.0 [read]",
   "introduced_date": "2012-01-22 (trunk, f3a363708ff); 2012-01-24 (branch_3x backport d387ae60fcf)",
   "first_affected_version": "3.6.0 [exec] (through the branch_3x backport); on the 4.x line 4.0.0-alpha by code [read] and 4.0.0 GA [exec]",
   "affected_versions": "Every release from 3.6.0 to 10.6.0 (10.6.0 by reading) and main ea57360912ed. [exec] follow-up main() probe (4 trigger cases, 4 controls): 3.6.0, 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) all lose the text, all controls pass; the finder's JUnit fails 3 of 4 on 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the independent reproduction's JUnit fails 6 of 10 on 9.12.3, 10.5.2 and main (-ea and -da); the intended-behaviour check's probe fails on 4.10.4; the finder's main() probe fails on 4.0.0, 6.6.6, 8.11.4, 9.0.0, 9.8.0, 9.9.0, 9.10.0, 9.12.3 and 10.0.0. [read] all 8 trigger rules are present at all 126 release tags that carry HTMLStripCharFilter.jflex. Not executed: 4.0.0-alpha and -beta (both tags carry the rules), 8.8.2-8.11.3 (not tagged in the history clone), x86 (pure scanner logic). Unaffected: Lucene 3.5.0 and earlier have no such class; Solr 3.5.0's hand-written predecessor filter keeps the text (with a stray '<') [exec]. Not fixed upstream: upstream main e1c4184cb983 (2026-10-26) has a byte-identical .jflex; branch_10x and branch_10_6 carry only the #15756 backport [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-311.html",
   "repro": "repro/LFV-311/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-780",
   "priority": "medium",
   "priority_rank": 126,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / HTMLStripCharFilter (JFlex grammar: the BR, SCRIPT and STYLE start-tag rules of the LEFT_ANGLE_BRACKET state; also the 'htmlStrip' char filter SPI)",
   "title": "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",
   "summary": "You strip '<scripts>hello</scripts> world' (or '<style-guide>hello</style-guide> world') with HTMLStripCharFilter and expect '\\nhello\\n world', which is what Lucene 10.4.0 gives and what main gives for the same shape with any other name, such as '<scrapes>'. Since 10.5.0 the output is empty: the start-tag rules for script and style no longer require a delimiter after the name, so the longer name is taken for a <script> or <style> tag and everything up to the next literal </script> or </style>, here the end of the input, is dropped (for '<stylesheet>hello</stylesheet> world' a StandardTokenizer after the filter emits no token at all). With escapedTags={brand}, '<brand>Acme</brand>' likewise comes out as '\\nAcme</brand>' instead of unchanged.",
   "impact_class": "silent wrong results",
   "introduced_commit": "02014a6245d329ae93898f281b52eb3203d3b343 (main; apache/lucene#15756 \"Fix HTMLStripCharFilter dropping content after =''>\" by GitHub Seungmin123, approved and merged by GitHub msfroh; it fixed #15754, an attribute value ending in '=') and its branch_10x backport b2640a889aa2de9882591e8ebaf4720ea6ce197c, first released in 10.5.0 [read]",
   "introduced_date": "2026-03-03 (merged 2026-03-03T19:17:27Z, author date 2026-03-04 +0900; branch_10x backport committed 2026-03-03)",
   "first_affected_version": "10.5.0 [exec] (10.4.0 is the last unaffected release [exec])",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2, 10.6.0 (by reading) and main a9779ef3c193. [exec] the finder's JUnit (4 tests) fails 4 of 4 on 10.5.0 (-ea and -da), 10.5.1 (-ea), 10.5.2 (-ea and -da) and main (-ea and -da), and passes 4 of 4 on 9.12.3, 10.0.0 and 10.4.0 (-ea; 10.4.0 also -da); the independent reproduction's JUnit fails 8 of 9 on main, 10.5.0 and 10.5.2 and passes 9 of 9 on 10.4.0 and 9.12.3. [read] the branch_10_6 head (contained in 10.6.0) and the unreleased branch_10_5 and branch_10x heads (fetched 2026-10-24) carry the same grammar and scanner blobs as 10.5.2; 9.12.3 to 10.4.0 share the pre-#15756 grammar; releases before 9.12.3 were not executed but are unaffected by code (the three rules required a delimiter after the name from LUCENE-3690 in 2012 until #15756). Not run on x86 (pure scanner logic). Not fixed upstream: upstream main a95c754ee00 (2026-10-26) has the same grammar and scanner blobs, f7bcc0abd816 (prior-art search time) the same grammar, and #15756 is still the last change to HTMLStripCharFilter.jflex on main, branch_10x, branch_10_5 and branch_10_6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-780.html",
   "repro": "repro/LFV-780/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-290",
   "priority": "medium",
   "priority_rank": 127,
   "novelty": "known",
   "withheld": false,
   "area": "analysis / HTMLStripCharFilter (JFlex grammar: OpenTagAttribute, EventAttribute, OpenTagContent)",
   "title": "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",
   "summary": "You strip '<p title=\"a b=\">one</p> two <p title=\"c\">three</p>' with HTMLStripCharFilter and expect the words 'one two three', as the GITHUB#15754 fix (#15756, 10.5.0) now gives for title=\"ab=\". Instead only 'three' comes out: the scanner may treat the value's opening quote as plain tag text, then read ' b=' plus the value's closing quote as the start of a new quoted value, which runs to the next double quote in the document, so the tag swallows 'one two' and that text is never indexed. No error is raised, and the #15754 input itself is handled correctly on main.",
   "impact_class": "silent wrong results",
   "introduced_commit": "Layered. Any attribute name: 4cff584a48941c5c00bbcfaedf799b629dcc7806 (PR #11724, GITHUB#11556 / LUCENE-10520, by GitHub elliotzlin, merged by dweiss; branch_9x backport fc17405271983e27770993d277f144f1f5cc8f94), which added OpenTagAttribute = {Name} \\s* \"=\" \\s* quoted to OpenTagContent [exec]. On-event names only: f3a363708ff95f28b5f29fe2cc27c1cd9fd0fca9 (LUCENE-3690 / GitHub #4764, the JFlex rewrite, svn era, no PR; branch_3x d387ae60fcf7ecb65596b756a0f8fc79923d0370), which added EventAttribute and the [^<>] alternative of OpenTagContent [read]. Partly fixed by 02014a6245d329ae93898f281b52eb3203d3b343 (PR #15756 for GITHUB#15754, 10.5.0; branch_10x b2640a889aa2), which prefixed both attribute rules with \\s+ and so fixed only the shapes without whitespace before the name [read]",
   "introduced_date": "2012-01-22 (LUCENE-3690, on-event names; branch_3x 2012-01-24); 2023-10-02 (PR #11724 merged, any attribute name); partial fix 2026-03-03 (PR #15756)",
   "first_affected_version": "3.6.0 [exec] for on-event names (title=\"a onclick=\"); 9.9.0 [exec] for any attribute name (9.8.0 passes the finder's JUnit 3 of 3 and the independent reproduction's 9 of 9)",
   "affected_versions": "Every release from 3.6.0 to 10.5.2 and main ea57360912ed, with shapes that depend on the version [exec]. 3.6.0-9.8.0 (probes on 3.6.0, 3.6.2, 4.0.0, 4.10.4, 8.11.4, 9.8.0): on-event names only (title=\"a onclick=\", also title=\"xonclick=\"). 9.9.0-10.4.x (probes and the finder's JUnit on 9.9.0, 9.12.3, 10.4.0; the independent reproduction on 9.9.0, 9.12.3, 10.4.0): every attribute name with or without whitespace, including the GITHUB#15754 input. 10.5.0, 10.5.2 and main (-ea and -da): every shape with whitespace before the name, for any name and for on-event names; the no-whitespace shapes are fixed by #15756. 10.5.2 (the last release before 10.6.0) and 9.12.3 (the latest 9.x) are affected. Unaffected: Solr 3.5.0's hand-written predecessor filter (0 of 10 probe cases lose text) [exec]. Not run: 4.0.0-ALPHA/BETA, the releases between 4.10.4 and 8.11.4, x86; git log -G over the attribute macros shows no other grammar change in those ranges [read]. Not fixed upstream: upstream main e1c4184cb983 (2026-10-26) has the same grammar and no open PR touches the filter [read].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15754",
    "https://github.com/apache/lucene/issues/15756",
    "https://github.com/apache/lucene/issues/11724",
    "https://github.com/apache/lucene/issues/13157"
   ],
   "doc": "",
   "repro": "repro/LFV-290/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-878",
   "priority": "medium",
   "priority_rank": 128,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / HTMLStripCharFilter (JFlex grammar: the %eof end-of-input switch for the start- and end-tag tail states; also the 'htmlStrip' char filter SPI)",
   "title": "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'",
   "summary": "You run 'price a < b' through HTMLStripCharFilter and StandardTokenizer and expect [price, a, b], which is what you get for 'price a < b ' (one trailing space) or 'price a < b c'. Instead you get [price, a]: when the input ends right after '<' [whitespace] Name or '</' Name with no '>', the end-of-input handler throws the pending text away, while anywhere else the same unclosed construct is output as text, as the upstream tests require for '<ahref=http:..' at end of input. A TermQuery for 'b' therefore misses the document; other shapes are 'a<b' -> 'a', 'x <p' -> 'x ', 'a </b' -> 'a ' and 'if a < b.' -> 'if a ' ('.' is a name character).",
   "impact_class": "silent wrong results",
   "introduced_commit": "f3a363708ff95f28b5f29fe2cc27c1cd9fd0fca9 (trunk, svn r1234452, 'LUCENE-3690: Re-implemented HTMLStripCharFilter as a JFlex-generated scanner', by GitHub sarowe; issue LUCENE-3690 = apache/lucene#4764; no PR, svn era) and its branch_3x backport d387ae60fcf7ecb65596b756a0f8fc79923d0370 (svn r1235308), the commit that shipped in 3.6.0 [read] [exec]. Wrong from the first release of the JFlex filter, not a later regression",
   "introduced_date": "2012-01-22 (trunk f3a363708ff, authored and committed 2012-01-22T05:20:46Z); branch_3x backport d387ae60fcf 2012-01-24",
   "first_affected_version": "3.6.0 [exec] (the first release of org.apache.lucene.analysis.charfilter.HTMLStripCharFilter, from the branch_3x backport; on the trunk line the first tag is 4.0.0-alpha; its predecessor, Solr 3.5.0's org.apache.solr.analysis.HTMLStripCharFilter, keeps the text [exec])",
   "affected_versions": "every release from 3.6.0 to 10.6.0 (10.6.0 executed as the branch_10_6 head 4ae946e5a9b) and main a9779ef3c193. [exec] the follow-up's version-neutral probe (only HTMLStripCharFilter; oracle: appending one space may only append one space) drops 6 of 6 inputs, with byte-identical output, on 3.6.0, 3.6.2, 4.0.0, 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.8.0, 9.9.0, 9.12.3, 10.0.0, 10.4.0, 10.5.0, 10.5.2 and main (21 targets, both sides of the later fixes #11724 and #15756); the finder's JUnit fails 3 of 3 on 9.1.0 (-ea), 9.12.3 and 10.5.2 (-ea and -da), branch_10_6 head 4ae946e5a9b (-ea) and main (-ea and -da); the independent reproduction's JUnit fails 3 of 5 on main and 10.5.2 (-ea and -da) and 9.12.3 (-ea); the intended-behaviour check reproduced on main (-ea, -da) and 10.5.2 (-da); re-runs on main 2026-10-28. [read] the releases in between, because the %eof case grouping is unchanged since f3a363708ff",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-878.html",
   "repro": "repro/LFV-878/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-721",
   "priority": "medium",
   "priority_rank": 129,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-common / wikipedia: WikipediaTokenizer (JFlex grammar character classes, WikipediaTokenizerImpl.jflex LETTER/DIGIT macros)",
   "title": "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 ﬁ, 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",
   "summary": "You tokenize ordinary plain text with WikipediaTokenizer, for example '5 µm', '1ª edición 2º piso', '２０２６ year', 'ﬁle' or the Yi text 'ꀀꀁ', and expect every letter and digit to end up in a token, as it does with ClassicTokenizer (whose grammar is also pinned to Unicode 3.0) and StandardTokenizer. Instead WikipediaTokenizer skips these characters without an error: '5 µm' gives [5, m], '1ª 2º' gives [1, 2], 'ﬁle' gives [le], and '２０２６', 'ＡＢＣ' and 'ꀀꀁ' give no token; an exhaustive check of the BMP finds 2,083 letters and digits that ClassicTokenizer keeps and WikipediaTokenizer drops. The cause is the grammar: ALPHANUM is built from LETTER and DIGIT macros that are fixed range lists copied in 2008 (WikipediaTokenizerImpl.jflex:154, :156), which miss U+00AA, U+00B5, U+00BA and every letter or digit from U+2000 up to the halfwidth forms outside the CJ and Korean ranges, so these characters fall into the '[^]' ignore rule (:216); StandardTokenizer had the same lists and replaced them with [:letter:]/[:digit:] in 2.4 (LUCENE-1126), but the WikipediaTokenizer copy was never updated.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f715fc6031704bc1a3566044bb80a1a050b917ca (LUCENE-1103 'WikipediaTokenizer', migrated as GitHub #2180; Subversion r608852 from a JIRA patch, no pull request; committed by gsingers): the new contrib/wikipedia grammar copied its ALPHANUM, LETTER and DIGIT lines byte for byte from the StandardTokenizerImpl.jflex of the time (LUCENE-966, 2d954694dc8, 2007-08-08), whose LETTER list goes back to the JavaCC StandardTokenizer.jj; the lines were never edited afterwards (git blame -w at the history base names f715fc60317 for lines 111, 154 and 156; the only later edits nearby, f0a62389ebc '%unicode 3.0' in 2010 and d516948bbde LUCENE-5357 '[^]' ignore rule in 2013, leave LETTER/DIGIT untouched). Divergence: 9e887341774 (LUCENE-1126, #2203, 2008-09-04, first released in 2.4.0) replaced the same lists with [:letter:]/[:digit:] in StandardTokenizer only [read]",
   "introduced_date": "2008-01-04 (the divergence from StandardTokenizer starts with LUCENE-1126 on 2008-09-04)",
   "first_affected_version": "2.3.0 [exec] (tag dated 2008-01-24; the tokenizer did not exist before: 2.2.0 has no WikipediaTokenizer [exec]). In 2.2.0-2.3.2 StandardTokenizer dropped the same characters [exec]; from 2.4.0 on only WikipediaTokenizer does [exec]",
   "affected_versions": "Every release from 2.3.0 through 10.5.2 and main a9779ef3c193 [exec]. By reading, all 141 release tags that contain the grammar have byte-identical ALPHANUM/LETTER/DIGIT lines. Not executed: 2.3.2 (no lucene-wikipedia 2.3.2 on Maven Central) and the other point releases (same lines by reading). Not fixed: upstream main a95c754ee003 (2026-10-26) has the same lists, and no open PR touches the wikipedia package or any .jflex file [read].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16911",
    "https://github.com/apache/lucene/issues/2203",
    "https://issues.apache.org/jira/browse/LUCENE-1126",
    "https://github.com/apache/lucene/issues/3150",
    "https://issues.apache.org/jira/browse/LUCENE-2074",
    "https://github.com/apache/lucene/issues/8050"
   ],
   "doc": "",
   "repro": "repro/LFV-721/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-353",
   "priority": "medium",
   "priority_rank": 130,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / WordDelimiterGraphFilter position increments (IGNORE_KEYWORDS keyword bypass; factory ignoreKeywords option)",
   "title": "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)",
   "summary": "You analyze 'lucene / solr rocks' with a whitespace tokenizer, a keyword marker that marks 'solr', and WordDelimiterGraphFilter(GENERATE_WORD_PARTS | IGNORE_KEYWORDS), and expect the hole left by the swallowed '/' to stay in front of 'solr' (position increments {1, 2, 1}), exactly as when 'solr' is not a keyword, is marked without IGNORE_KEYWORDS, or is a protected word. Instead the keyword branch returns 'solr' before the pending increment is applied, so 'solr' gets 1 and 'rocks' gets 2 ({1, 1, 2}); with the same analyzer at index and query time the exact phrase \"solr rocks\" finds 0 of the 1 matching documents, and the phrase \"lucene solr\" matches the document 'lucene / solr', which the chain without the keyword mark does not.",
   "impact_class": "silent wrong results",
   "introduced_commit": "fc0878cc2f97 (LUCENE-8265 'WordDelimiterFilter should pass through terms marked as keywords', now apache/lucene#9312; master) and its branch_7x backport d1bf6ad79a86, which shipped in 7.4.0; proposed as apache/lucene-solr#359 by GitHub msokolov, closed without a GitHub merge and committed directly by GitHub mikemccand [read]. Not a regression: the defect arrived with the flag, whose early return was placed before the hole accumulator 'accumPosInc += posIncAttribute.getPositionIncrement()' that LUCENE-7619 (637915b890d9, 2017-01-17) had added; no later commit changed that order",
   "introduced_date": "2018-04-28 (fc0878cc2f9 on master and d1bf6ad79a8 on branch_7x, both committed that day; authored 2018-04-22); first released in 7.4.0 (tagged 2018-06-18)",
   "first_affected_version": "7.4.0 [exec] (the first release with IGNORE_KEYWORDS: 7.3.1 has no such flag, compile error [exec], and its keyword-marked control without the flag keeps the hole [exec]); through WordDelimiterGraphFilterFactory (ignoreKeywords, #12525) only from 9.9.0 [exec]: the 9.8.0 factory rejects the parameter ('Unknown parameters'), although CHANGES.txt lists #12525 under 9.8.0",
   "affected_versions": "every release from 7.4.0 to 10.5.2, and main ea57360912ed; no fixed release (upstream main e1c4184cb98 checked 2026-10-26: the file last changed 2023-11-14, #12805, formatting). [exec] the finder's JUnit (its pre-9.1-import variant on 7.4.0-9.0.0) fails 3 run / 2 failed on 7.4.0 (-ea and -da), 7.5.0, 7.6.0, 7.7.3, 8.0.0, 8.1.1, 8.2.0, 8.3.1, 8.4.1, 8.5.2, 8.6.3, 8.7.0, 8.8.2, 8.9.0, 8.10.1, 8.11.4, 9.0.0, 9.1.0, 9.2.0, 9.3.0, 9.4.2, 9.5.0, 9.6.0, 9.7.0, 9.8.0, 9.9.2, 9.10.0, 9.11.1, 9.12.3 (-ea and -da), 10.0.0, 10.1.0, 10.2.2, 10.3.2, 10.4.0, 10.5.2 (-ea and -da) and main (-ea and -da); the factory probe (CustomAnalyzer keywordMarker + wordDelimiterGraph ignoreKeywords=1) fails on 9.9.0, 10.5.2 and main; the independent reproduction's own JUnit and the intended-behaviour check's runs fail on main (-ea, -da), 10.5.2 and 9.12.3; [read] the keyword return precedes 'accumPosInc +=' in the tagged sources of 7.4.0, 8.0.0, 9.0.0, 9.12.3 and 10.5.2; untested patch releases inside the range are inferred affected (the latest patch of every minor line fails and the lines did not change)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-353.html",
   "repro": "repro/LFV-353/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-528",
   "priority": "medium",
   "priority_rank": 131,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / shingle (ShingleFilter, ShingleFilterFactory, ShingleAnalyzerWrapper)",
   "title": "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)",
   "summary": "You index 'a cup of tea' with WhitespaceTokenizer, StopFilter{a, of, the} and ShingleFilter(min 3, max 3) with unigrams on (the default), and expect every real word to be indexed as a unigram, because the javadoc says unigrams 'are always output, regardless of whether any shingles are available' and that the unigram option 'is independent of the min shingle size'. Instead, when the window starts with the filler left by the removed stop word, incrementToken() skips the all-filler unigram, finds fewer than minShingleSize positions left for a shingle and returns false, which ends the stream although 'tea' is still in its window: 'tea' is never indexed and TermQuery(tea) finds 0 documents. With min 4 up to two trailing words are lost, a value such as 'the cat' yields no token at all, and nothing throws, with assertions on or off.",
   "impact_class": "silent wrong results",
   "introduced_commit": "7cd9a8da03ff71b9a2b55ea1e25a6591b43faa8f (LUCENE-2400 'ShingleFilter: don't output all-filler shingles/unigrams', patch by GitHub sarowe, committed by GitHub uschindler; trunk SVN r940451; JIRA patch, no PR; issue migrated as apache/lucene#3475), backported to branch_3x in 379c5fd00d4ff291e5253bacd9f7f143c7a53145 (SVN r940806, 2010-05-04) [exec]. It added the all-filler skip next to the single-attempt incrementToken() of LUCENE-400 (return tokenAvailable, :314); minShingleSize itself came from LUCENE-2218 (fdf4ea24488, 2010-01-31). Not a recent regression",
   "introduced_date": "2010-05-03 (trunk; branch_3x backport 2010-05-04)",
   "first_affected_version": "3.1.0 [exec] (first release with both minShingleSize and LUCENE-2400; 3.0.3 and older have no minShingleSize API [exec], so no release has the API without the bug)",
   "affected_versions": "3.1.0 through 10.5.2 (the last release before 10.6.0; the latest 9.x is 9.12.3) and main ea57360912ed. [exec] the follow-up's version-agnostic main() probe fails on the last patch release of every minor line from 3.1 to 10.5 (69 releases) and on main -ea/-da, with byte-identical output and both controls (min 2, no hole) passing; the finder's JUnit fails 4 of 4 on main -ea/-da, 10.5.2, 10.0.0 and 9.12.3; the independent reproduction's JUnit fails 5 of 8 (controls pass) on main -ea/-da, 10.5.2 and 9.12.3, and the independent reproduction's main() fails on 8.11.4, 6.6.6 and 4.10.4. Not affected: 3.0.x and older (no minShingleSize API)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-528.html",
   "repro": "repro/LFV-528/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-781",
   "priority": "medium",
   "priority_rank": 132,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / shingle (FixedShingleFilter, FixedShingleFilterFactory) over core analysis GraphTokenFilter (route walk)",
   "title": "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",
   "summary": "You run 'coffee at the café' through WhitespaceTokenizer, StopFilter{the}, ASCIIFoldingFilter(preserveOriginal=true) and FixedShingleFilter(2), and expect the filler that stands for the removed 'the' in every shingle that crosses it, as the folded 'cafe' gets it ('at _'), because the class javadoc says the filter 'handles position increments > 1 by inserting filler tokens' and 'will output stacked shingles' for stacked tokens. Instead the original 'café', stacked behind 'cafe' with position increment 0, is joined straight to 'at': you get [coffee at, at _, at café], at size 3 'coffee at café' appears and 'at _ café' is missing, and on a canned stream a(+1) b(+2) c(+0) swapping only the stream order of the two stacked tokens changes the output from [a _, a c] to [a _, a b]. The same misreading gives 'login _' instead of 'login page' after a two-position token 'login' over 'log' plus a removed 'in', and nothing throws, with assertions on or off.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f5867a1413189675cf69ea88412237e32429786e ('LUCENE-8564: Add GraphTokenFilter', GitHub romseygeek; a JIRA patch committed directly, no PR; issue migrated as apache/lucene#9610) [read] [exec]. The commit added core GraphTokenFilter, whose route walk copies each cached token's stream attributes unchanged, and rebuilt FixedShingleFilter on it so the fillers before a route token come from that token's stream position increment; CHANGES.txt 8.0.0 announces no behaviour change and FixedShingleFilterTest changed no shingle expectation. The stacked-after-hole half is a regression of that rewrite; the multi-position half arrived with the position-length-aware routes of the same commit (7.x ignores position length altogether, so it never produced 'login page' either)",
   "introduced_date": "2018-12-03 (author date; committed 2018-12-04)",
   "first_affected_version": "8.0.0 [exec] (7.4.0-7.7.3 pass the stacked-after-hole checks [exec]; 7.3.1 and older have no FixedShingleFilter [exec])",
   "affected_versions": "8.0.0 through 10.5.2 (the last release before 10.6.0, which was not checked; the latest 9.x is 9.12.3) and main a9779ef3c193: every release of those lines, 60 in all (27 8.x, 21 9.x, 12 10.x). [exec] the follow-up's version-portable main() check (core + analysis-common public API, 7 checks and 4 controls) fails 7 of 7 with 0 failed controls, byte-identical, on all 60 releases and on main (-da also on 8.0.0); the finder's JUnit fails 4 of 4 on main -ea/-da, 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 7 of 9 (controls pass) on main -ea/-da, 10.5.2 and 9.12.3; the intended-behaviour check's main() fails on main -ea/-da, 10.5.2, 9.12.3, 8.11.4 and 8.0.0. Not affected (stacked-after-hole half): 7.4.0, 7.5.0, 7.6.0, 7.7.0, 7.7.1, 7.7.2, 7.7.3 [exec]; 7.x is not a correct reference though (it ignores position length and has its own filler defect after an earlier stacked slot). Not fixed upstream: upstream main f7bcc0abd816 (2026-10-27), branch_10x and branch_10_5 have the same code [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-781.html",
   "repro": "repro/LFV-781/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1094",
   "priority": "medium",
   "priority_rank": 133,
   "novelty": "known",
   "withheld": false,
   "area": "analysis / kuromoji (JapaneseTokenizer discardPunctuation)",
   "title": "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)",
   "summary": "You tokenize 東芝（株） with JapaneseTokenizer (default discardPunctuation=true) and expect [東芝, （株）], because only punctuation tokens are to be dropped and （株） is a dictionary noun. Instead you get [東芝]: the tokenizer discards any token whose first character is punctuation, so the noun and its Han letter 株 vanish; the same happens to （有）, （社） and （財） in all three modes.",
   "impact_class": "silent wrong results",
   "introduced_commit": "unknown (not bisected); [read] the first-character test (ViterbiNBest.java:465 and :639 on main) dates from the kuromoji contribution (3.6.0), and JapaneseAnalyzer is affected only before 9.0 (LUCENE-9853 put CJKWidthCharFilter in front of the tokenizer).",
   "introduced_date": "unknown (not bisected)",
   "first_affected_version": "unknown (not bisected); kuromoji since 3.6.0 [read]; oldest executed 9.12.3 [exec]",
   "affected_versions": "9.12.3 and 10.5.2 fail 3 of 4 [exec]; released 10.6.0 fails 3 of 4 (-da) [exec]; main e1faeba08bde fails 3 of 4 with -ea and -da [exec].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/10430",
    "https://issues.apache.org/jira/browse/LUCENE-9390",
    "https://github.com/apache/lucene-solr/pull/1577"
   ],
   "doc": "",
   "repro": "repro/LFV-1094/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1058",
   "priority": "medium",
   "priority_rank": 134,
   "novelty": "known",
   "withheld": false,
   "area": "analysis / kuromoji and nori number filters (JapaneseNumberFilter, KoreanNumberFilter: attribute state of the composed number token)",
   "title": "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)",
   "summary": "You add JapaneseNumberFilter (or KoreanNumberFilter) to an analysis chain and expect a composed number such as 3 (from 三) to keep the attributes of the numerals it replaces: the javadoc says its part of speech and reading come from 'the last token used to compose the normalized number', and as a replacement it should sit at the position of its first numeral. Instead the filter reads one token past the number to find its end, captures that look-ahead token's state and overwrites only the term and offsets, so in 車は三台 with は removed by a StopFilter the number comes out as '3 +1 名詞-接尾-助数詞' (the increment and part of speech of 台) instead of '3 +2 名詞-数'. No error is raised; a part-of-speech stop filter after it then drops numbers that are followed by a particle or a space (the case reported in #10130), and a hole in front of the number disappears, so phrase queries over it can miss.",
   "impact_class": "silent wrong results",
   "introduced_commit": "4b93c66c252b6df109b281bef840b86cbdb5ffbd (JapaneseNumberFilter: 'Added JapaneseNumberFilter (LUCENE-3922)', by Christian Moen, trunk svn r1656670, never in 5.x) and 5a75b8a0808e577f9f1a737f411104034cc23a6b (KoreanNumberFilter, LUCENE-8812, by Namgyu Kim, master; branch_8x backport 36b90c6056932c9cf2e4dfae3d500cab5d03ba3b, a copy of the Japanese code); both came in as JIRA patches, not GitHub PRs (LUCENE-3922 = #4995, LUCENE-8812 = #9856). The first commit of each filter already captured the look-ahead token's state and changed only term and offsets; later commits only add the exhausted flag (LUCENE-7476), reformat or fix typos [read]. Not a regression.",
   "introduced_date": "2015-02-03 (JapaneseNumberFilter); 2019-06-09 (KoreanNumberFilter)",
   "first_affected_version": "6.0.0 [exec] for JapaneseNumberFilter (trunk-only commit; 5.5.5 executed compile_error, no 5.x tag has the class); 8.2.0 [exec] for KoreanNumberFilter (8.1.1 executed compile_error)",
   "affected_versions": "every release of each filter: JapaneseNumberFilter 6.0.0 through 10.6.0, KoreanNumberFilter 8.2.0 through 10.6.0, plus main 645d4fe14a20 (not fixed). [exec] the minimal JUnit fails on main (-ea and -da), on the 10.6.0 release jars (4ae946e5a9b, checksums verified against Maven Central), 10.5.2, 10.0.0 and 9.12.3; the follow-up's main() port of it fails on ja 6.0.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.6.0 and main and passes on main with the fix; the Korean position port fails on ko 8.2.0, 8.11.4, 9.12.3, 10.6.0 and main and passes on main with the fix; the independent reproduction's own JUnit fails on main (-ea and -da), 10.6.0, 10.5.2 and 9.12.3. [read] the relevant lines are unchanged since each filter's first commit; upstream main 716d6f216f5 (2026-10-29), branch_11x and branch_10_6 have no change to either file since ad24abfb0df (author date 2025-08-22) and 1d55d2383ce (2025-02-24), both cleanups. Not new in 10.6.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/10130",
    "https://issues.apache.org/jira/browse/LUCENE-9088",
    "https://github.com/apache/lucene-solr/pull/1073"
   ],
   "doc": "",
   "repro": "repro/LFV-1058/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-658",
   "priority": "medium",
   "priority_rank": 135,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / nori KoreanTokenizer user dictionary (UserDictionary right ids, UserMorphData left id vs the bundled mecab-ko-dic-2.1.1 connection costs)",
   "title": "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 이",
   "summary": "You add a noun such as 학교 ('school') to a nori user dictionary, or a new word such as 깃허브, and analyze '학교가' or '깃허브가 있다' with KoreanTokenizer or KoreanAnalyzer, and expect the noun to connect to the following particle like a plain common noun (NNG) with the same final syllable, which is what the constants' own comments say ('NNG left', 'NNG right with hangul and a coda on the last char', '... no coda') and what 9.x does. Instead the four hard-coded user-noun context ids are still the numbers of mecab-ko-dic 2.0.3, while 10.0.0 switched the bundled dictionary to mecab-ko-dic 2.1.1, in which those numbers name other contexts (the coda flag is inverted and the left id is a 'state change' noun subclass), so the subject particle 가 is analyzed as the verb 가 'go' (VV) and 이 as the copula (VCP) or a complement particle, and KoreanAnalyzer indexes [학교, 가] instead of [학교] and [깃허브, 가, 있] instead of [깃허브, 있]. Setting the constants to the 2.1.1 ids (LEFT_ID 1780, RIGHT_ID 3532, RIGHT_ID_T 3534, RIGHT_ID_F 3533) restores the analysis the bundled dictionary gives the same noun.",
   "impact_class": "silent wrong results",
   "introduced_commit": "76c9fd4e38af65d28236d5a2695348fbd8fa3ed8 (LUCENE-10416 'Update Korean Dictionary to mecab-ko-dic-2.1.1-20180720 for Nori', GitHub issue #11452; a JIRA patch by @uihyun committed by @mocobeta, no pull request) [read]: it switched the dictionary from mecab-ko-dic 2.0.3 to 2.1.1, regenerated ConnectionCosts.dat and the dictionary data and updated UnknownDictionaryBuilder's NGRAM left id (1798 -> 1801), but left UserDictionary RIGHT_ID 3533, RIGHT_ID_T 3535 and RIGHT_ID_F 3534 (set for 2.0.3 by LUCENE-8603, 53b05c5e7e8, 7.7.0) and the user LEFT_ID 1781 (from LUCENE-8231, e851b89cbeb; moved unchanged into UserMorphData by LUCENE-10393, bd22f199dec) as they were; the branch_9x backport b2b35964663 was reverted by c22d6d09d9b two days later, before 9.1.0",
   "introduced_date": "2022-02-20 (committed to main; first released in 10.0.0, 2024-10)",
   "first_affected_version": "10.0.0 [exec]; every 9.x release (9.0.0-9.12.3) and 8.11.4 pass [exec] because branch_9x reverted the dictionary upgrade and kept mecab-ko-dic 2.0.3, which the constants match",
   "affected_versions": "Every 10.x release (10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2, and 10.6.0 by reading) and main a9779ef3c193; never fixed. [exec] the finder's JUnit fails 2 of 2 on all 12 10.x releases up to 10.5.2 and on main (main with -ea and -da) and passes on 8.11.4 and on all 21 9.x releases (follow-up matrix); the independent reproduction's grammatical-probe JUnit fails 3 of 3 on 10.0.0, 10.5.2 and main and passes on 9.1.0 and 9.12.3; data A/B on 9.1.0 jars: with the introducing commit's dictionary data both tests fail, with its parent's data both pass. [read] static check of 59 binaries (cached release jars 7.4.0-10.5.2 and the main build; constants via javap, ConnectionCosts.dat SHA-1): 7.7.0-9.12.3 carry the 2.0.3 matrix with matching constants, 10.0.0-10.5.2 and main the 2.1.1 matrix with the stale constants; 7.4.0-7.6.0 had an earlier, different mismatch of the same constants, fixed by LUCENE-8603 in 7.7.0. The constants and the dictionary name are unchanged on upstream main a95c754ee00 (2026-10-26), branch_10x 1309534296e and branch_10_6 2763db11b0a (2026-10-24) [read]; the 7 commits ea57360912ed..a9779ef3c193 do not touch lucene/analysis/nori. All runs on JDK 25, aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-658.html",
   "repro": "repro/LFV-658/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-620",
   "priority": "medium",
   "priority_rank": 136,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-opennlp / OpenNLPLemmatizerFilter (sentence buffering, KeywordAttribute handling)",
   "title": "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",
   "summary": "You analyze text with OpenNLPTokenizer, OpenNLPPOSFilter, a keyword marker that protects some words (for example KeywordMarkerFilter with the pattern 'evening') and OpenNLPLemmatizerFilter, and expect the protected words to pass through unlemmatized, which is what the filter's KeywordAttribute handling is for. Instead 'They sent him running in the evening' becomes [they, send, he, run, in, the]: the protected last word is gone, and when every word of a sentence is protected only its first word survives ([They]). The filter ends a sentence once it has emitted one lemma per non-keyword token (OpenNLPLemmatizerFilter.java:64, a 9.5.0 change from #11734), so the keyword tokens after the last non-keyword token are thrown away.",
   "impact_class": "silent wrong results",
   "introduced_commit": "3a04aa44c22a (apache/lucene#11734 'Fix repeating token sentence boundary bug', by GitHub kotman12, merged by dweiss; it fixed GITHUB#11735 and GITHUB#11771) on main, and its branch_9x backport b253e4353f09 (re-applied 2022-09-24; the first backport b79edbb54acd of 2022-09-23 was reverted the same day by 64b124349bac because a new upstream test failed on JDK 11; no release in between) [read]; the change replaced the end-of-sentence test 'sentenceTokenAttrsIter == null || !sentenceTokenAttrsIter.hasNext()' by 'lemmaNum >= lemmas.length'; a regression for the sentence-final case; the all-keyword-sentence case was already wrong before (9.4.2 emits nothing and loses the rest of the stream through the old 'zero non-keyword tokens' exit) and #11734 only changed its symptom; no later commit changed this logic (#14804 imports, #16056 toArray calls)",
   "introduced_date": "2022-09-23 (main, #11734 merged); 2022-09-24 (branch_9x backport re-applied)",
   "first_affected_version": "9.5.0 [exec] (release commit dated 2023-01-25; 9.4.2, the last release before, keeps sentence-final keyword tokens [exec]); the filter itself exists since 7.3.0 (LUCENE-2899, 3e2f9e62d77)",
   "affected_versions": "sentence-final keyword drop: 9.5.0 through 9.12.3 and 10.0.0 through 10.5.2 (26 releases) and main a9779ef3c193 [exec]; not affected: 7.3.0 (first release with the filter), 8.11.4, 9.0.0 and 9.4.2 [exec]; all-keyword sentence: wrong in every tested release, 8.11.4 and 9.4.2 emit no token and lose the rest of the stream, 9.5.0, 10.5.2 and main keep only the first token [exec]; branch_10x has the same code (no logic change since #11734 per the upstream commits API) [read]; branch_10_6 not checked; not fixed anywhere, and no open PR changes the file (#16911 only deletes branch_10x) [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-620.html",
   "repro": "repro/LFV-620/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-444",
   "priority": "medium",
   "priority_rank": 137,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / nori KoreanTokenizer (Viterbi.backtrace unigram branch; KoreanTokenizerFactory, KoreanAnalyzer)",
   "title": "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",
   "summary": "You analyze '가격: $100' or '다음\\n\\n문장' with KoreanTokenizer(factory, null, DISCARD, outputUnknownUnigrams=true, discardPunctuation=true), or with the 'korean' factory given only outputUnknownUnigrams=\"true\", and expect punctuation and whitespace to be dropped, as the discardPunctuation javadoc says ('true if punctuation tokens should be dropped from the output') and as happens with outputUnknownUnigrams=false ([가격, 100], [다음, 문장]) and in 7.4.0-8.1.1. Instead you get [가격, $, 1, 0, 0] and [다음, \\n, \\n, 문장], and 'test@example.com' keeps its '@' and '.': the unigram branch of nori's Viterbi.backtrace adds each single-character token of an unknown word without the shouldFilterToken check that the other branch applies. Every such character becomes an index term and pushes the following words one position further, so an exact phrase across it no longer matches.",
   "impact_class": "silent wrong results",
   "introduced_commit": "a556925eb8aaea61e55010a6e5c90520139b56c3 (master; first released in 9.0.0) and its branch_8x backport 990f62aca47fc0571c79e80f25ee1d0b7dc4a824 (same Java changes; the commit 8.2.0 ships): LUCENE-8784 'The KoreanTokenizer now preserves punctuations if discardPunctuation is set to false (defaults to true)' (GitHub issue apache/lucene#9828; committed from a JIRA patch attachment, no pull request; author danmuzi, committer jimczi). In KoreanTokenizer.backtrace it replaced 'if (shouldFilterToken(token) == false) { pending.add(token); ... }' in the outputUnknownUnigrams branch with an unconditional pending.add(token), in the same diff that made shouldFilterToken return 'discardPunctuation && isPunctuation(...)' [read] [exec]. The code moved unchanged into nori Viterbi.java with LUCENE-10493 (c89f8a7ea1e, #805, first released in 10.0.0). Regression: the original nori code (LUCENE-8231, e851b89cbeb, 7.4.0) filtered unigrams. LUCENE-10081 (4df8d641ace, #272, released in 8.10.0 and 9.0.0) later widened the inputs that reach the branch (the second of two spaces now lands in an unknown word); it is a correct fix, not a second root cause [exec]",
   "introduced_date": "2019-05-27 (commit date of a556925eb8a; authored 2019-05-24)",
   "first_affected_version": "8.2.0 [exec]; 8.1.1 is the last unaffected release [exec]; nori first shipped in 7.4.0, which is unaffected [exec]",
   "affected_versions": "every release from 8.2.0 through 10.5.2 (8.2.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2) and main ea57360912ed. [exec]: 8.2.0, 8.3.0, 8.4.0, 8.5.0, 8.6.0, 8.7.0, 8.8.0, 8.8.1, 8.8.2, 8.9.0, 8.10.0, 8.10.1, 8.11.0, 8.11.1, 8.11.2, 8.11.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (follow-up probe); the finder's JUnit also fails on main with -ea and -da, on 9.12.3 and on 10.5.2; the independent reproduction's JUnit fails on 8.2.0, 9.12.3, 10.5.2 and main (-ea and -da). [exec]: 7.4.0, 7.7.3, 8.0.0, 8.1.0, 8.1.1. [read]: the unigram-branch guard is present in every 7.4.0-8.1.1 release tag and absent in every 8.2.0-8.8.1 and 9.0.0-10.5.2 tag of the history clone (the clone lacks tags 8.8.2-8.11.4, which were executed); upstream main 49483e82b357 (2026-10-26) and branch_10x still have the unguarded add; not fixed anywhere. Caveats: all runs on JDK 25 with checksum-verified release jars; releases before 9.1 ran a version-neutral main() probe and a JUnit port with the pre-9.1 test-framework package; releases between the executed ones (for example 9.1.0-9.12.2 and 10.1.0-10.5.1) were checked by tag scan only; the doubled-space symptom starts in 8.10.0 (LUCENE-10081)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-444.html",
   "repro": "repro/LFV-444/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-656",
   "priority": "medium",
   "priority_rank": 138,
   "novelty": "known",
   "withheld": false,
   "area": "analysis / kuromoji user dictionary (ja.dict.UserDictionary entry validation; USER-token expansion in ViterbiNBest and JapaneseTokenizer.incrementToken)",
   "title": "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",
   "summary": "You add the entry 'ソニー ミュージック,ソニー ミュージック,ソニー ミュージック,カスタム名詞' (a name written with a half-width space) to a Kuromoji user dictionary and expect it either to be rejected when the dictionary loads, as LUCENE-8933 promises for segmentations that do not match the surface form ('This change avoids unexpected runtime exceptions or behaviours', MIGRATE.md), or to give tokens that cover ソニー ミュージック. Instead it loads, and JapaneseTokenizer emits ソニー[0,3) and ' ミュージッ'[3,9): one term starts with a space and the final ク is in no token, because the load-time check compares the two columns with all whitespace removed, while the stored segment lengths come from splitting the segmentation on ' ' only and the dictionary key keeps its whitespace. Two related entry shapes also load: a tab between segments (日本<TAB>経済 新聞) makes incrementToken throw ArrayIndexOutOfBoundsException 'arraycopy: last source index 7 out of bounds for char[6]', the exact LUCENE-8933 symptom, and a space after each comma gives an empty token [0,0) (an AssertionError with -ea).",
   "impact_class": "silent wrong results",
   "introduced_commit": "cd372bdc83836148a7ae2e2958407ff0a37b7fc2 (trunk, 'LUCENE-3305: add Kuromoji Japanese morphological analyzer', Robert Muir, 2012-01-12) and its branch_3x commit 8c9485fb66427e54ff0dac9708fdcbe72ba62e94 (2012-01-14), the one contained in 3.6.0. Not a regression: that first UserDictionary already took segment lengths from a space-only split (values[1].replaceAll(\" *\", \" \").split(\" \")), used the raw surface values[0] (whitespace included) as the FST key, and validated nothing but the segment/reading counts [read]. The validation that was meant to stop malformed entries came later and does not cover whitespace: 73ba88a50dec64f367caa88d277c26dfd1d8883b (LUCENE-8933, PR apache/lucene-solr#809, 2019-08-14, first release 9.0.0) compares surface and segmentation only after removing every \\s character; the 8.x backport 0106b74badb98473e1e4464b8e2b37d7bebdc1a4 (PR apache/lucene-solr#810, first release 8.3.0) only rejects a whitespace-stripped segmentation longer than the whitespace-stripped surface. Neither changed the space-only split or the raw key, so the three whitespace entries pass both checks.",
   "introduced_date": "2012-01-12 (trunk cd372bdc838; the branch_3x commit 8c9485fb664 that shipped in 3.6.0 is from 2012-01-14); the incomplete LUCENE-8933 checks that the whitespace entries pass are from 2019-08-14 (73ba88a50de, 0106b74badb)",
   "first_affected_version": "3.6.0 [exec] (first release with Kuromoji; 3.5.0 has none [exec]). On the trunk line 4.0.0 is the first release with cd372bdc838 [exec].",
   "affected_versions": "Every release that ships Kuromoji, 3.6.0 through 10.5.2, and main a9779ef3c193 (unreleased 11.0); never fixed. [exec] 14 versions, all three variants fail identically on each: 3.6.0, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.2.0, 8.3.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.5.2, main. [read] releases in between: git log -G on UserDictionary.java shows only two commits that touched the split, the key or the check semantically (73ba88a50de added the check; #13431 4e8fb2a9df8, first in 10.0.0, precompiled the same regexes with equal semantics); the 8.9-8.11 line is not in the history clone but 8.11.4 was executed. Validation phases [exec]: 3.6.0-8.2.0 no validation at all (any mismatched entry loads); 8.3.0-8.11.4 length-only check; 9.0.0-main equality check. The whitespace entries load in all three phases.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/8236",
    "https://issues.apache.org/jira/browse/LUCENE-7181",
    "https://issues.apache.org/jira/browse/LUCENE-8933",
    "https://github.com/apache/lucene/issues/9976",
    "https://github.com/apache/lucene-solr/pull/809",
    "https://github.com/apache/lucene/issues/810"
   ],
   "doc": "",
   "repro": "repro/LFV-656/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-540",
   "priority": "medium",
   "priority_rank": 139,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-common / compound (HyphenationTree, HyphenationCompoundWordTokenFilter)",
   "title": "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)",
   "summary": "You index text through HyphenationCompoundWordTokenFilter with a hyphenation grammar and the dictionary {zimmer, wohnung}, and expect '3zimmerwohnung' (one StandardTokenizer token) or '\"zimmerwohnung' (WhitespaceTokenizer) to add the subwords zimmer and wohnung, as 'zimmerwohnung' and 'zimmerwohnung\"' (trailing quote) do. Instead no subword is added: HyphenationTree.hyphenate skips the leading characters that are in no character class and shifts its inner hyphenation points past them, but it adds the start and end points unshifted (0 and the letter count), so '3zimmerwohnung' gets [0, 7, 13] instead of [1, 7, 14] and every candidate slice either starts on the '3' or loses the final letter. With two or more such characters the points are not even ascending ('!!abcde' gives [0, 6, 5]), and nothing throws.",
   "impact_class": "silent wrong results",
   "introduced_commit": "7a27cdcbc901cd5e5ebb44065e3158866156dc08 (LUCENE-1166 'Added token filter for decomposing compound words', svn r657027, committed by gsingers; SVN era, no pull request; review record JIRA LUCENE-1166, now apache/lucene#2243, which never discusses the added points or leading characters): it imported HyphenationTree from Apache FOP 'slightly modified', and the modification added the synthetic points res[0]=0 and res[k+1]=len without the iIgnoreAtBeginning shift that FOP's code already applies to the inner points; FOP 0.94/0.95 returns only the inner points [read]. A commit-level A/B is not possible (the parent aa0074f5dbd3 has no compound package); 2.4.0, whose two files are byte-identical to the commit, fails [exec]",
   "introduced_date": "2008-05-16",
   "first_affected_version": "2.4.0 [exec] (the first release with the compound package; the API is absent from 2.3.2 [exec]); no release has ever behaved correctly",
   "affected_versions": "every release from 2.4.0 through 10.5.2, and main ea57360912ed; [exec] the release-portable points probe fails on 2.4.0, 2.4.1, 2.9.4, 3.0.3, 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (also with -da on 9.12.3, 10.5.2 and main) and passes with the fix shadowed on 2.4.0 and main; the filter's missing subwords are executed end to end on 2.4.0, 9.12.3, 10.0.0, 10.5.2 and main (for 2.4.1 to 9.0.0 that the filter drops them is [read]); the finder's JUnit fails 3 of 3 on main -ea/-da, 9.12.3, 10.0.0 and 10.5.2; the independent reproduction's JUnit fails 5 of 9 on main -ea/-da, 10.5.2 and 9.12.3; the intended-behaviour check's fails 2 of 5 on main -ea/-da and 10.5.2; [read] all 138 release tags 2.4.0..10.5.2 in the history clone carry the identical lines, as do upstream main a9779ef3c19, branch_10x 1309534296e (unreleased) and branch_10_6 2763db11b0a (10.6 line; 10.6.0 released 2026-10-29); aarch64 with JDK 25 only (pure char logic, no SIMD)",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-3969",
    "https://github.com/apache/lucene/issues/5042",
    "https://github.com/apache/lucene/issues/9233",
    "https://issues.apache.org/jira/browse/LUCENE-8185",
    "https://github.com/apache/lucene/issues/4120",
    "https://issues.apache.org/jira/browse/LUCENE-3047"
   ],
   "doc": "",
   "repro": "repro/LFV-540/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-897",
   "priority": "medium",
   "priority_rank": 140,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-common / compound hyphenation (TernaryTree insert and compact via HyphenationTree.loadPatterns and HyphenationCompoundWordTokenFilter)",
   "title": "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)",
   "summary": "You load a well-formed FOP-format hyphenation grammar with HyphenationCompoundWordTokenFilter.getHyphenationTree (or HyphenationTree.loadPatterns, or the factory's hyphenator file) and expect findPattern to return every pattern's values afterwards, or an exception if the grammar does not fit. For a grammar whose stored key tails pass 65,535 chars, such as the Norwegian nb.xml from the OFFO download the Lucene docs link to (27,448 patterns, 52,404 nodes), loading succeeds but 1,158 patterns return wrong values (1,111 are not found at all), and with the OFFO 1.2 Norwegian grammar real words such as 'forfatter' are hyphenated and decompounded differently. The cause: TernaryTree keeps the offset of each key tail in its key array in a 16-bit char (lo[p] = (char) kv.alloc(len + 1), TernaryTree.java:151, and (char) k in compact() at :408/:410) without a range check, so past 65,535 the offset wraps and the new tail is written over an earlier one; grammars past 65,535 nodes fail with StackOverflowError instead, the part that Apache FOP's open FOP-2569 already reports.",
   "impact_class": "silent wrong results",
   "introduced_commit": "7a27cdcbc901cd5e5ebb44065e3158866156dc08 (svn r657027), LUCENE-1166 / #2243 'A tokenfilter to decompose compound words' (pre-GitHub, no PR; CHANGES 2.4.0) [read]. The commit added the compound/hyphenation package copied from Apache FOP (the class javadoc says so), with the char-typed pointers and the (char) casts of key-array offsets; the 33-comment LUCENE-1166 discussion does not mention the pointer width or any size limit. When the casts entered FOP was not traced.",
   "introduced_date": "2008-05-16 (author date = commit date 2008-05-16T12:22:50Z); first released in 2.4.0 (tagged 2008-10-08)",
   "first_affected_version": "2.4.0 [exec] (the first release containing 7a27cdcbc901 and the first that ships org.apache.lucene.analysis.compound: the version-portable main() repro loses 556 of 2,600 patterns there, the introducing commit's own 9 hyphenation sources shadowed over 2.4.0 give the same counts, and the 1,500-pattern control loads intact). 2.3.2 and earlier are not affected because the API is absent [exec].",
   "affected_versions": "Every release from 2.4.0 to 10.6.0 (10.6.0 executed as the branch_10_6 head 4ae946e5a9b9), branch_10x and main a9779ef3c193; not fixed upstream (main c5ab3e57b9ba has the same lines) [read]. [exec].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/2243",
    "https://issues.apache.org/jira/browse/LUCENE-1166",
    "https://github.com/apache/lucene/issues/9172",
    "https://issues.apache.org/jira/browse/LUCENE-8124",
    "https://github.com/apache/lucene/issues/4120",
    "https://issues.apache.org/jira/browse/LUCENE-3047"
   ],
   "doc": "",
   "repro": "repro/LFV-897/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-739",
   "priority": "medium",
   "priority_rank": 141,
   "novelty": "known",
   "withheld": false,
   "area": "analysis / UAX29URLEmailTokenizer JFlex URL rules (path segments of http(s), scheme-less, ftp and file URLs; analysis-common)",
   "title": "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",
   "summary": "You run text such as 'see https://en.wikipedia.org/wiki/Python_(programming_language) now' or 'http://example.com/a+b/c' through UAX29URLEmailTokenizer, whose javadoc says URLs are 'tokenized according to the relevant RFCs', and expect each URL as one <URL> token, because RFC 3986 (sub-delims are allowed in path segments) and RFC 1738 (its 'safe' and 'extra' characters are allowed in hsegment and fsegment) both allow $ + ! * ' ( ) and , in a path. Instead the <URL> token stops right before the first such character ('https://en.wikipedia.org/wiki/Python_', then 'programming_language' as a word; 'http://example.com/a', then 'b' and 'c'), because the grammar's two path-segment rules use RFC 3986's narrow 'unreserved' set inside rules shaped after RFC 1738, so these characters are rejected under either RFC. The same characters in the query, fragment or userinfo stay inside the URL token, and nothing reports an error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "3c26a9167cc3a4f5d338e9b74d0af61d6de9d773 (LUCENE-2167 'Implement StandardTokenizer with the UAX#29 Standard', apache/lucene#3243; trunk svn r1002032 by sarowe, Subversion era, no pull request; branch_3x backport ec0e73cd04f940d6caf8308207577313e78a9009, svn r1002468): it added URIunreserved = [-._~A-Za-z0-9], URIsubDelims, HTTPsegment and FTPorFILEsegment with today's text; LUCENE-2763 (apache/lucene#3837; trunk 2b9726ae816, branch_3x 543849ca43f, 2010-12-07) moved them unchanged into the new UAX29URLEmailTokenizerImpl.jflex. Not a regression: git log -L on each macro line ends at the file's creation and, in the older file, at 3c26a9167cc, and the three macro lines are byte-identical at all 131 release tags in the history clone from 3.1 to 10.5.2 and on main [read]",
   "introduced_date": "2010-09-28 (trunk; branch_3x backport 2010-09-29; first release 3.1.0, tag dated 2011-03-30)",
   "first_affected_version": "3.1.0 [exec] (the first release with UAX29URLEmailTokenizer; the follow-up's version-portable probe fails 14 of 14 bug cases with 4 of 4 controls passing on 3.1.0 with -ea and -da; 3.0.3, the release before, has no UAX29* class [exec])",
   "affected_versions": "Every release that has UAX29URLEmailTokenizer, 3.1.0 through 10.5.2, and main a9779ef3c193 (unreleased 11.0); never fixed. [exec] The follow-up's version-portable probe (14 bug cases: the finder's five URLs, each of the eight characters inside a path segment, and RFC 3986's 'name,1.1' segment; 4 controls) fails 14 of 14 with 4 of 4 controls passing on 3.1.0, 3.2.0, 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (3.1.0, 9.12.3, 10.5.2 and main also with -da), and at the introducing commit and its backport (commit-level scanner run); the finder's JUnit fails 4 of 5 on 9.0.0 (import adapted), 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (9.12.3, 10.5.2 and main also with -da); the independent reproduction's test fails 11 of 16 on main and 10.5.2 (-ea and -da) and on 9.12.3 (-ea). [read] The three macro lines are byte-identical at all 131 release tags in the history clone (8 on branch_3x, 3.1 to 3.6.2; 123 from 4.0.0-alpha to 10.5.2), including the back-compat grammar copies of 3.x to 5.x; releases 8.8.2 to 8.11.4 have no tag there, and 8.11.4 was executed from its released jars. Upstream main a95c754ee003 still has the macros (2026-10-26). All runs with JDK 25 on aarch64.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9092",
    "https://issues.apache.org/jira/browse/LUCENE-8044",
    "https://github.com/apache/lucene/issues/9325",
    "https://issues.apache.org/jira/browse/LUCENE-8278",
    "https://github.com/apache/lucene/issues/6454",
    "https://issues.apache.org/jira/browse/LUCENE-5391"
   ],
   "doc": "",
   "repro": "repro/LFV-739/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-525",
   "priority": "medium",
   "priority_rank": 142,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / pattern tokenizers (analysis-common: SimplePatternTokenizer, SimplePatternSplitTokenizer and their simplePattern / simplePatternSplit factories)",
   "title": "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)",
   "summary": "You tokenize 'say \"hello world' with SimplePatternTokenizer and the pattern \"[^\"]*\"|[a-z]+ (a quoted string or a word) and expect [say, hello, world], because the javadoc says the longest match at each start point is the next token and the class otherwise skips one character and tries again (PatternTokenizer with the same regex gives these three tokens). Instead you get only [say]: the lookahead from the unclosed quote runs to the end of the input without ever matching, and that end-of-input branch ends tokenization instead of retrying at the next character, so 'hello' and 'world' are never indexed (minimal case: abc|b on 'ab' gives [] instead of [b]). SimplePatternSplitTokenizer has the same branch and emits the whole rest as one token: separator <[^>]*>|[ ]+ on 'x < y' gives [x, '< y'] instead of String.split's [x, <, y]; nothing throws.",
   "impact_class": "silent wrong results",
   "introduced_commit": "93fa72f77bd024aa09eef043c65c64a6524613dc (LUCENE-7465 'add SimplePatternTokenizer and SimpleSplitPatternTokenizer', by GitHub mikemccand; JIRA patch, no pull request; issue migrated as apache/lucene#8517; branch_6x backport c24e03e6bf4d09e6f31eee8192bb6c0c4b2b6d27 with identical file blobs) [exec]. Not a regression: the branch is as old as the classes",
   "introduced_date": "2017-02-13 (master 93fa72f and branch_6x c24e03e6bf4)",
   "first_affected_version": "6.5.0 [exec] (6.4.2 has no SimplePattern* classes [exec])",
   "affected_versions": "6.5.0 through 10.5.2 (the last release before 10.6.0; latest 9.x 9.12.3, latest 8.x 8.11.4) and main ea57360912ed; never fixed. [exec] the follow-up's portable main() probe (5 bug cases, 4 controls) fails 5 of 5 with all controls passing on 19 releases: 6.5.0, 6.5.1, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.8.2, 8.9.0, 8.10.0, 8.10.1, 8.11.0-8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2, and on main with -ea and -da; the finder's JUnit fails 3 of 3 on 6.5.0, 8.11.4 and 9.0.0 (old test-framework import adapted), 9.12.3, 10.0.0, 10.5.2 and main (-ea, -da); the independent reproduction's JUnit fails 6 of 10 on main (-ea, -da), 10.5.2 and 9.12.3. [read] the exact EOF branch is in both files at all 74 release tags 6.5.0-10.5.2 of the history clone (8.8.2-8.11.4 are untagged there and were executed instead).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-525.html",
   "repro": "repro/LFV-525/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-657",
   "priority": "medium",
   "priority_rank": 143,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-icu / segmentation (ICUTokenizer with DefaultICUTokenizerConfig; break rules Default.rbbi -> Default.brk)",
   "title": "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)",
   "summary": "You tokenize the Korean word U+D55C U+AD6D U+C5B4 ('Korean language') with the default ICUTokenizer, once as is, once with an invisible soft hyphen (U+00AD) after its second syllable and once with a combining mark after each syllable, and expect the word to be indexed every time, because ICUTokenizer 'Breaks text into words according to UAX #29' (ICUTokenizer.java:31), whose rule WB4 attaches Extend and Format characters to the preceding letter, and StandardTokenizer indeed keeps U+D55C U+AD6D U+00AD U+C5B4 as one <HANGUL> token. Instead, the two Hangul rules of Default.rbbi (:127 '$HangulSyllable {200};', :191 '$HangulSyllable $HangulSyllable {200};') have no trailing $ExFm*, unlike every other rule of their group, so the generic status-0 rule (:122) gives the longer match, the segment ending in that character gets rule status 0, and ICUTokenizer skips every status-0 segment as a non-word (:209-214): U+D55C U+AD6D U+00AD U+C5B4 yields only U+C5B4, and U+D55C U+0336 U+AD6D U+0336 U+C5B4 U+0336 (strikethrough), U+D55C U+AD6D U+C5B4 U+FEFF and the Middle Korean tone-marked U+B098 U+302E U+B78F U+302E yield no token at all, silently. Lucene 4.6.1 kept all of these words; the gap came with the ICU 52.1 rule import in 4.7.0 (LUCENE-4381) and is in every release since.",
   "impact_class": "silent wrong results",
   "introduced_commit": "b5dbac5e3582a1cfd59af34c1a41f88aed203da1 (trunk, SVN r1547502; LUCENE-4381 'upgrade ICU to icu4j 52.1' by Robert Muir (GitHub rmuir); JIRA patch, no pull request; the issue is now apache/lucene#5447), backported to branch_4x as 2924e528633022f2c68bbdd1db25b49bb13af4cb (SVN r1547561), which shipped in 4.7.0. It copied ICU 52.1's word.txt into Default.rbbi, moving Hangul syllables out of $ALetterPlus (whose $ALetterEx rule had absorbed ($Extend | $Format)*) into $dictionaryCJK and adding the bare '$HangulSyllable {200};' and '$HangulSyllable $HangulSyllable {200};' [exec]. The status-0 skip in ICUTokenizer already existed in 4.6.1. The secondary sites (rules 13a and 7a) came with 54a2e11434d81ab92923bccbe651752f81ac1973 (GITHUB#13239 'upgrade icu4j to 74.2', Robert Muir; branch_9x 56d4578b253c8c5cabc5d375eba0f981321c2d0c), which replaced the grammar with ICU 74.2's $ExFm form [exec]. Both rule texts follow ICU's own word.txt: ICU ROOT gives status 200 for U+D55C U+00AD in 49.1 and status 0 in 52.1 and 74.2 [exec]",
   "introduced_date": "2013-12-03 (trunk and branch_4x); secondary sites (rules 13a/7a) 2024-04-04",
   "first_affected_version": "4.7.0 [exec] (released 2014-02-25; 4.6.1, 4.6.0 and 4.0.0 are not affected [exec]; releases before 4.0.0 were not run). The secondary sites (a word ending in '_' or a Hebrew word ending in an ASCII apostrophe, followed by Extend/Format) first appear in 9.11.0 on the 9.x line and 10.0.0 on the main line [exec]",
   "affected_versions": "4.7.0 through 10.5.2 (the last release before 10.6.0; the latest 9.x is 9.12.3) and main a9779ef3c193. [exec] the follow-up's version-independent main() probe (default ICUTokenizer, 5 inputs, 3 controls that must keep all letters) loses Hangul on 5 of 5 inputs on 4.7.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.10.0, 9.11.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da), with every control passing; the finder's JUnit fails 5 of 6 on main -ea/-da, 10.5.2 and 9.12.3 and its main() on 5.5.5, 6.6.6 and 8.11.4; the independent reproduction's JUnit fails 8 of 10 on main -ea/-da, 10.5.2 and 9.12.3; the cross-model intended review's own test fails on 10.5.2 as on main. Rules 13a/7a: fail on 9.11.0, 9.12.3, 10.0.0, 10.5.2 and main; pass on 4.6.1, 4.7.0, 8.11.4 and 9.10.0. [read] releases between the sampled ones were not run one by one; continuity rests on the pickaxe result (the Hangul rule was never changed back) and on every sampled release failing; Default.rbbi at upstream main a95c754ee003 and on branch_10x still has the unfixed rules (2026-10-27). Not affected: 4.6.1 and earlier.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9572",
    "https://issues.apache.org/jira/browse/LUCENE-8526",
    "https://github.com/apache/lucene/issues/9570",
    "https://github.com/apache/lucene/issues/9594",
    "https://github.com/apache/lucene/issues/10793",
    "https://issues.apache.org/jira/browse/LUCENE-9754"
   ],
   "doc": "",
   "repro": "repro/LFV-657/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-728",
   "priority": "medium",
   "priority_rank": 144,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-smartcn / HHMM segmenter character classes (Utility.getCharType SPACE_LIKE test -> HHMMSegmenter OTHER branch -> one-character STRING term; SmartChineseAnalyzer and HMMChineseTokenizer)",
   "title": "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",
   "summary": "You index text with the stock SmartChineseAnalyzer, whose segmenter has a character class for 'Characters that act as a space' (CharType.SPACE_LIKE) and skips those characters, so you expect any space to separate words without a trace, as an ordinary space, a tab or the ideographic space U+3000 does. Instead Utility.getCharType knows only those five, and VERTICAL TAB, FORM FEED, OGHAM SPACE MARK and U+2000-U+200A fall through to OTHER and are each indexed as a one-character term: 'hello<THIN SPACE>world' gives [hello, U+2009, world], a TermQuery for U+2009 alone finds the document, and '中<U+2009>国' gives [中, U+2009, 国] where '中 国' gives [中国]. So the exact phrase \"hello world\" matches only 3 of 7 documents that differ only in the separator (space, tab and U+3000 match; FORM FEED, U+1680, EM SPACE and THIN SPACE miss), and HTML indented with &emsp;&emsp; gets two whitespace terms, with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "e01aad89fe24f2482eb2e8c0e39f8272704abe80 (LUCENE-1629 'contrib intelligent Analyzer for Chinese', GitHub #2703: the original SmartChineseAnalyzer contribution, a JIRA patch committed as svn r774718; no GitHub PR exists) [read]. Not a regression: the later commits on getCharType (5265dc1bb20 LUCENE-1722 comment translation, 55858d7ba72 LUCENE-8325 surrogate check in 7.4.0, 7f8b7ffbcad LUCENE-9570 reformatting) left the SPACE_LIKE test and the OTHER fall-through unchanged",
   "introduced_date": "2009-05-14 (first release 2.9.0)",
   "first_affected_version": "2.9.0 [exec] (the first release with the org.apache.lucene.analysis.cn.smart package; 2.4.1, the release before, has no such package [exec], so no release ever shipped an unaffected SmartChineseAnalyzer)",
   "affected_versions": "Every release from 2.9.0 to 10.5.2, 10.6.0 (by reading), and main a9779ef3c193; not fixed. [exec] a version-portable driver reports the bug fully present (28 of 28 inputs give a whitespace-only term, 14 of 14 break the exact phrase, 14 of 14 stop 中国 from being joined; controls hold) with byte-identical term lists on 24 releases (2.9.0, 2.9.4, 3.0.0, 3.0.3, 3.1.0, 3.6.2, 4.0.0, 4.7.2, 4.8.0, 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.3.1, 7.4.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2) and on main, with -ea and (9.12.3, 10.5.2, main) -da, and reports it absent on main with the tie-breaker's fix shadowed; the result is the same on both sides of the boundaries 4.7.2/4.8.0 (LUCENE-4984, HMMChineseTokenizer), 5.5.5/6.0.0 (LUCENE-5969, SentenceTokenizer removed) and 7.3.1/7.4.0 (LUCENE-8325); the tie-breaker's JUnit fails 4 of 7 (its 3 controls pass) and the finder's 2 of 2 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (neither compiles on 9.0.0, which predates org.apache.lucene.tests). [read] branch_10_6, branch_10x, branch_10_5 and upstream main a95c754ee00 have the same SPACE_LIKE test and OTHER fall-through (read 2026-10-27).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/202",
    "https://github.com/apache/lucene/issues/681",
    "https://github.com/apache/lucene/issues/3089",
    "https://issues.apache.org/jira/browse/LUCENE-2014",
    "https://github.com/apache/lucene/issues/2802",
    "https://issues.apache.org/jira/browse/LUCENE-1728"
   ],
   "doc": "",
   "repro": "repro/LFV-728/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-849",
   "priority": "medium",
   "priority_rank": 145,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / kuromoji completion romanization (romaji_map.txt read by KatakanaRomanizer; JapaneseCompletionFilter, JapaneseCompletionAnalyzer)",
   "title": "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')",
   "summary": "You index 雑誌 ('magazine'), マッチ ('match') and 三つ ('three') in a document suggester with JapaneseCompletionAnalyzer, whose javadoc lists modified Hepburn among the supported romanizations, and expect typing 'zasshi', 'macchi' or 'mittsu' to suggest them, just as 'issho' suggests 一緒 and 'maccha' suggests 抹茶. Instead nothing is suggested: the bundled romaji_map.txt gives the small-tsu rows ッシ, ッチ and ッツ only the spellings 'ssi', 'tti' and 'ttu', although the base rows シ, チ, ツ list shi, chi, tsu and the neighbouring rows ッシャ and ッチャ list 'ssha' and 'ccha'. Only the Kunrei spellings (zassi, matti, mittu) find these words.",
   "impact_class": "silent wrong results",
   "introduced_commit": "4e86df96c0385a7b552434d7e2a9bee69f18bd77 (LUCENE-10102 / issue #11140, PR #297, 'Add JapaneseCompletionFilter for Input Method-aware auto-completion'): the commit created romaji_map.txt with the defective rows [read]. Inside the PR, its first commit dff3942eed5 (2021-09-13) already had ッシ,ssi / ッチ,tti / ッツ,ttu, and PR commit fc90e452474 (2021-09-17) added jji/jja/jju/jjo to the ッジ rows after a review request while leaving these rows unchanged [read]. The only later commit to the file, 4676a735c18 (#12047, 2023-01-02), changed header comments only.",
   "introduced_date": "2021-09-17 (author and merge date of 4e86df96c03)",
   "first_affected_version": "9.0.0 [exec] (the first release with JapaneseCompletionFilter / romaji_map.txt; on 8.11.0 and 8.11.4 the repro fails to compile only because those classes are absent)",
   "affected_versions": "Every release from 9.0.0 to 10.5.2 (33 releases; latest 9.x: 9.12.3; latest 10.x before 10.6.0: 10.5.2), the branch_10_6 head 4ae946e5a9b9 (10.6.0, released 2026-10-29) and main a9779ef3c193 [exec]. Upstream main 20ced71c1e6 and branch_10x carry the identical table blob [read]. The release jars ship two blobs of the file (4a803a469ad in 9.x, 8136668e708 in 10.x and main) with identical data rows [read]. No fix exists; no regression window and no last good version.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-849.html",
   "repro": "repro/LFV-849/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-047",
   "priority": "medium",
   "priority_rank": 146,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / vectors",
   "title": "Two antipodal COSINE vectors make the OSQ centroid zero, so flush or merge fails and the writer closes",
   "summary": "With the scalar-quantized (OSQ) vectors format and COSINE, you index vectors whose normalized sum is exactly zero, such as {1,0} and {-1,0}, into one segment. You expect flush and merge to work. Instead normalizing the zero centroid throws 'Cannot normalize a zero-length vector', the writer closes tragically with its buffered documents lost, and merges stay blocked.",
   "impact_class": "index unusable",
   "introduced_commit": "#14078 (8856a5f4eb7) added the l2normalize(centroid) pattern (Lucene102BinaryQuantizedVectorsWriter, 10.2.0); #15169 (594eeb7e637) carried it into Lucene104 [read]",
   "introduced_date": "2025-03-04 (8856a5f4eb7)",
   "first_affected_version": "10.2.0",
   "affected_versions": "10.2.0-10.5.2, branch_10_6 2763db11b0a (2026-10-24, five commits before the 10.6.0 tag 4ae946e5a9b) and main [exec]; 10.6.0 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-047.html",
   "repro": "repro/LFV-047/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-183",
   "priority": "medium",
   "priority_rank": 147,
   "novelty": "known",
   "withheld": false,
   "area": "codecs / postings writer and reader (Lucene104 level-1 skip data, ImpactLength; the same field in the Lucene912, Lucene101 and Lucene103 formats)",
   "title": "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",
   "summary": "You index with the default codec and a custom Similarity whose norm is the field length (or another value that does not fit in a byte), and one term appears in 8,192 documents of a segment with growing frequencies, for example through Lucene's DelimitedTermFrequencyTokenFilter. You expect the term's postings to read back exactly as indexed. Instead the writer stores the length of the level-1 skip block's impact list, which here exceeds 32,767 bytes, in a signed short: with assertions on, flush fails; with assertions off, the segment is written and every read of the term throws 'numBytes must be >= 0', or, with wider norms, decodes wrong data (doc 0 with freq 1,602,871,807 instead of 1,000, and most documents missing).",
   "impact_class": "data corruption",
   "introduced_commit": "b4a8810b7aea2fa6143aa0323f924f85c5cb3329 on main and its branch_9x backport 59b7c28eb474bc223b7ede1e386651136468f3cc, apache/lucene#13585 'Inline skip data into postings lists' (author jpountz), which added the Lucene912 format with assert numImpactBytes <= Short.MAX_VALUE followed by writeShort((short) numImpactBytes) [read]. Carried unchanged into Lucene101 (cfdd20f5bc8, #13968), Lucene103 (878e23f7739, #14333) and Lucene104 (00f2b01e798). Reach widened by 00f2b01e798554bfd86b06da2897f810719064ab on main / backport 351c42c4fbdb9b0d52a6393d9974d2d7e67c3a38, apache/lucene#15160 'Bump block size of postings to 256.' (author jpountz, 10.4.0): the level-1 block grew from 4,096 to 8,192 docs, so about 4 bytes per impact now overflow instead of about 8",
   "introduced_date": "2024-07-31 (#13585 merged on main); reach widened 2025-09-10 (#15160)",
   "first_affected_version": "9.12.0 [exec] (9.11.1 is the last unaffected release [exec]: its Lucene99 skip writer stored the impact length as a VInt; the trigger API already existed there)",
   "affected_versions": "9.12.0, 9.12.1, 9.12.2, 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main ea57360912ed [exec]; not affected [exec]: 9.11.1 (two portable repros pass with -ea and -da); not fixed upstream [read]; not executed: reading a bad segment written by an older release through the backward-codecs readers on main (they read the same signed shorts)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/13585",
    "https://github.com/apache/lucene/issues/15160",
    "https://github.com/apache/lucene/issues/10196",
    "https://issues.apache.org/jira/browse/LUCENE-9156",
    "https://github.com/apache/lucene/issues/16248",
    "https://github.com/apache/lucene/issues/16491"
   ],
   "doc": "",
   "repro": "repro/LFV-183/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-097",
   "priority": "medium",
   "priority_rank": 148,
   "novelty": "new",
   "withheld": false,
   "area": "index / columnar addBatch doc values (dense NUMERIC and SORTED_NUMERIC writers)",
   "title": "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",
   "summary": "You index a dense LongColumn as NUMERIC or SORTED_NUMERIC doc values with IndexWriter#addBatch, its values cursor throws part-way (for example after 255 earlier documents, a 2-document batch whose cursor fails on its 2nd value), and you keep adding documents to the same writer. You expect what Lucene's own recovery test asserts: the exception propagates, the batch's documents are deleted, and a document added afterwards with value 42 reads back 42. Instead the values the cursor delivered before the throw stay in the doc-values buffer with no document attached, so the good document reads back -1 (a value of the rejected batch) and every later document of that field in the segment is shifted by the same number of values, which survives commit, reopen and forceMerge(1) while CheckIndex finds nothing wrong.",
   "impact_class": "data corruption",
   "introduced_commit": "3d89568155799e2e1efe132f67967d9725f4bd60 (#15990 'Add experimental columnar indexing api', main; parent 227255fdb08a), released through the branch_10x backport 3ec3bff01b15 (#16066), whose patch for the three methods is the same (git patch-id b091896e1e7b) [exec]. The bug is as old as the API.",
   "introduced_date": "2026-05-14 (#15990 merged into main, #16066 into branch_10x)",
   "first_affected_version": "10.5.0 [exec]",
   "affected_versions": "10.5.0, 10.5.1 and 10.5.2 (latest 10.5.x release) [exec]; main from 3d89568 (2026-05-14) through ea57360912ed [exec]; the unreleased branch_10x and branch_10_5, and branch_10_6 (10.6.0, released 2026-10-29), carry the same code for the three methods [read]; not applicable: every release before 10.5.0, including 10.4.0 and 9.12.3, where the columnar API does not exist (compile error) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-097.html",
   "repro": "repro/LFV-097/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-101",
   "priority": "medium",
   "priority_rank": 149,
   "novelty": "new",
   "withheld": false,
   "area": "index / columnar addBatch (dense points, PointValuesWriter)",
   "title": "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",
   "summary": "You add a batch with IndexWriter#addBatch whose dense points column (a LongColumn, or a BinaryColumn with point dimensions) has more values than fit in one 4 KiB chunk, and the batch fails after the first chunk, because Lucene's own length check rejects a value of the wrong width or because your cursor throws; Lucene rejects the batch with a non-aborting exception, the writer stays open, and you keep indexing. You expect the rejected batch to leave no trace, as Lucene promises for non-aborting exceptions and as its own ThrowMidBatchRecovers tests assert, so a document you add next with IntPoint p=7 matches p == 7. Instead the dense path had already copied the first chunk's point bytes into the field's buffer without recording doc IDs for them, so the next document is paired with the rejected batch's first value (the only live document, added with p=7, matches p == 1000 instead), every later point of that field in the segment is shifted, CheckIndex stays clean and the wrong values survive merges.",
   "impact_class": "data corruption",
   "introduced_commit": "3d8956815579 (#15990 'Add experimental columnar indexing api', main, merged 2026-05-14; branch_10x backport 3ec3bff01b1 via #16066), which added PointValuesWriter.addDense1DIntValues / addDense1DLongValues with each staged chunk written inside the loop and numPoints / numDocs / lastDocID advanced only after it, with no try/finally; 8a77a334aea5 (#16227 'Add dense indexing path for BinaryColumn', merged 2026-06-12; branch_10x cherry-pick 7a0042427ff) copied the structure into addDenseNDValues, added the default BytesRefValuesCursor#fillPackedPoints length check that throws part-way, and raised the chunk from 1 KiB to 4 KiB [read]",
   "introduced_date": "2026-05-14 (#15990, LongColumn variant); 2026-06-12 (#16227, BinaryColumn variant)",
   "first_affected_version": "10.5.0 [exec]",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2 and main ea57360912ed [exec]; main since 3d8956815579 (2026-05-14) [exec]; branch_10x, branch_10_6 (10.6.0, released 2026-10-29) and branch_10_5 have the same dense-path code [read]; not applicable: 10.4.0 and every earlier release, including 9.12.3 (no column API; the repro does not compile) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-101.html",
   "repro": "repro/LFV-101/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-096",
   "priority": "medium",
   "priority_rank": 150,
   "novelty": "new",
   "withheld": false,
   "area": "index / columnar addBatch (term vectors)",
   "title": "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",
   "summary": "You add a document, then call IndexWriter#addBatch with a column batch that declares a new text field with term vectors but adds no row: the batch is empty, or it is rejected with IllegalArgumentException because a later column conflicts with the existing schema, or its column cursor throws before the first row. You expect the earlier document to commit and the index to open, as it does when the same rejection happens through addDocument. Instead the segment's FieldInfos say the field has term vectors but no term-vector files were written, so DirectoryReader.open on the commit throws CorruptIndexException ('No sub-file with id .tvd found in compound file'), or, with the default IndexWriterConfig, commit() itself throws.",
   "impact_class": "index unusable",
   "introduced_commit": "3d89568155799 (#15990 'Add experimental columnar indexing api', main), released through its branch_10x backport 3ec3bff01b15 (#16066) [exec]; not a regression: the defect is in the column API's first version. It combines two older pieces that were safe on their own: the lazily created term-vectors writer with the 'if (writer != null)' flush guard (873f19992445, LUCENE-2621, 2011) and the setHasVectors() call made when a term-vector FieldInfo is created (d03662c48bfc, LUCENE-9334, first released in 9.0.0) [read]",
   "introduced_date": "2026-05-14 (#15990 merged into main; backport #16066 merged into branch_10x the same day)",
   "first_affected_version": "10.5.0 [exec]",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2 and main ea57360912ed [exec], and the introducing commit 3d89568155799 [exec]; not applicable to 10.4.0 and earlier, including 9.12.3 (no column API, the repro does not compile) [exec]; branch_10_6 (10.6.0, released 2026-10-29) and branch_10x have the same TermVectorsConsumer blob 832f0275fa9 and the same processBatch structure [read], so 10.6.0 (released 2026-10-29) is affected [read]; not fixed upstream as of main ea57360912ed [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-096.html",
   "repro": "repro/LFV-096/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-094",
   "priority": "medium",
   "priority_rank": 151,
   "novelty": "new",
   "withheld": false,
   "area": "index / columnar addBatch (DictionaryColumn SORTED_SET doc values, SortedSetDocValuesWriter)",
   "title": "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",
   "summary": "You add a batch with IndexWriter#addBatch whose SORTED_SET DictionaryColumn gives the first value of some document an ordinal outside the dictionary (or whose cursor throws while returning that ordinal); Lucene rejects the batch with an IllegalArgumentException, the writer stays open with no tragic exception, and you keep indexing. You expect the rejected batch to leave no trace, as Lucene promises for non-aborting exceptions (the batch's documents are marked deleted and the index stays consistent), so a later document with two SORTED_SET values commits and reads back normally. Instead the doc-values writer had already opened the rejected document before it checked the ordinal and records it with zero values, so the next commit fails (AssertionError with -ea, ArrayIndexOutOfBoundsException with -da), closes the writer and loses all uncommitted documents, or, with -da and some value layouts, succeeds but writes a segment whose field throws NullPointerException when opened or fails CheckIndex.",
   "impact_class": "data corruption",
   "introduced_commit": "e79c6780627f (#16101 'Add DictionaryColumn for SORTED / SORTED_SET dvs', main; branch_10x backport 8a9e55f254d1, contained in releases 10.5.0-10.5.2), which added SortedSetDocValuesWriter.addOrdinalTuples with the document switch before the ordinal check [read]",
   "introduced_date": "2026-05-26 (#16101 merged)",
   "first_affected_version": "10.5.0 [exec]",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2 and main ea57360912ed [exec]; branch_10_6 (10.6.0, released 2026-10-29), branch_10x and branch_10_5 have the same code [read]; not applicable: 10.4.0 and every earlier release, including 9.12.3 (no org.apache.lucene.document.column package and no IndexWriter#addBatch; the repro does not compile) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-094.html",
   "repro": "repro/LFV-094/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-199",
   "priority": "medium",
   "priority_rank": 152,
   "novelty": "known",
   "withheld": false,
   "area": "index / deletion policies (PersistentSnapshotDeletionPolicy save-file loading, crash recovery)",
   "title": "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",
   "summary": "You use PersistentSnapshotDeletionPolicy to protect a commit (for example for a backup): snapshot() returns, which its javadoc says means the snapshot is persisted, and later the machine crashes, loses power or the process is killed while another snapshot() or release() call is writing the next save file snapshots_N. You expect that after a restart the policy still holds the earlier snapshot (persist() keeps the previous save file until the new one is fsynced, so there is a good file to fall back on). Instead loadPriorSnapshots() takes its state from the newest, empty or truncated save file even though reading it threw, deletes the good older save file, and reports no snapshots, with no exception or log, so the next IndexWriter deletes the snapshotted commit (in the repro: snapshot count 0, segments_1 deleted, only commit 2 left).",
   "impact_class": "data corruption",
   "introduced_commit": "efeaac746ae10c63d71051ce2d8575cf85bb6616 (trunk, svn r1478726, 2013-05-03; this line reaches 6.0.0 and later) and its branch_4x backport c82d98363498194ae4a656d34a2029efdd9e4b6d (svn r1478730, same day; reaches 4.4.0-5.5.5): LUCENE-4976 'PersistentSnapshotDeletionPolicy should save to a single file' (apache/lucene#6040; SVN-era patch by mikemccand, reviewed +1 by shaie; no PR). It replaced the index-backed store with snapshots_N save files and added loadPriorSnapshots(), whose genLoaded/refCounts assignment after the try/catch (:239-241) and 'Remove any broken / old snapshot files' loop (:253-260) are the root cause; later loader edits (LUCENE-5512, LUCENE-5904, 2016 delete-API churn, LUCENE-9570 reformat) are cosmetic. The follow-up 8c6e38ee605 / 1edbfb98ee8 (2013-05-05, 'add missing sync / delete old save files', also in 4.4.0) added sync-then-delete-old to persist() and left the loader unchanged [read]",
   "introduced_date": "2013-05-03 (efeaac746ae1 trunk, c82d98363498 branch_4x)",
   "first_affected_version": "4.4.0 [exec] (the first release with LUCENE-4976); 4.3.1 is the last unaffected release [exec]: the API did not exist there (PersistentSnapshotDeletionPolicy kept its snapshots in a one-document Lucene index, with snapshot(String id)); the repro does not compile on it, and an analog crash test on that old store keeps the snapshot (3 of 3 pass)",
   "affected_versions": "Every release from 4.4.0 through 10.5.2, and main ea57360912ed. [exec] the finder's repro (version-adapted sources for the 4.x, 5.x and 6.x-8.x API spellings) fails 2 of 3 with its control passing on 4.4.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.12.3, 10.5.2 (-ea and -da) and main (-ea and -da); the independent reproduction's independent test fails on main (-ea, -da), 10.5.2 and 9.12.3; a separate test fails on main, 10.5.2 and 9.12.3; the intended-behaviour check's process-kill driver loses the snapshot on main and 10.5.2. [read] all 115 release tags from 4.4.0 to 10.5.2 in the history clone carry the same loader (8.8.2-8.11.x are not tagged in the clone; 8.11.4 was executed). Not fixed upstream: main is still ea57360912ed, and open PR #16482 is unmerged (read 2026-10-26). All runs on aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16482",
    "https://github.com/apache/lucene/pull/16482"
   ],
   "doc": "",
   "repro": "repro/LFV-199/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-408",
   "priority": "medium",
   "priority_rank": 153,
   "novelty": "new",
   "withheld": false,
   "area": "misc / index tools (IndexSplitter.split) over core / index: SegmentCommitInfo per-commit doc-values update state",
   "title": "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",
   "summary": "You update a doc value in a segment (updateNumericDocValue, updateBinaryDocValue, or a soft delete), commit, and copy that segment to a new index with IndexSplitter.split, expecting the copy to hold the same documents and values and to stay a normal index. Instead split() copies all of the segment's files but writes a destination commit that records only the segment's generation numbers, not its per-commit field-infos files, doc-values update files or (on main) doc-values overlays. So on main the copy reads an updated field from its newest sparse update alone (price 10,999,12,13 reads as none,999,none,none), and in every release since 4.6.0 the first IndexWriter opened on the copy deletes the copied update files as unreferenced, after which the copy cannot be opened (NoSuchFileException: _0_1.fnm).",
   "impact_class": "data corruption",
   "introduced_commit": "49684b82701b4196c9ae029b0c4d45fd6efdcb4a (branch_4x merge of LUCENE-5189 'add NumericDocValues field updates', committed by shaie, svn r1537832, pre-GitHub, no PR; the trunk commit is 1120e46961b, 2013-09-15): the commit that added doc-values updates and the per-commit update file sets in segments_N changed IndexSplitter.split in the same diff to pass only a generation into the new per-commit object [read]; later edits of the same constructor call (LUCENE-5618/5636 c863a7251d5, LUCENE-8341 fe83838ec37, LUCENE-9324 113043b1ed2, #12685 6677109ee60) kept the omission. The wrong-values symptom (by default on main only; in 10.6.0 only with overlays enabled) came with 75eddfaff22eb46e8a68529952fb6787b1258854 (#16418 'Incremental doc-values updates', by jimczi), which added per-commit doc-values overlays that IndexSplitter does not carry [exec]",
   "introduced_date": "2013-11-01 (branch_4x; trunk 2013-09-15) for the writer-deletes-files symptom; 2026-08-13 for the wrong-values symptom (#16418)",
   "first_affected_version": "4.6.0 [exec] for the writer-deletes-files symptom (the first release with IndexWriter.updateNumericDocValue; 4.5.1 cannot compile the trigger, and a deletion-instead-of-update control passes on 4.5.1 and 4.6.0); the wrong-values symptom is in no release by default (main by default since 75eddfaff22; 10.6.0, released 2026-10-29, only with setMaxDocValuesOverlays(n>0), because branch_10_6 defaults overlays to 0)",
   "affected_versions": "every release from 4.6.0 through 10.6.0 (10.6.0 by reading, its branch_10_6 executed at 2763db11b0a) and main ea57360912ed. [exec] the writer-deletes-files symptom (an IndexWriter opened and closed on the copy deletes _0_1.fnm and the doc-values update files, then DirectoryReader.open throws NoSuchFileException, FileNotFoundException on 4.6.0) on 16 releases: 4.6.0, 4.8.1, 4.9.0, 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0 and 10.5.2 (version-portable main() probe; 9.12.3 and 10.5.2 also with -da and with the finder's and the independent reproduction's JUnits; 7.0.0, 8.11.4 and 9.0.0 also with the finder's portable main()), on main commits 23c1810e431 and 75eddfaff22, on 10.6.0-SNAPSHOT branch_10_6 2763db11b0a, and on main ea57360912ed (-ea and -da); in every release the copy reads correct values until a writer opens it. [exec] the wrong-values symptom (the copy reads none,999,none,none instead of 10,999,12,13) only where doc-values overlays are on: main 75eddfaff22 (default 16) and ea57360912ed (default 8), and branch_10_6 2763db11b0a only with setMaxDocValuesOverlays(8); main with setMaxDocValuesOverlays(0) reads correctly. [read] the releases in between carry the same IndexSplitter construction. Not affected: 4.5.1 and older (no doc-values updates). Not fixed upstream: IndexSplitter.java is the same blob on upstream main cf398bfb142c and branch_10_6 cb17f8f865c (2026-10-26, read-only). All runs on aarch64 with JDK 25.0.3; release jars from Maven Central, SHA-1 checked.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-408.html",
   "repro": "repro/LFV-408/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-481",
   "priority": "medium",
   "priority_rank": 154,
   "novelty": "new",
   "withheld": false,
   "area": "facet / taxonomy (ReindexingEnrichedDirectoryTaxonomyWriter.reindexWithNewOrdinalData)",
   "title": "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",
   "summary": "You index a document with the category Author/Bob through a ReindexingEnrichedDirectoryTaxonomyWriter after its last commit, then call reindexWithNewOrdinalData to refresh the per-category data, whose javadoc promises 'The ordinals themselves will be preserved, so the caller does not need to update references to them in the main index'. Instead the method rebuilds the taxonomy from a reader of the last commit, so Author/Bob disappears (the writer's getSize() drops from 4 to 3) and its ordinal 3 goes to the next new category, Author/Carol. After both indexes are committed, the main index's Bob document is counted as Carol (Alice=1 Carol=1 instead of Alice=1 Bob=1) with no error; on a taxonomy that was never committed the call throws IndexNotFoundException.",
   "impact_class": "data corruption",
   "introduced_commit": "f339e24e8ed64bf64ef4bb05111d252ecdacde1e (main) and its branch_9x backport 2d713d904d011767f5e98bbc763f84a0b4fa508f, GITHUB#12337 'Index arbitrary fields in taxonomy docs' (author stefanvodita, approved by mikemccand; addresses issue #12336; CHANGES 9.10.0 New Features: 'GITHUB#12336: Index additional data per facet label in the taxonomy.') [read] [exec]",
   "introduced_date": "2024-02-08 (f339e24e8ed authored and committed 11:02:12 +0000, merged 2024-02-08T11:02:12Z; backport 2d713d904d0 committed 11:13:36 +0000; PR opened 2023-05-27)",
   "first_affected_version": "9.10.0 [exec], the first release with the API; no earlier release has it [exec]",
   "affected_versions": "9.10.0, 9.11.0, 9.11.1, 9.12.0, 9.12.1, 9.12.2, 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main ea57360912ed [exec]. ReindexingEnrichedDirectoryTaxonomyWriter.java is byte-identical at 9.10.0, 9.11.1, 9.12.3, 10.0.0, 10.5.2 and main [read]. Not fixed upstream: line 63 still opens new DirectoryTaxonomyReader(d) on upstream main a9779ef3c193 and branch_10x (2026-10-26) [read]; open PR #16847 (long doc ids) edits lines 68-70 of the same method but not line 63 [read]. branch_10_6 was not read for this row; at the 10.6.0 release commit 4ae946e5a9b the file is identical to main ea57360912ed [read], so 10.6.0 (released 2026-10-29) is affected. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-481.html",
   "repro": "repro/LFV-481/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-280",
   "priority": "medium",
   "priority_rank": 155,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / per-field postings format merge (PerFieldPostingsFormat attribute bookkeeping)",
   "title": "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",
   "summary": "You index a field with a per-field postings codec (for example a Lucene104Codec subclass that maps the field to its own postings format), then, in a writer session whose codec's postings format is not per-field (SimpleTextCodec or a custom codec), delete every document that has the field and force-merge, and then go back to the per-field codec and merge again. You expect the committed index to open, because every call returned normally. Instead the merged segment still records the field's old format name and suffix although the merge wrote no files for that group, so DirectoryReader.open and CheckIndex fail with CorruptIndexException caused by a missing <segment>_<format>_<suffix>.psm (for example _4_FST50_0.psm).",
   "impact_class": "index unusable",
   "introduced_commit": "63dfba4c7d81a019a4008777beace0d391987ceb on master and its branch_7x commit e8bfa67716368ff3ad670a63d4a8935c6a989cac (the one 7.7.0 shipped), LUCENE-8601 'Adding attributes to IndexFieldType' (now apache/lucene#9647; a JIRA patch series, no pull request; patch by muralikpbhat, committed by mikemccand): merged FieldInfos started to keep the source attributes (FieldInfos.Builder.add passes fi.attributes() where 7.6.0 used an empty map) and the per-field formats' 'found existing value' checks became plain overwrites, while the postings merge kept choosing its fields from the source producers (logic from the default FieldsConsumer.merge and LUCENE-7456, 796ed508f39, 2016), so a field that no source postings reader lists keeps its inherited attributes [read]",
   "introduced_date": "2019-01-03 (master 63dfba4c7d8) and 2019-01-04 (branch_7x e8bfa677163, released in 7.7.0)",
   "first_affected_version": "7.7.0 (released 2019-02-11), with -ea and -da [exec]; the master commit first shipped in 8.0.0 (2019-03-14); 7.6.0 and earlier are not affected [exec]",
   "affected_versions": "7.7.0 through 10.5.2 (the last release before 10.6.0) and main ea57360912ed, with -ea and -da [exec]; [read] every release tag in the history clone from 7.7.0 on contains 63dfba4c7d8 or e8bfa677163 (the clone lacks the 8.8.2 to 8.11.4 tags; 8.11.4 was executed); not affected: every release up to and including 7.6.0 [exec]; not fixed upstream: no commit has touched PerFieldPostingsFormat.java since b6ca26f1212 (upstream main e1c4184cb983 at search time) and none of the 412 open PRs touches it; executed on aarch64 with JDK 25, release jars checksum-verified against Maven Central",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-280.html",
   "repro": "repro/LFV-280/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-249",
   "priority": "medium",
   "priority_rank": 156,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / SharedTermsUniformSplit postings format (STUniformSplitTermsWriter.merge under PerFieldPostingsFormat and PerFieldMergeState)",
   "title": "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",
   "summary": "You index fields a and b with a per-field codec, a in SharedTermsUniformSplit and b in the default postings format, then open a new writer whose codec maps both a and b to one SharedTermsUniformSplit instance (PerFieldPostingsFormat records the mapping per segment, and merging segments written under different mappings is supported), add a document and force-merge. You expect every term to be found after the merge, as with any other postings format. Instead the merge reads only a's shared-terms block from the old segment, so b's old postings are never copied: docFreq(b:b1) is 0 instead of 1, the document stays in the index but cannot be found through b, and CheckIndex reports the index clean.",
   "impact_class": "data corruption",
   "introduced_commit": "b963b7c3dbecda86c2917ad341caee63b93815ac (LUCENE-8753 'New UniformSplit and SharedTermsUniformSplit PostingsFormats', committed by dsmiley; CHANGES.txt credits Bruno Roustant, Juan Rodriguez and David Smiley; apache/lucene-solr#828 per the issue thread, which absorbed #676; the JIRA issue is now apache/lucene#9798) and its branch_8x cherry-pick b8a1857b0bd235bc9d4833276b1e60c9865aa04b (the commit 8.3.0 contains) [read] [exec]: the commit created the format and its custom merge with the 'first Terms, then break' loop, so the defect is as old as the format and not a regression; PerFieldMergeState dates from LUCENE-7456 (796ed508f39, 2016) and its rework #13208 neither introduced nor fixed it (the repro fails before and after)",
   "introduced_date": "2019-09-06 (b963b7c3dbe and the branch_8x cherry-pick b8a1857b0bd, same day)",
   "first_affected_version": "8.3.0 [exec] (tag 2019-10-24, the first release with SharedTermsUniformSplit; 8.2.0 has no uniformsplit classes [exec]); main line 9.0.0 [exec]",
   "affected_versions": "every release from 8.3.0 to 10.5.2 (the last before 10.6.0) and main ea57360912ed [exec] [read]; not a regression; not fixed upstream (the loop is unchanged on main and branch_10x and no open PR changes it, read-only check 2026-10-26); 10.6.0 (released 2026-10-29) was not checked; executed on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-249.html",
   "repro": "repro/LFV-249/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-417",
   "priority": "medium",
   "priority_rank": 157,
   "novelty": "new",
   "withheld": false,
   "area": "misc / BP merge-time reordering (BPIndexReorderer with document blocks)",
   "title": "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",
   "summary": "You index document blocks with IndexWriterConfig#setParentField, merge through BPReorderingMergePolicy with a BPIndexReorderer, and a segment ends up ending with child documents that have no parent after them, for example because you deleted or updated only the parent of its last block and a merge dropped it, or because IndexWriter rejected a block at one of its children (with the documented IllegalArgumentException) just before a flush. You expect later merges to work: IndexWriter accepted every call, CheckIndex calls the index clean and a plain merge of the same segment succeeds. Instead BPIndexReorderer, which assumes the merged view ends with a parent, runs past the end of its arrays in the next reordering merge in which that segment comes last (ArrayIndexOutOfBoundsException with assertions off, AssertionError with them on), and IndexWriter closes with a tragic exception, loses uncommitted changes and fails the same way after every reopen.",
   "impact_class": "index unusable",
   "introduced_commit": "3ad73336ae5ce05d9c96d32e32502383a4d856b3, apache/lucene#13125 'Make BP work on indexes that have blocks.' (by jpountz, merged 2024-03-13; branch_9x backport cb318af614b) [read]; #13128 (4a3f4cfe974, 2024-03-29) only narrows when IndexWriter calls the reorderer and is not the cause; not a regression: before 9.11.0 BP reordering did not keep blocks at all, so this is a defect of the block support since its first release",
   "introduced_date": "2024-03-13",
   "first_affected_version": "9.11.0 (tagged 2024-06-06) [exec]",
   "affected_versions": "9.11.0 through 10.6.0 (10.6.0 by reading) and main ea57360912ed (unreleased 11.0.0-SNAPSHOT) [exec]; not affected: 9.10.0 [exec]; 9.9.x and older cannot express the trigger [exec]; 10.6.0 (released 2026-10-29) has the same block loop with no last-document check [read]; not fixed on upstream main cf398bfb142c (2026-10-26) [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-417.html",
   "repro": "repro/LFV-417/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-563",
   "priority": "medium",
   "priority_rank": 158,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter document blocks (parent field) and merges",
   "title": "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",
   "summary": "You set IndexWriterConfig#setParentField (no index sort) and a merge policy that keeps fully deleted segments, such as SoftDeletesRetentionMergePolicy, and IndexWriter rejects a document block at a child with a documented non-aborting exception (for example a term longer than MAX_TERM_LENGTH) while that block is the only content of its in-memory segment, for example the first thing indexed after a commit. You expect the rejection to leave a consistent index that keeps merging, as the addDocument javadoc promises ('if an Exception is hit ... the index will be consistent'). Instead the block is flushed as a fully deleted segment whose FieldInfos have no parent field (IndexWriter registers the parent field only when it reaches a block's last document), the merge policy keeps it, and every merge that combines it only with segments holding no multi-document block throws IllegalStateException 'expected parent doc field to be \"_parent \" across all segments but found a segment with different field \"null\"' and closes IndexWriter, also after the index is reopened, until forceMergeDeletes removes the segment.",
   "impact_class": "index unusable",
   "introduced_commit": "df6bd25ce44ead0b38cffca6ef9bc3a9ce63dbea (#12829 'Add support for index sorting with document blocks', author s1monw, main); its branch_9x backport 0aa88910ca9 shipped first, in 9.10.0 [read]; #12829 added both halves at once; the preconditions were already there and harmless before it: the merged view that IndexWriter.mergeMiddle builds when no index sort is configured (f7cab164501, #12622, 9.9.0) and MergePolicy#keepFullyDeletedSegment / SoftDeletesRetentionMergePolicy (ecc17f90233, LUCENE-8233, 7.4.0); later 4a3f4cfe974 (#13128, 9.11.0) narrowed it (a merge that includes a multi-document block segment skips the merged view) and 34c9495241d (#15960, 10.5.0) moved the last-document-only registration into IndexingChain without changing behaviour (10.4.0 and 10.5.0 give the same results [exec]); not bisected commit by commit, because the repro needs the API that #12829 itself added",
   "introduced_date": "2024-01-11 (#12829 merged into main as df6bd25ce44, 15:11 UTC)",
   "first_affected_version": "9.10.0",
   "affected_versions": "all 19 releases from 9.10.0 through 10.5.2 (9.10.0, 9.11.0, 9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2) and main a9779ef3c193 (unreleased 11.0.0) [exec]; the scope is wider on 9.10.0, where merges that include a multi-document block segment fail too; from 9.11.0 on (#13128) such merges succeed [exec]; 9.9.2 and earlier are not affected (no IndexWriterConfig#setParentField; the repro does not compile on 9.9.2) [exec]; the previous hunt main ea57360912ed is affected [read]; not fixed on upstream main a95c754ee003 (2026-10-26) [read]; aarch64 with JDK 25 only (no platform-specific code involved)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-563.html",
   "repro": "repro/LFV-563/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1050",
   "priority": "medium",
   "priority_rank": 159,
   "novelty": "new",
   "withheld": false,
   "area": "index / index sorting with document blocks (IndexingChain flush-time sort, DocumentsWriterPerThread non-aborting rejection)",
   "title": "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)",
   "summary": "You configure an index sort and a parent field, add a block (a child and its parent) with addDocuments, then add one document that IndexWriter rejects with IllegalArgumentException because a field's doc-values type conflicts with the block's, and call commit(). You expect the rejected document simply not to be added and the commit to keep the two block documents, as it does without a parent field (upstream test testFlushAfterInconsistentSchema). Instead commit() throws ArrayIndexOutOfBoundsException 'Index 2147483647 out of bounds for length 3' from the flush-time sort, IndexWriter closes itself and both block documents are lost.",
   "impact_class": "crash",
   "introduced_commit": "apache/lucene#12829 'Add support for index sorting with document blocks' (s1monw): df6bd25ce44ead0b38cffca6ef9bc3a9ce63dbea on main, backport 0aa88910ca9 on branch_9x [read]. It added IndexWriterConfig#setParentField and the parent-aware flush comparator in the same commit, so the trigger cannot be written before it and no bisect is possible [exec]",
   "introduced_date": "2024-01-11 (author date and main merge; branch_9x backport committed 2024-01-17)",
   "first_affected_version": "9.10.0 [exec]; 9.9.2, the last release before it, has no IndexWriterConfig#setParentField, so the trigger cannot be written (the repro does not compile) [exec]",
   "affected_versions": "[exec] the minimal JUnit fails on every release from 9.10.0 to 10.6.0 (9.10.0, 9.11.0, 9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2 and 10.6.0 from the published jars, commit 4ae946e5a9b) and on main 645d4fe14a20 with -ea, and also with -da on 9.10.0, 9.12.3, 10.6.0 and main; the independent reproduction's independent test fails on main (-ea and -da), 10.6.0, 10.5.2 and 9.12.3 (-da). Released in 10.6.0 (the tag releases/lucene/10.6.0 exists: e29d290eeb05, peels to 4ae946e5a9b). 10.4.0 (before #15960 moved the parent field into IndexingChain) and 10.5.0 (after it) fail the same way. Not new in 10.6. [read] not fixed upstream: no commit after 645d4fe on main (716d6f216f5) or branch_10_6 (7e5aec4370e) touches the comparator, DocumentsWriterPerThread or IndexSorter.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1050.html",
   "repro": "repro/LFV-1050/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-256",
   "priority": "medium",
   "priority_rank": 160,
   "novelty": "known",
   "withheld": false,
   "area": "codecs / per-field doc values and vectors formats (PerFieldDocValuesFormat, PerFieldKnnVectorsFormat attribute bookkeeping)",
   "title": "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",
   "summary": "You write a codec whose per-field doc-values (or vectors) hook returns another per-field format, for example the default codec's docValuesFormat(), add one document and close the writer. You expect the writer to reject the configuration, as PerFieldPostingsFormat does ('cannot embed PerFieldPostingsFormat inside itself'), or the committed index to open. Instead the commit succeeds, because the nested writer silently overwrote the outer per-field attributes with its own format name and suffix, and DirectoryReader.open fails with 'No sub-file with id _Lucene90_0.dvm' (vectors: _Lucene99HnswVectorsFormat_0.vemf) since the files were written as _0_PerFieldDV40_0_Lucene90_0.*.",
   "impact_class": "index unusable",
   "introduced_commit": "doc values (all assertion settings): 63dfba4c7d81a019a4008777beace0d391987ceb on master and its branch_7x commit e8bfa67716368ff3ad670a63d4a8935c6a989cac (the one 7.7.0 contains), LUCENE-8601 'Adding attributes to IndexFieldType' (now apache/lucene#9647; a JIRA patch by muralikpbhat, committed by mikemccand), which removed the write-time IllegalStateException 'found existing value for PerFieldDocValuesFormat.format' so that attributes survive merges; that check had rejected the nested configuration as a side effect, and the issue never discusses nesting [read]; vectors: e2788336d49c56050b3cea5944008bcffe35dcb1 (apache/lucene#114, LUCENE-9905, by msokolov) added the per-field vectors format by copying the post-LUCENE-8601 doc-values logic, with no nesting guard, and e9339253f5e (apache/lucene#176, by jtibshirani) removed a forName lookup that would have made the default-codec trigger fail at write; both before 9.0.0 [read]; an earlier, assertions-disabled-only window for doc values: 1120e46961b (trunk) / 49684b82701 (branch_4x), LUCENE-5189, replaced the original 'cannot embed' throw (5cbaddcbc7f, LUCENE-4547, 4.2.0) with outer + '_' + inner suffix concatenation and an assert, and 35db73c39ee / 33bdf278cba (LUCENE-5969 'assert -> check') made it an IllegalStateException again in 5.0 [read]",
   "introduced_date": "2019-01-03 (master 63dfba4c7d8) and 2019-01-04 (branch_7x e8bfa677163, released in 7.7.0) for doc values; 2021-05-06 (e2788336d49) and 2021-06-08 (e9339253f5e) for vectors; the earlier -da-only doc-values window opened 2013-09-15 / 2013-11-01 (LUCENE-5189) and closed 2014-09-27 / 2014-10-05 (LUCENE-5969)",
   "first_affected_version": "7.7.0 for doc values, with -ea and -da [exec] (5.0.0 to 7.6.0 reject the configuration at write [exec]); 9.0.0 for vectors, the first release with the per-field vectors format [exec]; also 4.6.0 to 4.10.4 for doc values with assertions disabled only [exec]",
   "affected_versions": "doc values: 7.7.0 through 10.5.2 (the last release before 10.6.0) and main ea57360912ed, -ea and -da [exec]; doc values 4.6.0 to 4.10.4 with -da only [exec]; vectors: 9.0.0 through 10.5.2 and main, -ea and -da [exec]; not affected: doc values 4.2.0 to 4.5.1 (rejected with 'cannot embed PerFieldPostingsFormat inside itself') and 5.0.0 to 7.6.0 (rejected with 'found existing value for PerFieldDocValuesFormat.format') [exec], vectors before 9.0.0 (no API), postings never; intermediate releases were not all executed (inferred from a per-tag scan of the guard code) and the history clone lacks the 8.9 to 8.11 tags (covered by executing 8.11.4); not fixed upstream: the code is unchanged on main and no open apache/lucene PR adds a nesting check (all 413 open PRs scanned by touched file, 2026-10-26); executed on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/13257",
    "https://github.com/apache/lucene/issues/16891",
    "https://issues.apache.org/jira/browse/LUCENE-8601",
    "https://github.com/apache/lucene/issues/9647",
    "https://github.com/apache/lucene/issues/6253",
    "https://issues.apache.org/jira/browse/LUCENE-5189"
   ],
   "doc": "",
   "repro": "repro/LFV-256/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-615",
   "priority": "medium",
   "priority_rank": 161,
   "novelty": "known",
   "withheld": false,
   "area": "core index / IndexUpgrader (command line and default-config upgrade path); IndexWriter index-sort validation",
   "title": "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",
   "summary": "You run Lucene's documented upgrade tool (java ... org.apache.lucene.index.IndexUpgrader indexDir, or new IndexUpgrader(dir).upgrade()) on an index that has an index sort, for example Lucene's own backward-compatibility fixture sorted.9.10.0.zip, and expect only the segment format to change. Instead the tool rewrites the old segments with a writer whose config has no sort, so the new segment records indexSort=null: all 50 documents survive, but the sort is gone for good, and the application's IndexWriter configured with the original sort, which opened the index before, now throws 'cannot change previous indexSort=null ... to new indexSort=<long: \"dateDV\">!'. On an index with a parent field or a soft-deletes field, the same default tool throws IllegalArgumentException and cannot upgrade the index at all.",
   "impact_class": "index unusable",
   "introduced_commit": "54fa7dfd271f7fe3bc8da2cfcd165e21e76e1804, the LUCENE-6766 'initial patch' ('Make index sorting a first-class citizen', by Mike McCandless) on the index_sort feature branch. It was merged to master in d715210467a4 (first release 7.0.0) and backported to branch_6x as fdc220eeb423 .. ea26dd5855ec (first release 6.2.0). It added IndexWriterConfig#setIndexSort, validateIndexSort with its 'if (indexSort != null)' guard, and the merged SegmentInfo that takes config.getIndexSort(). Evidence [read]: git blame of the guard and git log -S on the merged SegmentInfo constructor in the history clone. Bounded by execution [exec]: 6.1.0 lacks the API (compile error), and 6.2.0 and later lose the sort. The bare config itself is older: IndexUpgrader dates from LUCENE-3082 (600a50bb2ae8, 2011, 3.2), and its default constructors have used new IndexWriterConfig(null) since LUCENE-5871 (872bd9145cd9, 2014). It became a defect only when the index gained settings that every writer must repeat. Companion symptoms: the soft-deletes rejection comes from LUCENE-8335 (branch_7x 67b6593e7adb, master e7a0a12926c3, first release 7.4.0) and the parent-field rejection from apache/lucene#12829 (main df6bd25ce44e, branch_9x 0aa88910ca9a, first release 9.10.0). No later commit to IndexUpgrader or UpgradeIndexMergePolicy deals with sort, soft deletes or parent fields.",
   "introduced_date": "2016-05-04 (LUCENE-6766 authored; on master 2016-05-13; on branch_6x 2016-06-11). Companion symptoms: 2018-06-04 (soft-deletes field) and 2024-01-11 (parent field)",
   "first_affected_version": "6.2.0 [exec]. 6.2.0 is the first release with index sorting in core; on 6.2.0 itself an ordinary upgrade cannot trigger it, because no older release writes a sort. 6.2.1 is the first release that loses the sort on a normal older-to-newer upgrade (of a 6.2.0 index) [exec]. Soft-deletes symptom: 7.4.0 [exec]. Parent-field symptom: 9.10.0 [exec].",
   "affected_versions": "Every release from 6.2.0 to 10.6.0 (10.6.0 by reading), and main a9779ef3c193; it was never fixed. Sort loss executed on 6.2.0 (downgrade only), 6.2.1, 6.4.2, 6.5.0, 6.6.6, 7.0.0 (-ea and -da), 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) [exec]; the releases in between share the unchanged code path [read]. What the application's writer configured with the sort does afterwards: on 6.2.0 to 6.4.2 it opens, so the loss is fully silent; on 6.5.0 to 7.7.3 it throws CorruptIndexException 'segment not sorted with indexSort=null' (LUCENE-7579); from 8.0.0 to main it throws IllegalArgumentException 'cannot change previous indexSort=null ...' (LUCENE-8505) [exec]. Soft-deletes rejection executed on 7.4.0, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main; parent-field rejection on 9.10.0, 9.12.3, 10.0.0, 10.5.2 and main [exec]. Not affected: 6.1.0 and earlier (API absent; compile error [exec]). The branch_10_6 and branch_10x heads have the same code [read]. IndexUpgrader.java, UpgradeIndexMergePolicy.java, IndexWriter.java and FieldInfos.java are identical on upstream main a95c754ee003 (2026-10-26).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16809",
    "https://github.com/apache/lucene/issues/16810",
    "https://issues.apache.org/jira/browse/LUCENE-6766",
    "https://github.com/apache/lucene/issues/7824",
    "https://issues.apache.org/jira/browse/LUCENE-9888",
    "https://github.com/apache/lucene/issues/10927"
   ],
   "doc": "",
   "repro": "repro/LFV-615/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-580",
   "priority": "medium",
   "priority_rank": 162,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriterConfig and IndexWriter configuration (creation-only settings re-read from the caller's config object)",
   "title": "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",
   "summary": "You create an IndexWriter from an IndexWriterConfig and later call a setter such as setIndexSort, setParentField, setSoftDeletesField or setCodec on that same config object, expecting no effect, because the IndexWriterConfig class javadoc says that once the writer has been created 'changes to this object will not affect the IndexWriter instance'. Instead IndexWriter has kept the caller's object since 4.9 and reads these settings again for every new segment, so new segments get the new sort, parent field, soft-deletes field or codec. forceMerge then fails with 'cannot change index sort from <long: \"a\"> to <long: \"b\">' or 'expected parent doc field to be \"_parent \" across all segments' and closes the writer, and with a late soft-deletes field a document that was never deleted vanishes after an unrelated delete (numDocs 0, expected 1).",
   "impact_class": "index unusable",
   "introduced_commit": "43be0a77b5efbd69c06eb7e692a257163a98c9b8 (trunk, svn r1598489) and its branch_4x backport a7994df8c5e15404ddb7c97dcb9b5097a9f83b34 (svn r1598492, shipped in 4.9.0): LUCENE-5708 'Remove IndexWriterConfig.clone' (GitHub issue #6770, mikemccand), which changed the IndexWriter constructor from 'config = new LiveIndexWriterConfig(conf);' to 'config = conf;' and removed the LiveIndexWriterConfig copy constructor, without changing the IndexWriterConfig class javadoc, written by LUCENE-4132 for 4.0.0 when IndexWriter still cloned the config [exec]. The setting-specific manifestations start with their setters: setIndexSort 6.2.0 (LUCENE-6766), setSoftDeletesField 7.4.0 (LUCENE-8233), setParentField 9.10.0 (GITHUB#12829)",
   "introduced_date": "2014-05-30",
   "first_affected_version": "4.9.0 [exec] (late setCodec reaches the writer); per setting [exec]: index sort from 6.2.0 (6.2.0-6.4.0 merge silently into the late sort; from 6.5.0 the merge throws), soft-deletes field from 7.4.0, parent field from 9.10.0; not affected: 4.5.0 and 4.8.1 [exec], 3.1-4.4.0 [read]",
   "affected_versions": "every release from 4.9.0 to 10.5.2 (the last release before 10.6.0) and main a9779ef3c193 (the previous main ea57360912ed has the same code [read]). [exec] the portable main() probe (codec, index sort, soft deletes, parent field; reflection for setters that older versions lack) fails on 4.9.0 (also -da), 4.10.4, 5.0.0, 6.1.0, 6.2.0, 6.3.0, 6.4.0, 6.5.0, 6.6.6, 7.0.0, 7.3.1, 7.4.0, 8.11.4, 9.9.2, 9.10.0, 9.12.3, 10.5.2 and main, and its no-change control passes on 4.8.1, 4.9.0, 6.2.0, 7.4.0, 9.10.0, 9.12.3, 10.5.2 and main; the finder's JUnit fails 4 of 4 on 9.10.0, 9.12.3, 10.5.2 and main (main also -da); the independent reproduction's JUnit fails 5 of 10 with all 5 controls passing on 9.12.3, 10.5.2 and main (main also -da). [read] releases between the executed ones are counted affected from tag ancestry and the unchanged 'config = conf;' line. Not fixed upstream [read]. Executed on aarch64 with JDK 25 only",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/10365",
    "https://issues.apache.org/jira/browse/LUCENE-9325",
    "https://github.com/apache/lucene/issues/15480",
    "https://github.com/apache/lucene/issues/15481",
    "https://issues.apache.org/jira/browse/LUCENE-5708",
    "https://issues.apache.org/jira/browse/LUCENE-2294"
   ],
   "doc": "",
   "repro": "repro/LFV-580/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1042",
   "priority": "medium",
   "priority_rank": 163,
   "novelty": "known",
   "withheld": false,
   "area": "luke / IndexTools write operations (IndexToolsImpl.optimize and addDocument through IndexUtils.createWriter) behind Tools > Optimize and Documents > Add document; IndexWriter index-sort validation",
   "title": "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",
   "summary": "You open a sorted index (written with IndexWriterConfig.setIndexSort) in Luke with the default options and run Tools > Optimize or Documents > Add document, and you expect a force merge or one more document, with the index's sort unchanged. Instead Luke opens its IndexWriter with a config that has no index sort, which IndexWriter accepts on a sorted index, so the merged or flushed segment records indexSort=null and Luke reports success. Afterwards the application's own IndexWriter, configured with the same sort, refuses to open the index: IllegalArgumentException 'cannot change previous indexSort=null (from segment=_2(11.0.0):c2) to new indexSort=<long: \"ts\">'.",
   "impact_class": "index unusable",
   "introduced_commit": "3a78c1999a8716669c574448b2b07c0f63cbb39c (master; LUCENE-2562 'Make Luke a Lucene/Solr Module', migrated as apache/lucene#3636, by Tomoko Uchida; no PR, committed under the JIRA issue), backported to branch_8x as 9915056cbc8380658ae2cf4e413969642d96a815. The import added IndexUtils.createWriter (new IndexWriterConfig(analyzer) with only the compound-file option, the infoStream and the deletion policy) and its IndexToolsImpl callers [read]. Boundary [exec]: 8.0.0 has no Luke module (compile error), 8.1.0 fails. The bare config is older than the import: the standalone Luke repository (DmitryKey/luke c8c6e1765524, 2017-12-17) already had it, and its luke-swing-7.7.0 and luke-swing-8.0.0 releases fail the same test [exec]. Enabling core behaviour, not a defect by itself: since LUCENE-6766 (54fa7dfd271, 6.2.0) IndexWriter checks the index sort only when the config has one, and since LUCENE-8505 (2bad3c49851, 8.0.0) a sorted writer refuses any segment whose sort is null.",
   "introduced_date": "2019-04-10 (author date of 3a78c1999a8 on master and 9915056cbc8 on branch_8x); the createWriter code was first written on 2017-12-17 in the standalone Luke repository",
   "first_affected_version": "8.1.0 [exec]",
   "affected_versions": "[exec] fails on 35 releases: 8.1.0, 8.11.4, every release from 9.0.0 to 9.12.3 (21) and from 10.0.0 to 10.5.2 (12), and on main 645d4fe14a20 with -ea and -da (20 of 20 iterations with -da); 10.5.2 and 9.12.3 also with -da; the independent reproduction's own JUnit fails on main and 10.5.2 (-ea and -da) and on 9.12.3 (-da). [read] 8.1.1 to 8.11.3 (unchanged code: 8.1.1 to 8.8.1 contain the commit by tag containment, 8.8.2 to 8.11.3 lie between the executed 8.1.0 and 8.11.4 runs), 10.6.0 (its release-candidate revision branch_10_6 4ae946e5a9b) and branch_10x 657014b3c57 (createWriter identical to main; no Luke jar in the release-candidate jar set, so not executed). Upstream main a518d9ae1777 (2026-10-29) still has IndexUtils.java, IndexToolsImpl.java and validateIndexSort unchanged. Not affected: 8.0.0 and earlier (no Luke module). Not new in 10.6. Outside Lucene, the standalone luke-swing-7.7.0 (CorruptIndexException 'segment not sorted with indexSort=null') and luke-swing-8.0.0 releases fail too.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16809",
    "https://github.com/apache/lucene/issues/16810",
    "https://issues.apache.org/jira/browse/LUCENE-6766",
    "https://github.com/apache/lucene/issues/7824",
    "https://issues.apache.org/jira/browse/LUCENE-9888",
    "https://github.com/apache/lucene/issues/10927"
   ],
   "doc": "",
   "repro": "repro/LFV-1042/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-730",
   "priority": "medium",
   "priority_rank": 164,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter merge soft-delete accounting (mergeMiddle carry-over of soft deletes x OneMerge#wrapForMerge, OneMergeWrappingMergePolicy, SoftDeletesRetentionMergePolicy)",
   "title": "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)",
   "summary": "You set IndexWriterConfig#setSoftDeletesField and a merge policy whose OneMerge#wrapForMerge hides expired documents (its javadoc says a wrapper may 'add/remove fields or documents'), index two segments without hard deletes, and call forceMerge(1); you expect the merge to drop the expired document and succeed, as the same merge does without a soft-deletes field, or with one when the segment happens to hold a hard delete. Instead IndexWriter derives the carried-over soft deletes as getSoftDelCount() - wrappedReader.numDeletedDocs(), which counts each hidden live document as a dropped soft delete, so the count comes out -1 and the merge throws IllegalArgumentException 'invalid softDelCount=-1 (maxDoc=2)'. With SoftDeletesRetentionMergePolicy on top (one retained soft-deleted document) the merge silently commits softDelCount=0, so numDocs and IndexSearcher#count report 3 where 2 documents are live, CheckIndex reports 'actual soft deletes: 1 but expected: 0', and after the retention window the next merge of that segment throws 'invalid softDelCount=-1 (maxDoc=3)'.",
   "impact_class": "silent wrong results",
   "introduced_commit": "56cb42d200dd999342c4cd5c92fbfa271ba91153 on the main line (LUCENE-8569 'Never count soft-deletes if reader has no hard-deletes', apache/lucene-solr#502, migrated issue apache/lucene#9615, by s1monw, approved by mikemccand and jpountz; first released in 8.0.0) and its branch_7x backport 8f76c1b0ca64cd65e05330de9379fed44cfe6a8f (first released in 7.7.0) [exec]. Before it (7.4.0 to 7.6.0) mergeMiddle counted the surviving soft-deleted documents of every wrapped reader (code from LUCENE-8341 fe83838ec37 and LUCENE-8381 0ccd5d580d1), which is right for any wrapper",
   "introduced_date": "2018-11-20 (authored; committed 2018-11-21; the branch_7x backport the same days)",
   "first_affected_version": "7.7.0 [exec] (branch_7x backport); 8.0.0 [exec] is the first affected main-line release; 7.4.0, 7.5.0 and 7.6.0 pass [exec]; soft deletes first shipped in 7.4.0 (LUCENE-8233), so no earlier release can build the trigger",
   "affected_versions": "Every release from 7.7.0 through 10.6.0 (7.7.0-7.7.3 and every 8.x, 9.x and 10.x release; 10.6.0 by reading) and main a9779ef3c193 (unreleased 11.0); never fixed. [exec] 7.7.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main with -da, and 7.7.0, 8.0.0, 9.12.3, 10.5.2 and main with -ea: the same failures everywhere, the control passes (repro/src-pre9 variant before 9.1.0). [read] the other releases by tag containment of 8f76c1b0ca6 or 56cb42d200d and by the shortcut's assertion string in IndexWriter.class of every release jar 7.7.0-10.5.2 (absent in 7.4.0-7.6.0); 8.8.2-8.11.4 were released from the old lucene-solr branch_8x, covered by the bytecode marker and the 8.11.4 run. Upstream main a95c754ee003 (2026-10-26), branch_10x 657014b3c579 and branch_10_6 still contain the subtraction [read]. Executed on aarch64 Linux with JDK 25 only",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-730.html",
   "repro": "repro/LFV-730/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-161",
   "priority": "medium",
   "priority_rank": 165,
   "novelty": "known",
   "withheld": false,
   "area": "search / CachingCollector first-pass caching (CachingCollector, CachingCollectorManager)",
   "title": "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",
   "summary": "You run a query once through a CachingCollector or CachingCollectorManager that wraps a first-pass collector, see isCached() return true (the cache did not overflow), and replay the cached hits into a second collector, expecting the same result as running that collector on the query, which is what the javadocs and the grouping docs offer ('without re-running the query', 'hold all hits'). Instead the cache holds only the hits the first-pass collector let through: TopScoreDocCollectorManager(10, 1000), the IndexSearcher#search(Query, int) default, prunes non-competitive hits (even when the score-caching variant tells the searcher it needs COMPLETE), an index-order TopFieldCollector stops each segment early, and TotalHitCountCollector skips whole segments it can count from index statistics. In the repro, replaying into a hit counter sees 1001, 2 and 0 of 5000 matching documents, with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "65b70503ab16 (branch_4x, svn r1459408, merged from trunk 986444de446b, r1459400; LUCENE-4862 'Ability to terminate queries on a per-segment basis', GitHub mirror #5927, by jpountz; pre-GitHub, no PR) [read]; the getLeafCollector (then setNextReader) path followed with a5c3b88fe7ae (LUCENE-4858, mirror #5923, 2013-04-09, also 4.3.0). Later commits each added a trigger without changing CachingCollector [read]: 2034bb2f32d3 (LUCENE-8463, mirror #9509, 2018-11-12, 7.7.0: TopFieldCollector index-order early termination), 4fc5a872ded9 (LUCENE-4100, mirror #5172, 2017-12-07, 8.0.0: ScoreMode, with FilterCollector delegating scoreMode, so the no-score cache inherits TOP_SCORES), e983d391d71f (LUCENE-10620, PR #964, 2022-06-23, 9.3.0: Collector#setWeight, so a wrapped TotalHitCountCollector skips leaves via Weight#count), adbf9a9e0110 (PR #14709 'Speed up TermQuery', 2025-05-26, 10.3.0: BatchScoreBulkScorer drops hits below minCompetitiveScore in any score mode, which exposes the score cache), and 3afffeef5a8d (#16247 by gaobinlong, 2026-07-08, first released in 10.6.0: CachingCollectorManager, which inherits every mechanism). The CachingCollector code involved dates from LUCENE-3102 (2011, 3.2) and the LUCENE-5527 rewrite (85642f59ddf0, 2014, 5.0). Not a commit-level bisect: the parent of the introducing commit has no CollectionTerminatedException, and the 4.2.1/4.3.0 pair brackets it.",
   "introduced_date": "2013-03-21 (LUCENE-4862, termination path); later triggers 2013-04-09 (LUCENE-4858), 2017-12-07 (LUCENE-4100, TOP_SCORES), 2018-11-12 (LUCENE-8463), 2022-06-23 (LUCENE-10620), 2025-05-26 (#14709, score cache), 2026-07-08 (#16247, CachingCollectorManager, first released in 10.6.0)",
   "first_affected_version": "4.3.0 [exec] for CachingCollector (4.2.1 is the last release without it: CollectionTerminatedException does not exist there [exec]); the triggers grew: index-order TopFieldCollector from 7.7.0 [exec], TOP_SCORES pruning of the no-score cache from 8.0.0 [exec], TotalHitCountCollector leaf skipping from 9.3.0 [exec], score-cache pruning from 10.3.0 [exec]; CachingCollectorManager: 10.6.0 (released 2026-10-29; listed under 10.6.0 in CHANGES.txt)",
   "affected_versions": "every release from 4.3.0 to 10.5.2 and main ea57360912ed, with a growing set of triggers. [exec] the follow-up's history probes (public-API main() programs, one per API generation) fail on 4.3.0, 5.1.0, 5.5.5, 6.6.6, 7.6.0, 7.7.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.2.0, 9.3.0, 9.12.3, 10.0.0, 10.2.2, 10.3.0, 10.5.2 and main (-da too on 9.12.3, 10.5.2 and main), do not compile on 4.2.1 (API absent), and pass on main with the fix shadowed; on 10.3.0, 10.5.2 and main all six probed mechanisms lose hits (score cache 1001 of 5000, no-score TOP_SCORES 1001, index-order TopField 2, custom early termination 1, TotalHitCountCollector 0, custom leaf skip 0). The independent reproduction's JUnit fails 4 of its 4 manifestations on 10.5.2 and 10.3.0 and 3 of 4 on 10.2.2, 10.0.0 and 9.12.3 (score-cache case starts at 10.3.0); the finder's legacy JUnit (docs-only StringField) fails 4 on 10.5.2 and 10.3.0, 3 on 10.2.2 and 2 on 10.0.0 and 9.12.3; the intended-behaviour check's count-then-groups probe fails on main, 10.5.2 and 9.12.3; the CachingCollectorManager JUnit fails 4 of 5 on main and does not compile on 10.5.2 (class absent). [read] the releases between executed ones (code order in CachingCollector and IndexSearcher's exception handling unchanged); branch_10_6 and branch_10_7 not in the local clone, expected affected. The 4.x-7.x runs used JDK 25, not the JDK those releases supported. Not executed: the LUCENE-8059 index-sort-prefix trigger (7.2.0+), x86, concurrent slices and intra-segment partitions in the release probes.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15210",
    "https://github.com/apache/lucene/issues/15239",
    "https://github.com/apache/lucene/issues/14709",
    "https://github.com/apache/lucene/issues/16542",
    "https://github.com/apache/lucene/issues/5438",
    "https://issues.apache.org/jira/browse/LUCENE-4372"
   ],
   "doc": "",
   "repro": "repro/LFV-161/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-765",
   "priority": "medium",
   "priority_rank": 166,
   "novelty": "new",
   "withheld": false,
   "area": "facet / sampling (RandomSamplingFacetsCollector.createManager reduce, FacetsCollectorManager.reduceMatchingDocs)",
   "title": "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)",
   "summary": "You count facets on a sample of a large result set with RandomSamplingFacetsCollector.createManager(sampleSize, seed) on an IndexSearcher that has an executor, and expect what a one-slice search gives: about sampleSize sampled hits, taken at the rate sampleSize / totalHits that getSamplingRate() reports, so that amortizeFacetCounts estimates the real counts. Instead, with two or more slices the reduce fills the reduced collector's original hits from FacetsCollectorManager.reduceMatchingDocs, which calls each slice collector's getMatchingDocs(), the accessor RandomSamplingFacetsCollector overrides to return that slice's sample; the reduced collector then samples those samples again. The sample shrinks to about sampleSize^2 x numSlices / totalHits and every amortized count is low by the per-slice ratio, with no error: 2 segments of 1,024 matching docs with sampleSize 128 and one slice per segment give 16 sampled hits and an amortized count of 256 instead of 128 and 2,048, and default slicing on 2 segments of 262,144 docs with sampleSize 4,096 gives 64 sampled hits and 8,192 instead of 4,096 and 524,288.",
   "impact_class": "silent wrong results",
   "introduced_commit": "fafd6af004e0c39582043b797555d6eeb9aa7638, apache/lucene#13542 'Add support for intra-segment search concurrency' (javanna; closes #9721; not backported to branch_9x): it replaced the reduce over each collector's getOriginalMatchingDocs() (7ed0f3d7adb, LUCENE-10484 / #765, first released in 9.2.0, correct) with FacetsCollectorManager.reduceMatchingDocs(facetsCollectors), a new helper of the same commit that loops over the overridable, sampled getMatchingDocs() [exec]. A regression; the parent commit itself was not built",
   "introduced_date": "2024-09-10",
   "first_affected_version": "10.0.0 [exec]; 9.12.3, the last 9.x release, is correct [exec]; createManager first shipped in 9.2.0 with a correct reduce [exec]; 9.1.0 has no createManager [exec]",
   "affected_versions": "Every release from 10.0.0 to 10.5.2, 10.6.0 (by reading), and main a9779ef3c193; not fixed upstream. [exec] The finder's repro fails with identical numbers on all 12 releases 10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1 and 10.5.2 (-da also on 10.0.0 and 10.5.2) and on main (-ea and -da); the independent reproduction's own test fails on 10.0.0, 10.5.2 and main; the intended-behaviour check's probe fails on 10.5.2 and main. Not affected [exec]: 9.2.0 through 9.12.3 (19 releases; the 9.x API variant gives the same sample for 2 slices as for one), and 9.1.0 and older (no createManager). [read] RandomSamplingFacetsCollector.java is the same blob (32cda39b013) in fafd6af004e, in all 12 10.x releases, on the branch_10x, branch_10_6 and branch_10_5 heads (refs fetched 2026-10-24) and at main a9779ef3c193; no commit has touched it since fafd6af004e on main, branch_10x or branch_10_5 (GitHub commit history read 2026-10-27), and CHANGES.txt on upstream main a95c754ee00 has no fix entry.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-765.html",
   "repro": "repro/LFV-765/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-303",
   "priority": "medium",
   "priority_rank": 167,
   "novelty": "new",
   "withheld": false,
   "area": "facet / range facet counts (LongRangeCounter multi-valued path, exclusive and overlapping counters)",
   "title": "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",
   "summary": "You compute range facet counts over a multi-valued source, for example the distances from the user to each of a document's locations computed by your own MultiDoubleValuesSource, or doubles stored as raw bits in a SortedNumeric field and read with fromDoubleField or the DoubleRangeFacetCounts(String, ...) constructor. You expect each range to count every document that has at least one value in it, which is exactly what the range's own drill-down query finds. Instead, when a document's values arrive in descending order (a custom source in its natural order, or raw-bit doubles whenever the document has two or more negative values), the counter skips every later value that sorts below an interval it already counted for that document, so a document with distances {3.0, 0.5} is missing from '< 1 km' and '< 2 km'.",
   "impact_class": "silent wrong results",
   "introduced_commit": "d669ddebc538 (LUCENE-9946, PR #127 'Support multi-value fields in range facet counting', by GitHub gsmiller), released first in 8.10.0 through the lucene-solr branch_8x backport e1ffcb11d9c2 (PR #2507) [read]. The ascending-order shortcut came in during review (PR revision 923d35eb0cee 'optimize the bsearch for multi-valued cases', after rmuir asked about using the sortedness of SORTED_NUMERIC); the PR's earlier search from interval 0 did not depend on order. Exposure widened by 82703757fe05 (LUCENE-10245, PR #543, 9.1.0), which fed MultiLong/MultiDoubleValues, whose nextValue() promises no order, into the unchanged counter. A shortcut that was valid while SortedNumericDocValues was the only multi-valued input, not a later regression",
   "introduced_date": "2021-05-30 (d669ddebc538, -0700; 2021-05-31 UTC); branch_8x backport 2021-06-24; exposure widened 2022-01-10 (82703757fe05)",
   "first_affected_version": "8.10.0 [exec] (DoubleRangeFacetCounts(String, ...) over raw-bit doubles with two or more negative values per document); 9.1.0 [exec] for the custom-source and fromDoubleField/fromFloatField/fromField(decoder) triggers",
   "affected_versions": "String-constructor raw-bit trigger: every release from 8.10.0 to 10.6.0 (8.10.0, 8.10.1, 8.11.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2, and 10.6.0 by reading) and main ea57360912ed; source-based triggers: every release from 9.1.0 to 10.6.0 (10.6.0 by reading) and main [exec]; not affected: 8.9.0 and earlier, where multi-valued range faceting does not exist (IllegalStateException on the SORTED_NUMERIC field) [exec]; 10.6.0 (released 2026-10-29) very likely affected (LongRangeCounter.java unchanged on upstream main and branch_10x as of 2026-10-26) but not verified [read]; not fixed anywhere",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-303.html",
   "repro": "repro/LFV-303/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-433",
   "priority": "medium",
   "priority_rank": 168,
   "novelty": "known",
   "withheld": false,
   "area": "facet / LongValueFacetCounts (count-all constructors with a LongValuesSource or MultiLongValuesSource)",
   "title": "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)",
   "summary": "You delete or update documents and then count all values of a long field with new LongValueFacetCounts(\"field\", LongValuesSource.fromLongField(\"field\"), reader), or with a MultiLongValuesSource, and expect what both constructors' javadoc promises, 'the same result as computing facets on a MatchAllDocsQuery', which sees only live documents. Instead the two value-source count-all loops visit every doc id below maxDoc and never check getLiveDocs(), so deleted documents are counted: on upstream's own testCountAll index (10 documents, 1 deleted) you get value=10 and '0 (5)' instead of value=9 and '0 (4)', and after updateDocument the replaced value is still listed as a label. LUCENE-10070 fixed exactly this in 8.11.0 for the field-based count-all constructor of the same class, but left the value-source paths out.",
   "impact_class": "silent wrong results",
   "introduced_commit": "de5c68b5f813f8069ad7524bd772514e1f818f30 (LUCENE-7927 'Add facets impl to count unique numeric values', by mikemccand, committed as a JIRA patch with no GitHub PR, migrated issue #8976; branch_7x backport 4b48608574d9da0152288b103c8ceea940194062, identical file) for the LongValuesSource path [read]; 82703757fe05 (LUCENE-10245, PR #543 by gsmiller; branch_9x 60b499b907d) copied the same unfiltered loop for the MultiLongValuesSource path [read]. Not a regression: the loop and the 'same result as ... MatchAllDocsQuery' javadoc arrived in the same commit. In between, LUCENE-10070 (#293 by goankur, deff5a1f5aa, merged 2021-09-17; 8.x backport lucene-solr#2584) added the live-docs check only to countAll(IndexReader, String) [read]",
   "introduced_date": "2017-08-29 (LongValuesSource path, de5c68b5f813); 2022-01-10 (MultiLongValuesSource path, 82703757fe05); the incomplete fix LUCENE-10070 was merged 2021-09-17",
   "first_affected_version": "7.1.0 [exec] for the LongValuesSource constructor (7.0.1 has no LongValueFacetCounts: compile error [exec]); 9.1.0 [exec] for the MultiLongValuesSource constructor (9.0.0 has no MultiLongValuesSource: compile error [exec]). From 7.1.0 to 8.10.x the field-based count-all also counted deleted documents (that was LUCENE-10070; executed: wrong in 8.10.1, correct in 8.11.0), so from 8.11.0 on the value-source paths are the unfixed remainder",
   "affected_versions": "every release from 7.1.0 through 10.6.0 (10.6.0 by reading) and main ea57360912ed (LongValuesSource path) and every release from 9.1.0 through 10.6.0 (10.6.0 by reading) and main (MultiLongValuesSource path); no release has a fix. [exec] [read]; not affected: 7.0.1 and older, where the class does not exist [exec]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/11108",
    "https://issues.apache.org/jira/browse/LUCENE-10070",
    "https://github.com/apache/lucene/issues/293",
    "https://github.com/apache/lucene/issues/282",
    "https://github.com/apache/lucene/issues/263",
    "https://github.com/apache/lucene/issues/2577"
   ],
   "doc": "",
   "repro": "repro/LFV-433/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-437",
   "priority": "medium",
   "priority_rank": 169,
   "novelty": "known",
   "withheld": false,
   "area": "facet / sampling (RandomSamplingFacetsCollector: sampling rate vs bin size in amortizeFacetCounts and getSamplingRate)",
   "title": "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)",
   "summary": "You sample facet counts with RandomSamplingFacetsCollector and sampleSize 1000 on a query with 1999 hits, call amortizeFacetCounts to scale the sampled counts back up, and expect estimates of the true counts; here the sample happens to contain every hit, so the right answer is the exact counts 667/666/666. Instead you get 1333/1331/1331 and a dimension total of 3996 for 1999 hits, with no error: the collector computes samplingRate = 1000 / 1999 = 0.50025 but samples one hit per bin of (int) (1 / samplingRate) = 1 hit, and it amortizes, and reports through getSamplingRate(), with the untruncated rate. In general the counts are too high by totalHits / (sampleSize * binSize), between 1 and 2, worst just below twice the sample size.",
   "impact_class": "silent wrong results",
   "introduced_commit": "e50b392f467cf1e3dea3999b5449c48742cf2084 (LUCENE-5476 'add RandomSamplingFacetsCollector', committed by shaie, svn r1579594; a JIRA patch by Rob Audenaerde with Gilad Barkai, no GitHub PR, migrated issue #6539); branch_4x backport 4d26f04cedcd (svn r1579598) is the copy released in 4.8.0 [read]. Not a regression: the defect arrived with the class, and no later commit to the file touched this arithmetic",
   "introduced_date": "2014-03-20",
   "first_affected_version": "4.8.0 [exec] (fails with the same numbers as main); 4.7.2 has no RandomSamplingFacetsCollector [exec]",
   "affected_versions": "4.8.0 through 10.5.2 and main ea57360912ed, every release since the class was added; not fixed upstream (upstream main and branch_10x have no commit to RandomSamplingFacetsCollector.java after 2024-09-10, read 2026-10-26). [exec] The finder's JUnit (the same data, sizes, seed and assertions in four API-spelling variants) fails with identical numbers on 4.8.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.2.0, 9.12.3 (-ea, -da), 10.0.0, 10.5.2 (-ea, -da) and main (-ea, -da); the independent reproduction's JUnit fails 2 of 3 on main (-ea, -da), 10.5.2 (-ea, -da) and 9.12.3. [read] The five defect lines are verbatim at the tags 4.8.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.8.1, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and on main; the releases in between were checked by source history only. Not affected: 4.7.x (no such class) [exec]; the separate, older sampling package of 4.6.1 and earlier was not examined. Old releases ran on JDK 25 with SHA-1-checked jars",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-5476",
    "https://github.com/apache/lucene/issues/6539",
    "https://github.com/apache/lucene/issues/16847",
    "https://github.com/apache/lucene/issues/11520",
    "https://github.com/apache/lucene/issues/765",
    "https://issues.apache.org/jira/browse/LUCENE-10484"
   ],
   "doc": "",
   "repro": "repro/LFV-437/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-539",
   "priority": "medium",
   "priority_rank": 170,
   "novelty": "new",
   "withheld": false,
   "area": "facet / taxonomy association facets (TaxonomyFacetFloatAssociations value-source path, FloatTaxonomyFacets#updateValueFromRollup count roll-up)",
   "title": "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)",
   "summary": "You index documents with a FacetField in a dimension declared hierarchical (FacetsConfig.setHierarchical(\"d\", true)), for example d/a/x with weight 7 and d/a/y with weight 2, and sum a per-document DoubleValuesSource per label with TaxonomyFacetFloatAssociations; you expect label a under d to report value 9 and count 2, the 'Number of occurrences for this label' that FastTaxonomyFacetCounts reports for the same hits. Instead getTopChildren and getAllChildren report a (9.0) with count 4, because FloatTaxonomyFacets#updateValueFromRollup first calls super.updateValueFromRollup, which rolls up the counts of the whole sub-tree, and then its own rollup(childOrdinal), which calls updateValueFromRollup again for every descendant, so the sub-tree counts are added once more at each ancestor level. Values and leaf counts are right; only LabelAndValue.count of labels with descendants is inflated, and the deeper the tree, the larger the overcount.",
   "impact_class": "silent wrong results",
   "introduced_commit": "9ba4af7b883c1c5cd3453dc60d8024851e658367 (apache/lucene#12966 'Reduce duplication in taxonomy facets; always do counts', by @stefanvodita, merged to main; branch_9x backport 42884fab46ded7c939c02668bfbdcdf8f05949a9, #13358, the line that shipped first) [read]. It added the super call to FloatTaxonomyFacets#updateValueFromRollup, whose own private rollup(int) already recursed through the virtual updateValueFromRollup. The counts became user-visible with #13414 ('Allow users to retrieve counts from taxo association facets', main b3dc9153bb5d, branch_9x 09302078a6eb), which added LabelAndValue.count filled from getCount(ord); before that the counts were used only for count > 0 checks, which the inflation cannot change.",
   "introduced_date": "2024-04-05 (#12966 on main); 2024-05-14 (#13358 on branch_9x); counts exposed 2024-05-29 (#13414)",
   "first_affected_version": "9.11.0 [exec] (released 2024-06, the first release with both #13358 and #13414); not affected: 9.10.0 [exec]; first 10.x release 10.0.0 [exec]",
   "affected_versions": "every release from 9.11.0 to 9.12.3 and from 10.0.0 to 10.5.2, plus main ea57360912ed; never fixed. [exec] the finder's JUnit, unchanged, fails with count 4 instead of 2 (value 9.0 right) on 9.11.0, 9.11.1, 9.12.0, 9.12.1, 9.12.2, 9.12.3 (-ea and -da), 10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 (-ea and -da) and main (-ea and -da); the independent reproduction's JUnit fails 4 of 4 on main, 10.5.2, 9.12.3 and 9.11.0. [read] FloatTaxonomyFacets.java is unchanged on upstream main since 2024-05-27 (#13422, import only), and upstream main, branch_10x, branch_10_6 and branch_9_12 still have the double roll-up (2026-10-26). On 9.11.0-9.12.x only, the deprecated TaxonomyFacetCounts(OrdinalsReader, ...) also reports count 4 with value 2 for the same data [exec], because IntTaxonomyFacets#updateValueFromRollup has the same shape; that class was removed in 10.0.0, and on 10.x/main no in-tree class rolls IntTaxonomyFacets up",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-539.html",
   "repro": "repro/LFV-539/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-234",
   "priority": "medium",
   "priority_rank": 171,
   "novelty": "known",
   "withheld": false,
   "area": "grouping / GroupingSearch (all-groups and all-group-heads passes)",
   "title": "GroupingSearch.setIgnoreDocsWithoutGroupField(true) is applied only to the first pass, so totalGroupCount, getAllMatchingGroups() and getAllGroupHeads() still include the null group",
   "summary": "You build a GroupingSearch with setIgnoreDocsWithoutGroupField(true) and setAllGroups(true) or setAllGroupHeads(true), and some documents that match your query have no value in the group field. You expect those documents to form no group at all, as the setter's javadoc says ('ignore documents that don't have the group field instead of putting them in a null group'), so that totalGroupCount, documented as usable 'for accurate pagination', equals the number of groups that can be returned. Instead only the returned top groups honour the flag: totalGroupCount and getAllMatchingGroups() still count the null group (3 instead of 2 in the repro), and getAllGroupHeads() still marks the best document without the field as a group head.",
   "impact_class": "silent wrong results",
   "introduced_commit": "a4ebe984087c (GITHUB#15167 'FirstPassGroupingCollector supports ignoring docs without group field' by gaobinlong, merged by romseygeek, main) and its branch_10x backport 898d38a4fd37, which the 10.4.0 release contains [read]. The PR added the option and wired it into GroupingSearch for the first pass only; #15557 and #15565 (AllGroupsCollectorManager, AllGroupHeadsCollectorManager) and #16247 (3afffeef5a8d, the collector-manager rewrite of GroupingSearch) carried the omission forward. Release-granularity bisection only; none is needed below that, because the bug cannot predate the setter.",
   "introduced_date": "2025-10-06 (#15167 merged into main at 14:56:59Z; branch_10x backport the same day; listed under Lucene 10.4.0 in CHANGES.txt)",
   "first_affected_version": "10.4.0 [exec] (the release that added setIgnoreDocsWithoutGroupField; 10.3.2 and 9.12.3 do not have the option [exec])",
   "affected_versions": "10.4.0, 10.5.0, 10.5.1, 10.5.2 and main ea57360912ed [exec]: the finder's JUnit fails on all five (10.4.0, 10.5.2 and main also with -da; history runs and the intended-behaviour check re-runs), the independent reproduction's 7-test suite fails 5 of 7 on main, 10.5.2 and 10.4.0 with -ea and -da; not affected: every release up to 10.3.2 and all of 9.x, because the option does not exist there (9.12.3 and 10.3.2 executed: compile error), and a flag-off control passes on 9.12.3, 10.3.2, 10.4.0, 10.5.2 and main; 10.6.0 not executed (not on Maven Central on 2026-10-26), affected by inference from main's code [read]; not fixed upstream on main, branch_10x or branch_10_6 as of 2026-10-26 [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15167",
    "https://github.com/apache/lucene/issues/15557",
    "https://github.com/apache/lucene/issues/15565",
    "https://github.com/apache/lucene/issues/15574",
    "https://github.com/apache/lucene/issues/15936",
    "https://github.com/apache/lucene/issues/16247"
   ],
   "doc": "",
   "repro": "repro/LFV-234/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-414",
   "priority": "medium",
   "priority_rank": 172,
   "novelty": "known",
   "withheld": false,
   "area": "grouping / range group selectors (LongRangeGroupSelector, DoubleRangeGroupSelector) on scorer-less collection paths: the GroupingSearch score-less cache replay and the DistinctValuesCollector value selector",
   "title": "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",
   "summary": "You group a two-segment index (prices 5, 15, 25 | 35, 45, 55) into price ranges with GroupingSearch and new LongRangeGroupSelector(price, new LongRangeFactory(0, 20, 60)), sort by a field, and turn on the documented second-pass cache without scores, setCaching(100, false); you expect the same groups as without the cache: LongRange(0, 20) -> docs 0, 1, LongRange(20, 40) -> 2, 3, LongRange(40, 60) -> 4, 5. Instead every release from 8.6.0 to 10.5.2 returns LongRange(0, 20) -> none, LongRange(20, 40) -> 0, 3 and LongRange(40, 60) -> 1, 2, 4, 5 with no error (the first segment's documents are grouped by the second segment's prices), 10.6.0 (by reading) and main throw NullPointerException, and DistinctValuesCollector with a range selector as its value selector throws NullPointerException in every version; DoubleRangeGroupSelector behaves the same. The cause is that both range selectors fetch their per-segment values only in setScorer(), while the score-less cache replay and DistinctValuesCollector's per-group collector call setNextReader and advanceTo on the selector but never setScorer.",
   "impact_class": "silent wrong results",
   "introduced_commit": "7c350d22c7070acf362fb4f477e6797f2711c910 (LUCENE-7889 'Allow grouping on Double/LongValuesSource', PR apache/lucene-solr#1484 by romseygeek, no reviews or comments; migrated issue apache/lucene#8940; branch_8x backport 5e62c42c5f304eee7b5695f97f02a2aea7d00366) [read] [exec]. Born with the feature, not a regression: the same commit added the abstract GroupSelector.setScorer and forwarded it only from the first- and second-pass grouping collectors. Enabling commit: LUCENE-9348 (0c58687a978 / branch_8x 5fd36c4d56b, 2020-05-04) made GroupingSearch(GroupSelector) public, also first released in 8.6.0. Symptom change, released in 10.6.0 (2026-10-29): apache/lucene#16247 (3afffeef5a8 on main, d60e550b47f on branch_10x/branch_10_6, gaobinlong, merged 2026-07-08) builds one selector per pass from a Supplier, which turns the release-era silent wrong groups into a NullPointerException [exec]",
   "introduced_date": "2020-05-11",
   "first_affected_version": "8.6.0 [exec] (8.5.2, the last earlier release, has no range selectors: the repro does not compile [exec])",
   "affected_versions": "every release with the selectors before 10.6.0, 8.6.0 to 10.5.2 (all 49 releases executed with -ea; 8.6.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0 and 10.5.2 also with -da): silent wrong groups on the score-less caching path for both selectors and a NullPointerException on the DistinctValues path [exec]; main ea57360912ed: NullPointerException on both paths [exec]; 10.6.0 (released 2026-10-29 from branch_10_6): relevant files identical to main, so NullPointerException on both paths [read]. Not fixed upstream: main cf398bfb142c, branch_10x and branch_10_6 (2026-10-26) [read]. All runs on one aarch64 Linux host with JDK 25.0.3, release jars SHA-1-checked against Maven Central",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16247",
    "https://github.com/apache/lucene/issues/8940",
    "https://github.com/apache/lucene-solr/pull/1484",
    "https://issues.apache.org/jira/browse/LUCENE-7889",
    "https://github.com/apache/lucene/issues/16217",
    "https://github.com/apache/lucene/issues/4175"
   ],
   "doc": "",
   "repro": "repro/LFV-414/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-368",
   "priority": "medium",
   "priority_rank": 173,
   "novelty": "new",
   "withheld": false,
   "area": "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)",
   "title": "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)",
   "summary": "You mark facet dimensions a and b as multi-valued (FacetsConfig#setMultiValued, requireDimCount left at its default false), index one document with a=a1 and one with b=b1, search for the second document only and call getTopDims(10, 10), expecting [b], the same as getAllDims(10), as the Facets#getTopDims javadoc says. Taxonomy and SortedSetDocValues facets instead return [null, b] (with -ea, getTopDims throws AssertionError at Lucene's own 'assert facetResult != null'), and SSDV getTopDims(1, 10) returns [null], dropping b, the only dimension with a hit. For such dimensions getTopDims uses the placeholder value -1 without checking for hits, the admission test 'value != 0' lets -1 through, and the per-dimension result of a dimension without hits is null.",
   "impact_class": "silent wrong results",
   "introduced_commit": "7c33f04d3746f855479da5177df8f19b6fdbbe84 (main, apache/lucene#747 'LUCENE-10325: Add getTopDims functionality to Facets', by Yuti-G, merged by gsmiller; issue #11361), first released through the branch_9x backport 77ccf2fb359ee926a3776ec4a78b2c0d95ee45fb (#773) in 9.2.0: it added Facets#getTopDims together with the SortedSetDocValuesFacetCounts override, whose 'dimCount != 0' admission already let the -1 placeholder of a hit-less multi-valued dimension through. Copies of the same logic: ConcurrentSortedSetDocValuesFacetCounts ef43242d77a (#777; branch_9x #889, 87655fd015c), 9.2.0; taxonomy facets got the same admission in #779 and #806 (main) and #889 (branch_9x), 9.2.0, and the null-element form of this bug from LUCENE-10585 (#915, 8db1e41fc07; branch_9x 075f5103e9a), 9.3.0, which made getTopChildren and getAllDims return null for such a dimension but left the getTopDims admission unchanged; #12966 (9ba4af7b883) moved the code into TaxonomyFacets and kept it. [read]",
   "introduced_date": "2022-03-28 (#747 merged 22:54:07Z; backport #773 merged 2022-03-29T00:06:38Z); the concurrent SSDV and taxonomy overrides 2022-05-13 (#777, #779, #806, #889); the taxonomy null-element form 2022-05-29 (#915)",
   "first_affected_version": "9.2.0 [exec] (the first release with Facets#getTopDims): SortedSetDocValuesFacetCounts and ConcurrentSortedSetDocValuesFacetCounts return the null element there (no AssertionError with -ea yet; the assert came with LUCENE-10585 in 9.3.0); taxonomy facets from 9.3.0 [exec] (in 9.2.0 taxonomy getAllDims also listed the hit-less dimension with value -1 and no children, so getTopDims agreed with it); 9.1.0 has no getTopDims [exec]",
   "affected_versions": "Every release from 9.2.0 to 10.5.2 (31 releases), 10.6.0 (by reading) and main ea57360912ed; not fixed upstream. [exec] follow-up: a 13-test JUnit (8 getTopDims cases over FastTaxonomyFacetCounts, TaxonomyFacetIntAssociations, TaxonomyFacetFloatAssociations, SortedSetDocValuesFacetCounts and ConcurrentSortedSetDocValuesFacetCounts, 3 getAllDims checks, 2 controls) fails 8 of 13 on every release from 9.3.0 to 10.5.2 and on main, with -ea (AssertionError inside Lucene) and with -da (null element); 9.2.0 fails 6 of 13 (SSDV and concurrent SSDV null elements; taxonomy getAllDims lists the hit-less dimension); the controls pass everywhere; the candidate fix makes 13 of 13 pass on main. The independent reproduction's JUnit fails 5 of 6 on main, 10.5.2 and 9.12.3 (-ea and -da) and on 9.3.0 and 9.2.0 (-da); the finder's JUnit fails on main (-ea, -da), 10.5.2, 9.12.3, 9.4.2 and 9.2.0 (-da). [read] branch_10x and branch_10_6 have TaxonomyFacets.java and AbstractSortedSetDocValueFacetCounts.java byte-identical to 10.5.2 (not executed); upstream main cf398bfb142c (2026-10-26) still has the -1 assignment, the '!= 0' admission and the assert. All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-368.html",
   "repro": "repro/LFV-368/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-363",
   "priority": "medium",
   "priority_rank": 174,
   "novelty": "new",
   "withheld": false,
   "area": "facet / taxonomy facets (TaxonomyFacets#getTopDims, shared by FastTaxonomyFacetCounts and the int and float association facets)",
   "title": "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)",
   "summary": "You mark taxonomy facet dims as multi-valued, run a query and call getTopDims(1, 10), and expect the same as getAllDims(10).subList(0, 1), as the Facets#getTopDims javadoc says. When the winning dim is visited after the dim it pushes out of the internal top-dims queue (dim x with 2 hits, created first, and dim y with 1 hit, both with requireDimCount), Lucene returns 'dim=x value=1 childCount=1 y1 (1)' instead of 'dim=x value=2 childCount=2 x1 (1) x2 (1)', that is y's children and count under x's name. The queue-replacement branch sets bottomDim.dim and bottomDim.value but never bottomDim.dimOrd, and the children of multi-valued dims are then computed from that stale ordinal.",
   "impact_class": "silent wrong results",
   "introduced_commit": "57f8cb2fd6bcc0a27f89dc8c36b43bfd812ded46 (main, apache/lucene#779 'LUCENE-10488: Optimize Facets#getTopDims in IntTaxonomyFacets', by Yuti-G, approved by gsmiller) and f0ec226167230a42b27a4b946c9c0f74d0f0abfc (main, #806, the same block in FloatTaxonomyFacets); first released through the branch_9x backport 87655fd015ceef36c4210a0d20f1071068544fe4 (#889, gsmiller) in 9.2.0; issue #11524 (LUCENE-10488). [read]. Before it, taxonomy facets inherited the default Facets#getTopDims (a getAllDims prefix), which is correct. LUCENE-10585 (#915, 8db1e41fc07; branch_9x 075f5103e9a, 9.3.0) changed which dims take the stale-ordinal path; #12966 (9ba4af7b883) and #14761 (a7704f5242d) moved the code and kept the omission",
   "introduced_date": "2022-05-13 (#779 merged 22:54:32Z, #806 22:54:41Z, backport #889 23:41:13Z)",
   "first_affected_version": "9.2.0 [exec] (the first release with Facets#getTopDims, -ea and -da; there the affected dims are multi-valued dims with requireDimCount and hierarchical dims; from 9.3.0 every multi-valued dim, with or without requireDimCount, and no longer hierarchical single-valued dims); 9.1.0 has no getTopDims [exec]",
   "affected_versions": "Every release from 9.2.0 to 10.5.2 (31 releases), 10.6.0 (by reading) and main ea57360912ed; not fixed upstream. [exec] follow-up: a 9-test JUnit (6 eviction cases over FastTaxonomyFacetCounts and TaxonomyFacetFloatAssociations with a value source and with associations, 3 controls) fails 4 of 9 on all 31 releases and main with -ea, and also with -da on 9.2.0, 9.3.0, 9.12.3, 10.5.2 and main; the controls pass everywhere; the one-line fix makes 9/9 pass on 9.12.3, 10.5.2 and main. The independent reproduction's JUnit (FastTaxonomyFacetCounts and TaxonomyFacetIntAssociations) fails 4 of 7 on main (-ea, -da), 10.5.2 and 9.12.3; the intended-behaviour check's no-tie variant fails on main (-ea, -da) and 10.5.2; the finder's JUnit fails on 9.2.0 (requireDimCount case only), 9.4.2, 9.6.0, 9.8.0, 9.9.2, 9.10.0, 9.12.3, 10.5.2 and main. [read] branch_10x and branch_10_6 have a TaxonomyFacets.java identical to 10.5.2 (not executed); the newest upstream main commit touching the file is a7704f5242d (2025-06-18). All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-363.html",
   "repro": "repro/LFV-363/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-524",
   "priority": "medium",
   "priority_rank": 175,
   "novelty": "known",
   "withheld": false,
   "area": "facet / MultiFacets and DrillSideways results (MultiFacets#getAllDims, the default DrillSideways#buildFacetsResult, the inherited Facets#getTopDims)",
   "title": "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",
   "summary": "You run a DrillSideways search that drills down on Author=Lisa and Publish Date=2010, where the sideways counts are Author 3 and Publish Date 1, and call getAllDims(10) on the result's facets, expecting what Facets#getAllDims documents, the dims that had hits sorted by value ([Author (3), Publish Date (1)]), with getTopDims(1, 10) returning its first entry. Instead the MultiFacets that DrillSideways returns lists the sideways dims in HashMap order without sorting ([Publish Date (1), Author (3)]), so getTopDims(1, 10) returns Publish Date, and when the base query has no hits getAllDims returns [null] where FastTaxonomyFacetCounts returns []. The cause is MultiFacets#getAllDims, which appends getTopChildren of every mapped dim without a null check, then the default Facets' dims, and never sorts.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f44831feb9dec636679bff68da85ef3ef1115063 ('LUCENE-5525: implement MultiFacets.getAllDims', trunk svn r1578042, by mikemccand; JIRA LUCENE-5525 is now GitHub issue #6588; no pull request, SVN era), released through the lucene_solr_4_7 backport 20c0e9164ef5f254ac81d3299e4656b4253ef873 ('LUCENE-5525: backport to 4.7.x', r1578530, 2014-03-17, in 4.7.1) and branch_4x 9e0eddc86db45bdb5098816b44ec4c763b1a6c68 (r1578043, in 4.8.0). It replaced 'throw new UnsupportedOperationException()' with the loop that adds getTopChildren(topN, dim) of every mapped dim unchecked and never sorts; the Facets#getAllDims contract text was already there (LUCENE-5339, 966de3eaf59, 2013-11-14), and DrillSideways#buildFacetsResult already collected the sideways Facets in a HashMap and returned new MultiFacets(...) (LUCENE-5339, trunk 46e67d8f04be, 2013-11-17; present in 4.7.0, DrillSideways.java:104 and :127 at that tag) [read]. The getTopDims symptom starts with LUCENE-10325 (7c33f04d374, #747, backport 77ccf2fb359 #773, 2022-03-28, released 9.2.0): its default getTopDims = getAllDims(n).subList(0, k) is inherited by MultiFacets. Later changes to the method are cosmetic: LUCENE-9570 reformat (7f8b7ffbcad), LUCENE-10467 validateTopN (6b82e600a8f), #14965 diamond operator (dbaf97f5dcc)",
   "introduced_date": "2014-03-16 (f44831feb9d on trunk and 9e0eddc86db on branch_4x; 4.7.x backport 2014-03-17)",
   "first_affected_version": "4.7.1 [exec] (tagged 2014-04-01, the first release with an implemented MultiFacets#getAllDims); not affected: 4.7.0, where getAllDims throws UnsupportedOperationException [exec], and earlier releases, which lack the Facets/MultiFacets API [exec]; the getTopDims symptom starts at 9.2.0 [exec]",
   "affected_versions": "every release from 4.7.1 through 10.5.2 (the last 10.x release before 10.6.0), including 9.12.3 (latest 9.x) and 8.11.4 (latest 8.x), plus main ea57360912ed; never fixed. [exec] the version-portable probe (taxonomy facets) is violated on 4.7.1 (-ea and -da), 4.7.2, 4.8.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.1.0, 9.2.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da), with its controls passing; the finder's JUnit (needs getTopDims and the 9.x test framework) fails 4 of 4 on 9.2.0, 9.12.3, 10.0.0, 10.5.2 and main; the independent reproduction's JUnit, which adds the SortedSetDocValues DrillSideways path, fails 6 of 6 on 9.12.3, 10.5.2 and main. [read] the normalized getAllDims body is identical at all 109 release tags from 4.7.1 to 10.5.2 in the history clone, every tag has the HashMap in buildFacetsResult, and no tag overrides getTopDims in MultiFacets. Upstream main a9779ef3c193 (2026-10-26) is unchanged and no open PR changes MultiFacets#getAllDims. The Lucene.NET port carries the same code (read, not executed). Executed only on aarch64 Linux with JDK 25; HashMap iteration order is unspecified, so another JDK could swap which orientation of the two-drill-down case is misordered (the repros test both)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/6588",
    "https://issues.apache.org/jira/browse/LUCENE-5525",
    "https://github.com/apache/lucene/issues/747",
    "https://github.com/apache/lucene/issues/11361",
    "https://issues.apache.org/jira/browse/LUCENE-10325",
    "https://github.com/apache/lucene/issues/6397"
   ],
   "doc": "",
   "repro": "repro/LFV-524/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-723",
   "priority": "medium",
   "priority_rank": 176,
   "novelty": "known",
   "withheld": false,
   "area": "facet / taxonomy facets (TaxonomyFacets#rollup dimension enumeration vs the overridable FacetsConfig default dimension config; FastTaxonomyFacetCounts, TaxonomyFacetFloatAssociations)",
   "title": "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",
   "summary": "You subclass FacetsConfig so that every dimension without an explicit entry is hierarchical (override getDefaultDimConfig to return a DimConfig with hierarchical = true, as TestFacetsConfig#testCustomDefault does), index three documents Publish Date/2010/10/15, Publish Date/2010/10/20 and Publish Date/2012/1/1, count them with FastTaxonomyFacetCounts, and expect what an explicit setHierarchical(\"Publish Date\", true) gives: value=3, 2010 (2), 2012 (1). FacetsConfig.build follows the default and indexes only the leaf ordinals, relying on the search-time roll-up, but TaxonomyFacets.rollup() loops over config.getDimConfigs(), which lists only explicitly configured dimensions, so the roll-up never runs. getTopChildren(10, \"Publish Date\") returns null and getSpecificValue(\"Publish Date\") and getSpecificValue(\"Publish Date\", \"2010\") return 0, while a DrillDownQuery on Publish Date/2010 still matches 2 documents.",
   "impact_class": "silent wrong results",
   "introduced_commit": "7477fde1cb063b5c849369afa531bb28df4566fc (branch_4x, svn r1555342, 2014-01-04, committed by mikemccand: 'LUCENE-5371, LUCENE-5339: ... simplify facet APIs'; trunk merge 9d0b60388da; LUCENE-5339 = apache/lucene#6403; Subversion era, no pull request) brought the reworked facet API into the 4.x line with rollup() iterating config.getDimConfigs(), i.e. only explicitly configured dimensions. The loop was first written in 5458dbf2484 (lucene5339 development branch, 2013-11-14) and was later only moved (458786d0f41, 2013-11-27, into IntTaxonomyFacets/FloatTaxonomyFacets; 9ba4af7b883, #12966 by stefanvodita, 2024-04-05, into TaxonomyFacets, 9.x backport 42884fab46d #13358) without changing what it enumerates; LUCENE-7994 (77e6e291bf3, 2017) also kept it. The documented trigger arrived with 074923dda7e (trunk) / 1ea87054f0d (branch_4x), 2014-03-01, LUCENE-5479 = #6542, which added the protected getDefaultDimConfig and changed only FacetsConfig and its test (testCustomDefault sets hierarchical = true), not the roll-up [read]. Not a regression: a latent assumption from when the only default was the static, flat DEFAULT_DIM_CONFIG",
   "introduced_date": "2014-01-04 (7477fde1cb0; loop first written 2013-11-14 on the lucene5339 branch); documented trigger 2014-03-01 (LUCENE-5479)",
   "first_affected_version": "4.7.0 [exec] through an override of the public FacetsConfig#getDimConfig (the workaround the LUCENE-5479 report quotes; fails on 4.7.0, 4.7.1 and 4.7.2); 4.8.0 [exec] through the documented protected getDefaultDimConfig, which first exists in 4.8.0. 4.6.1 and older have no FacetsConfig API [exec]",
   "affected_versions": "Every lucene-facet release on Maven Central from 4.7.0 to 10.5.2 (119 releases, including 8.11.4 and 9.12.3) [exec]; 4.8.0 to 10.5.2 (116 releases) also with the getDefaultDimConfig override [exec]; main a9779ef3c193 [exec]. The wrong output is identical in every affected run and the explicit-config control is correct in all 239 runs that compiled. The finder's JUnit fails on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (it does not compile on 9.0.0 and older because of the test-framework package rename; the main() probes cover those). Not fixed: the loop is unchanged on upstream main a95c754ee00 (2026-10-26), branch_10x 1309534296e and branch_10_6 2763db11b0a (contained in 10.6.0, released 2026-10-29) [read], so 10.6.0 is affected too, and no open PR changes rollup() or getDimConfigs(). All runs on JDK 25, aarch64",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/14237",
    "https://github.com/apache/lucene/issues/6863",
    "https://issues.apache.org/jira/browse/LUCENE-5801",
    "https://github.com/apache/lucene/issues/11780",
    "https://github.com/apache/lucene/issues/6542",
    "https://issues.apache.org/jira/browse/LUCENE-5479"
   ],
   "doc": "",
   "repro": "repro/LFV-723/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-690",
   "priority": "medium",
   "priority_rank": 177,
   "novelty": "new",
   "withheld": false,
   "area": "misc / search: DiversifiedTopDocsCollector and DiversifiedTopDocsCollectorManager (per-key diversity cap)",
   "title": "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",
   "summary": "You subclass DiversifiedTopDocsCollector to get the top hits with at most maxHitsPerKey hits per source, and some matching documents have no value in the key field; you expect such a document not to use up the quota of any real source. Instead insert() gives it key 0 whenever getKeys().advanceExact() returns false (DiversifiedTopDocsCollector.java:146-151), and the manager's reduce counts by that same key (DiversifiedTopDocsCollectorManager.java:77-89), so with one keyless and one key-0 document, numHits 2 and maxHitsPerKey 1, only one hit comes back. With ordinal keys, the pattern of upstream's own test, key 0 is the first value in sort order, so a song without an artist takes the slot of the alphabetically first artist.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f7aa200d406dbd05a35d6116198302d90b92cb29 (LUCENE-7407, GitHub mirror #8460, by mikemccand; a JIRA patch committed directly, no GitHub PR): the move of doc values to an iterator API wrote 'else value = 0' for a document without a key in DiversifiedTopDocsCollector.insert, and ported upstream's ordinal test adapter from getOrd (-1 when missing) to ordValue behind advanceExact; 99af830223a ('switch to advanceExact', 2017-04-02, also in 7.0.0) kept the branch; DiversifiedTopDocsCollectorManager (#16216, 0a598f6b3b5 on main / ced96e18c79 on branch_10x, 2026-06-15) added a reduce that counts by the same key. With a plain numeric doc-values key source the collision is as old as the class (LUCENE-6066 / #7128, ef3a99b385f, 2015-02-12), through the pre-7.0 convention that NumericDocValues.get() returned 0 for a missing value [read]",
   "introduced_date": "2016-09-21 (f7aa200d406); 2017-04-02 (99af830223a keeps the branch); 2026-06-15 (manager, #16216); the numeric-key collision dates from the class itself, 2015-02-12 (ef3a99b385f, 5.x backport ac75a8bae1d)",
   "first_affected_version": "7.0.0 [exec] for the collector-assigned key 0 (numeric and ordinal key sources both collide). With a plain numeric doc-values key source already 5.1.0 [exec], the class's first release, where the random-access get() returned 0 for a missing value; upstream's ordinal-key pattern is not affected before 7.0.0 (getOrd = -1, its own group; executed on 5.1.0 and 6.6.6). The manager path from 10.5.0 [read].",
   "affected_versions": "Every release from 7.0.0 to 10.5.2 and main a9779ef3c193 [exec]; the manager on 10.5.x and main [exec]; with a plain numeric key source also 5.1.0 to 6.6.6 [exec]. Not fixed: upstream main a95c754ee003 (2026-10-26) still has the else-0 branch and no open PR touches either file [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-690.html",
   "repro": "repro/LFV-690/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-155",
   "priority": "medium",
   "priority_rank": 178,
   "novelty": "new",
   "withheld": false,
   "area": "misc / DocValuesStats double statistics (DocValuesStatsCollector, DocValuesStatsCollectorManager)",
   "title": "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)",
   "summary": "You collect statistics for a double doc-values field with DocValuesStats.DoubleDocValuesStats (or SortedDoubleDocValuesStats) and expect max() to be the largest collected value; the javadoc calls it 'the maximum value of the field' and leaves it undefined only when count() is zero. If every collected value is zero or negative, max() returns 4.9E-324 instead: max starts at Double.MIN_VALUE, which is the smallest positive double, not the most negative one, and no value <= 0 ever beats it, so for {-5, -3, -4} you get count 3 and min -5.0 but max 4.9E-324. The same mix-up on the other side makes min() return Double.MAX_VALUE when every value is +Infinity; the long variants start at Long.MAX_VALUE / Long.MIN_VALUE and are correct.",
   "impact_class": "silent wrong results",
   "introduced_commit": "ad7152ad4739 (master, 'LUCENE-7590: add DocValuesStatsCollector', by shaie; JIRA LUCENE-7590, migrated as apache/lucene#8641; pre-GitHub, no PR): DoubleDocValuesStats was created with super(description, Double.MAX_VALUE, Double.MIN_VALUE) next to LongDocValuesStats with Long.MAX_VALUE, Long.MIN_VALUE; SortedDoubleDocValuesStats copied the pair in 944b8e07f557 ('LUCENE-7590: add DocValuesStats for SortedNumeric DV fields'); both were released through the branch_6x backports 7269c484a4a0 and 63a5cd00173f in 6.4.0 [read]; 0210af757c54 (#15653 'Introduce DocValuesStatsCollectorManager', by gaobinlong, merged 2026-05-19, released in 10.5.0) added merge() and the manager without touching the initial values, which gave the bug a second, non-deprecated entry point [read]",
   "introduced_date": "2016-12-11 (authored; committed to master and branch_6x 2016-12-14, DoubleDocValuesStats); 2016-12-17 (authored; committed 2016-12-18, SortedDoubleDocValuesStats); 2026-05-19 (#15653, CollectorManager entry point)",
   "first_affected_version": "6.4.0 [exec] (6.3.0 has no DocValuesStats [exec]); the DocValuesStatsCollectorManager path since 10.5.0 [exec] (10.4.0 has no such class [exec])",
   "affected_versions": "every release from 6.4.0 to 10.6.0 (10.6.0 by reading) and main ea57360912ed. [exec] the follow-up's history probe (public-API main(), 4 bug cases and 3 controls) is affected on 6.4.0, 6.4.2, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.8.2, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.4.0, 10.5.0, 10.5.2 and main (-ea and -da), always with max = 4.9E-324 and min = 1.7976931348623157E308 while the controls are right; the finder's JUnit (ported only in package and import lines where needed) fails 4 of 4 on 6.4.0, 7.0.0, 9.0.0, 9.12.3, 10.5.2 and main; the independent reproduction's CollectorManager JUnit fails 2 of 3 on 10.5.0, 10.5.2 and main; the intended-behaviour check's CollectorManager JUnit fails 4 of 4 on 10.5.2 and main; all runs on JDK 25, also for releases that predate it. [read] the same two constructor lines at the release tags 6.4.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.8.1, 9.0.0, 9.12.3, 10.0.0, 10.4.0, 10.5.0 and 10.5.2, and no change to either line in git log -L; releases between those were neither run nor read one by one, and 8.9.0-8.11.3 were neither read nor executed (between affected 8.8.2 and 8.11.4). 10.6.0 (released 2026-10-29) was not run; it is affected by the branch_10_6 reading below. Not fixed upstream: main, branch_10x, branch_10_6 and branch_9_12 still have both lines (follow-up prior-report record, read 2026-10-26).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-155.html",
   "repro": "repro/LFV-155/",
   "triage_status": "fix_in_progress",
   "triage_by": "sjs004 (PR #16971)",
   "triage_date": "2026-11-03",
   "triage_link": "https://github.com/apache/lucene/pull/16971",
   "triage_note": "Open PR #16971 (sjs004, opened 2026-11-03) fixes this bug and adds a test; it references this bug.",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1129",
   "priority": "medium",
   "priority_rank": 179,
   "novelty": "new",
   "withheld": false,
   "area": "misc / DocValuesStats: SortedDoubleDocValuesStats decode of sorted-numeric double doc values (core DoubleField)",
   "title": "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)",
   "summary": "You index two documents with DoubleField(\"f\", -5.0) and DoubleField(\"f\", 3.0) and search MatchAllDocsQuery with new DocValuesStatsCollectorManager<>(() -> new SortedDoubleDocValuesStats(\"f\")); you expect min() = -5.0 (sum -2.0, mean -1.0), because the class 'Holds DocValues statistics for a sorted-numeric field storing double values' and DoubleField is core's sorted-numeric double field. You get min() = -0.8749999999999999 (sum 2.125, mean 1.0625) with no error: DoubleField stores NumericUtils.doubleToSortableLong(value), but SortedDoubleDocValuesStats decodes each stored long as raw IEEE bits (Double.longBitsToDouble, DocValuesStats.java:436). Positive values are unaffected because their sortable and raw bits are the same.",
   "impact_class": "silent wrong results",
   "introduced_commit": "944b8e07f557b9320895998fe33d71cae5199eee ('LUCENE-7590: add DocValuesStats for SortedNumeric DV fields', by Shai Erera, migrated as #8641; pre-GitHub, no PR), which added SortedDoubleDocValuesStats with the raw decode that is today DocValuesStats.java:436, unchanged since [read]; release carrier the branch_6x backport 63a5cd00173f7e89a478981429d4d5cd38f3cf1d, first released in 6.4.0 [exec]. The same commit's test writes Double.doubleToRawLongBits of positive values only. Reachable through core's own field since 57201aa967828a678a6c440b6a2e36fd8846ca37 (main) / 827f762d137 (branch_9x, in 9.5.0), apache/lucene#11997 'Add IntField, LongField, FloatField and DoubleField' (closes #11199), which added DoubleField with sortable SORTED_NUMERIC doc values and did not touch DocValuesStats [exec]. Not a regression of DocValuesStats",
   "introduced_date": "2016-12-17 (author date of 944b8e07f55 and 63a5cd00173; committed 2016-12-18); DoubleField trigger 2022-12-20 (author date of 57201aa9678 / 827f762d137, #11997)",
   "first_affected_version": "6.4.0 [exec]; with core's DoubleField, the trigger of the repro, 9.5.0 [exec]. For 6.4.0-9.4.x calling it a bug rests on the javadoc recipe being the convention for sorted-numeric doubles; from 9.5.0 the DoubleField case does not depend on that reading",
   "affected_versions": "every release from 6.4.0 through 10.6.0 (6.4.0-6.6.6, 7.0.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.6.0; 10.6.0 released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT). Executed with core's DoubleField (the repro, all 'expected:<-5.0> but was:<-0.8749999999999999>'): main -ea and -da (finder, the independent reproduction, the intended-behaviour check, adjudication, follow-up, re-run), 10.6.0 -ea and -da, 10.5.2 -da, and 9.12.3 -da and 9.5.0 -da (9.x form of the test: DocValuesStatsCollector with search(Query, Collector)) [exec]; with the javadoc recipe: 6.4.0 -ea and -da, 8.11.4 -da and 9.4.2 -da (min -0.8749999999999999, sum 2.125, mean 1.0625) [exec]; the other releases by code identity (the raw decode is at all 78 release tags 6.4.0-10.6.0 in the history clone; its 8.8.2-8.11.x tags are missing, and 8.11.4 was executed) [read]; upstream main head 1c2072f0284 (2026-11-02) still decodes raw at DocValuesStats.java:436 (checked via the GitHub API), as do branch_10_6 and branch_11x (follow-up) [read]. Not affected: 6.3.0 and earlier (no DocValuesStats; 6.3.0 compile error [exec]); the DoubleField trigger needs 9.5.0 or later (9.4.2 compile error [exec]). Not new in 10.6 (10.5.2 fails [exec]).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1129.html",
   "repro": "repro/LFV-1129/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-547",
   "priority": "medium",
   "priority_rank": 180,
   "novelty": "known",
   "withheld": false,
   "area": "facet / taxonomy association facets (TaxonomyFacetIntAssociations, TaxonomyFacetFloatAssociations incl. the DoubleValuesSource path; MAX start value in the per-ordinal, roll-up and dimension aggregates)",
   "title": "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)",
   "summary": "You index two documents whose IntAssociationFacetField values for the label int/x are -3 and -5 (or float associations -1.5 and -2.5, or a DoubleValuesSource over a field holding -4 and -7) and facet them with AssociationAggregationFunction.MAX, the 'Aggregation that computes the maximum value'. You expect -3 (-1.5, -4.0), since the 9.11.0 CHANGES say aggregation facets no longer assume that values are positive. Instead getTopChildren, getAllChildren, getSpecificValue and the dimension value all report 0 (0.0), because the first value of every ordinal is combined with the 0 of an unseen ordinal, Math.max(0, v), and the roll-up and dimension aggregates also start at 0.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f870edf2fe26cffcd4bcddc760b8436c13424103 (main, PR #718, LUCENE-10444 'Support alternate aggregation functions in association facets', by gsmiller; first released in 10.0.0) and its branch_9x backport 9e10ba02ec350f267458926035bb172ea82291b9 (PR #719), which shipped MAX in 9.2.0 [read] [exec]. Not a regression: the bug was born with MAX. #12966 (9ba4af7b883c; 9.x backport #13358, 42884fab46d, in 9.11.0) changed the symptom from a dropped label to a label shown with value 0 and rewrote several of the 0 starts without changing their meaning [read]",
   "introduced_date": "2022-04-06 (main, #718) and 2022-04-07 (branch_9x, #719; 9.2.0 tagged 2022-05-24); symptom change 2024-04-05 (#12966 on main) and 2024-05-14 (9.x backport #13358, first released in 9.11.0)",
   "first_affected_version": "9.2.0 [exec], the first release with AssociationAggregationFunction.MAX; the label shown with value 0 first in 9.11.0 [exec]. 9.1.0 has no MAX [exec]",
   "affected_versions": "Every release from 9.2.0 to 10.5.2 and main ea57360912ed [exec]. 9.2.0 to 9.10.0: getSpecificValue returns 0 and getTopChildren returns null (labels with value <= 0 were filtered, the #12585 symptom); 9.11.0 to main: such labels are returned with value 0 / 0.0 and the dimension value is 0. Not checked: the 10.6 branch (10.6.0, released 2026-10-29; not in the local clone) and getAllChildren across releases (absent in 9.2.0; executed on main only). Not fixed upstream: the six fix-site files are unchanged on upstream main ffa9d816eeb4 (2026-10-26) and no open PR changes the start value [read]. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/12585",
    "https://github.com/apache/lucene/issues/12966",
    "https://github.com/apache/lucene/issues/718",
    "https://issues.apache.org/jira/browse/LUCENE-10444",
    "https://github.com/apache/lucene/issues/13198",
    "https://github.com/apache/lucene/issues/13287"
   ],
   "doc": "",
   "repro": "repro/LFV-547/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1116",
   "priority": "medium",
   "priority_rank": 181,
   "novelty": "known",
   "withheld": false,
   "area": "facet / taxonomy association facets (TaxonomyFacetIntAssociations, IntTaxonomyFacets, AssociationAggregationFunction.SUM)",
   "title": "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)",
   "summary": "You index two documents whose IntAssociationFacetField values for the label dim/a are 1,500,000,000 and 1,000,000,000 and aggregate them with TaxonomyFacetIntAssociations and AssociationAggregationFunction.SUM, the 'Aggregation that computes the sum'. You expect 2,500,000,000, but getSpecificValue returns -1,794,967,296 with no error: SUM adds in int and the per-label values are kept in an int array or int map, so any label or dimension total above Integer.MAX_VALUE wraps (about 2.2 million matches of value 1,000 are enough).",
   "impact_class": "silent wrong results",
   "introduced_commit": "unknown (not bisected); the int sum is present in every association-sum implementation read: SumIntAssociationFacetsAggregator in 4.6.1 ('values[ordinal] += value' on an int[]), TaxonomyFacetSumIntAssociations from 4.7.0 (LUCENE-5339, 7027c5690ed; 'values[ord] += value' on an int[]), and the int-returning AssociationAggregationFunction.SUM that replaced it (LUCENE-10444 / #718, f870edf2fe2 on main, backported as #719, 9e10ba02ec3, first released in 9.2.0) [read]",
   "introduced_date": "unknown (not bisected); before 2013-11-18 (LUCENE-5339) [read]",
   "first_affected_version": "4.x [read]; earlier 4.x association releases not checked; oldest executed 9.12.3",
   "affected_versions": "9.12.3 and 10.6.0 (released) with -da [exec]; main e1faeba08bde with -ea and -da [exec]; 4.6.1 and 4.7.0 by reading [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/6596",
    "https://issues.apache.org/jira/browse/LUCENE-5533"
   ],
   "doc": "",
   "repro": "repro/LFV-1116/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-382",
   "priority": "medium",
   "priority_rank": 182,
   "novelty": "new",
   "withheld": false,
   "area": "classification / document classifiers (SimpleNaiveBayesDocumentClassifier field boosts)",
   "title": "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)",
   "summary": "You build a SimpleNaiveBayesDocumentClassifier with textFieldNames {\"title^10\", \"body\"}, as its constructor javadoc allows, and classify documents with it one after another, expecting the title boost on every call. The first call applies the boost but also overwrites \"title^10\" with \"title\" in textFieldNames, which is the caller's own array kept by reference, so from the second call on every boost is 1: classifying the same document twice gives fruit (0.99994) and then vehicle (0.55373), exactly the unboosted classifier's answer, and on the upstream test's own fixture ('title^100') the class flips from batman to the video-game class. No error is raised, and a second classifier built from the same String[] is unboosted even on its first call.",
   "impact_class": "silent wrong results",
   "introduced_commit": "71cea88773e8fe1086d0f2d7829b17b9c23bcc63 ('LUCENE-6631 - added document classification api and impls', SVN trunk r1709522; JIRA LUCENE-6631 'Lucene Document Classification', GitHub mirror apache/lucene#7689; patch by GitHub alessandrobenedetti, committed by tteofili; no PR, SVN era) [read] [exec]. The defect came with the class, so it is not a regression; the parent has stored the caller's array by reference since LUCENE-5311 (b4a343d6ba9, 2013-11-02, then in train(...); LUCENE-6045, 92842e7c348, 2015-04-30, moved the assignment into the varargs constructor) and that store is not itself the defect",
   "introduced_date": "2015-10-20",
   "first_affected_version": "6.0.0 [exec] (the first release with SimpleNaiveBayesDocumentClassifier; CHANGES.txt 6.0.0 New Features 'LUCENE-6631: Lucene Document classification'; 71cea88773e is an ancestor of the 6.0.0 tag); 5.3.1 and 5.5.5 [exec]: API absent (compile error; the release jars have no classification/document package)",
   "affected_versions": "Every release from 6.0.0 to 10.5.2 and main ea57360912ed; not fixed upstream (upstream main cf398bfb142c, branch_10x, releases/lucene/10.5.2 and releases/lucene/9.12.3 still have the write-back, read 2026-10-26). [exec] the finder's JUnit (follow-up, seed DEADBEEF) fails 2 of 2 on 6.0.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (main with -ea and -da), always with call 1 boosted and call 2 unboosted; the independent reproduction's JUnit fails 3 of 3 on main (-ea, -da), 10.5.2 and 9.12.3; the intended-behaviour check's fails on main (-ea, -da) and 10.5.2; the upstream-fixture check (verify-v2) fails on main (-ea, -da) and 10.5.2. [read] all 83 release tags in the history clone that contain 71cea88773e (6.0.0 ... 10.5.2) have the write-back, the scoring loop over textFieldNames, the 'title^10' javadoc and the parent's by-reference store; 8.8.2-8.11.3 are inferred (not tagged in the clone; bracketed by 8.8.1 [read], the old branch_8x tip d76dfaf68a8 [read] and 8.11.4 [exec]). Not applicable to 5.x and earlier (API absent [exec]). All runs on JDK 25.0.3; the 6.0.0 fix control rules out a JDK artifact on the old jars",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-382.html",
   "repro": "repro/LFV-382/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-680",
   "priority": "medium",
   "priority_rank": 183,
   "novelty": "new",
   "withheld": false,
   "area": "classification / BooleanPerceptronClassifier (batched training)",
   "title": "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)",
   "summary": "You index two training documents labelled false, 'bb' and 'aa aa', train BooleanPerceptronClassifier with bias 1.5 and batchSize 2, and expect assignClass('aa aa') = false, which is what batchSize 1 gives on the same data and what both an online and a mini-batch perceptron give. Instead it returns true (score 0.81): the update for the misclassified 'aa aa' (batch position 1) is written only to the pending weight map, because the FST that holds the weights is rebuilt only when a misclassified document sits at a position that is a multiple of batchSize, and the constructor ends by clearing that map without a final rebuild. Updates inside a batch are also computed from the last FST build and overwrite each other, so with batchSize 10 and three training documents 'aa' labelled false only the first update is applied and the model still answers true.",
   "impact_class": "silent wrong results",
   "introduced_commit": "05940e34ab8c2a961fef8498b39d592f4099e8e2 (trunk, svn r1519590, message 'LUCNE-4818 - added boolean perceptron classifier' ('LUCNE' is a typo in the original); issue LUCENE-4818 'Create a boolean perceptron classifier', migrated as GitHub issue #5883; by GitHub tteofili; svn era, no pull request) [read]: the first committed version already has all three fragments (the rebuild flag batchCount % batchSize == 0 passed only for misclassified documents, the update read from the last FST build with Util.get(fst, term), and no rebuild after the loop). The issue's only attachment, LUCENE-4818.patch (March 2013), had no batching: it read the pending weight from the map and rebuilt the FST after every update, so batching and the stale read arrived in the commit. It reached a release through the branch_5x creation backport 55594bad9b0 (LUCENE-5944, 2014-09-18). Not a regression: later commits (LUCENE-6433 dbf063d3d1e / 70ce247cdb0, LUCENE-6479 8b2e0d937d5, LUCENE-6853 cbad533d7a4, the 2021 reformat 7f8b7ffbcad, 06f91792957, 47f8c1baa2e) left the batch logic unchanged.",
   "introduced_date": "2013-09-03 (05940e34ab8, trunk); 2014-09-18 (branch_5x backport 55594bad9b0); first release 5.0.0, tagged 2015-02-19",
   "first_affected_version": "5.0.0 [exec] (the first release with the class, via the branch_5x backport: the 5.x API copy of the repro fails 2 of 2 with -ea (seeds DEADBEEF and 0BADF00D) and -da; shadowing only BooleanPerceptronClassifier with the minimal batch fix makes it pass, while shadowing the unmodified 5.0.0 file still fails). No earlier release has the class (the 4.10.4 classification jar holds only Classifier, KNearestNeighborClassifier and SimpleNaiveBayesClassifier [exec]). On the trunk line the first release tag containing 05940e34ab8 is 6.0.0, which is also the JIRA fix version.",
   "affected_versions": "Every release that has the class, 5.0.0 through 10.5.2 (107 releases) and 10.6.0 (by reading), and main a9779ef3c193; not fixed upstream. [exec] the finder's repro (lost update at batch position 1 with batchSize 2; batchSize 10 applies only the first of three updates; batchSize 1 controls pass), in API-adapted copies for old releases, fails 2 of 2 on 5.0.0 (-ea two seeds, -da), 5.5.5, 6.0.0, 6.3.0, 6.4.0, 6.6.6, 7.0.0, 7.7.3, 8.9.0, 8.11.4, 9.0.0, 9.12.3 (-ea, -da), 10.0.0, 10.5.2 (-ea, -da) and main a9779ef3c193 (-ea two seeds, -da); the independent reproduction's own test fails 3 of 3 on main, 10.5.2 and 9.12.3. [read] the other releases by code identity (file blobs 993dd9e3b5 through d45bcb1f81 all contain the three fragments; 8.8.2-8.11.3, released from the old lucene-solr repository, lie between 8.8.1 and the executed 8.9.0 and 8.11.4); upstream main a95c754ee00 (2026-10-26), branch_10x 1309534296e and branch_10_6 2763db11b0a carry the same file blob d45bcb1f81 as a9779ef3c193, and the only open PR touching the file (#16847) changes just a parameter type.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-680.html",
   "repro": "repro/LFV-680/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-391",
   "priority": "medium",
   "priority_rank": 184,
   "novelty": "known",
   "withheld": false,
   "area": "classification / SimpleNaiveBayesClassifier (training query; copies in SimpleNaiveBayesDocumentClassifier and CachingNaiveBayesClassifier)",
   "title": "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)",
   "summary": "You index four training documents marked split:train (fruit: 'apple', 'pear', 'plum'; vehicle: 'car') and ten more vehicle documents marked split:other, build SimpleNaiveBayesClassifier with the training query split:train and classify 'apple', expecting what the same classifier trained on an index holding only the four training documents answers: fruit (0.811), with prior P(fruit) = 3/4. Instead it answers vehicle (P(fruit) = 0.445), and for an empty input, which only the prior decides, it gives P(fruit) = 3/14, the whole-index share. The query is ANDed only into the per-word counts (getWordFreqForClass); the prior (docFreq(class) / Terms.getDocCount()) and the likelihood denominator (average unique terms per document x docFreq(class) + that document count) ignore it, because countDocsWithClass applies the query only in a getDocCount() == -1 fallback that current codecs never take.",
   "impact_class": "silent wrong results",
   "introduced_commit": "e60f7af1d16c5467a1300abe575ddb983212bfb2 'LUCENE-5284 - added method for training with a Query filter' (svn r1532983 on trunk, by GitHub tteofili; issue apache/lucene#6348; Subversion era, no pull request), backported to branch_4x the same day as 3df19e13b2dc (svn r1533003, 'LUCENE-5290 - backport LUCENE-5284 and performance tests from trunk', #6354; the commit that the 4.6.0-5.x release tags contain): it added the training query and ANDed it only into getWordFreqForClass and into the getDocCount() == -1 fallback of countDocsWithClass, leaving the unfiltered docFreq prior and denominator that the module's first commit 4711f774ee4e (LUCENE-4345, 2012) had written before any training query existed [read]. Present since the feature was created, not a regression: git log -L lists 8 later commits on calculateLogPrior/docCount and 10 on getTextTermFreqForClass (2012-2021), none of which applies the query. Related: 173daaedefe (LUCENE-5466, 2014) moved the query assignment in train() so that the fallback count sees it.",
   "introduced_date": "2013-10-17 (e60f7af1d16 on trunk and the branch_4x backport 3df19e13b2dc)",
   "first_affected_version": "4.6.0 [exec] (tagged 2013-11-22, the first release with the training-query API; 4.5.1 lacks the API [exec]; the JIRA fix versions of LUCENE-5284 (6.0) and LUCENE-5290 (4.5.1) are misleading, and no CHANGES entry mentions either). SimpleNaiveBayesDocumentClassifier is affected since it was added in 6.0.0 and CachingNaiveBayesClassifier (denominator only; it has no prior) since 5.0.0 [read]",
   "affected_versions": "Every release from 4.6.0 to 10.5.2 and main ea57360912ed; not fixed upstream (upstream main cf398bfb142c, 2026-10-26: no change to the three files after 2026-06-14; the only open PR touching them, #16847, widens int to long). [exec] follow-up main() ports with the same data and oracle (one per API era) fail on 4.6.0 (-ea and -da), 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da); the controls without outside documents pass on 4.6.0, 9.12.3, 10.5.2 and main. The finder's JUnit fails on main (-ea and -da), 10.5.2 and 9.12.3 (9.x accessor variant repro/src-9x); the independent reproduction's JUnit fails 2 of 3 (its control passes) on main (-ea and -da), 10.5.2 and 9.12.3. SimpleNaiveBayesDocumentClassifier fails on main (-ea and -da; the independent reproduction and the intended-behaviour check) and 10.5.2. CachingNaiveBayesClassifier was not executed [read]. [read] releases between the executed ones follow from release-tag containment of the introducing commit and git log -L (no 8.9-8.11.3 tags in the history clone; 8.11.4 executed).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/6529",
    "https://issues.apache.org/jira/browse/LUCENE-5466",
    "https://github.com/apache/lucene/issues/8723",
    "https://issues.apache.org/jira/browse/LUCENE-7672",
    "https://github.com/apache/lucene/issues/2115",
    "https://issues.apache.org/jira/browse/LUCENE-1039"
   ],
   "doc": "",
   "repro": "repro/LFV-391/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-380",
   "priority": "medium",
   "priority_rank": 185,
   "novelty": "new",
   "withheld": false,
   "area": "classification / document classifiers (SimpleNaiveBayesDocumentClassifier.assignClass and getClasses)",
   "title": "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)",
   "summary": "You train SimpleNaiveBayesDocumentClassifier on the fields title and body and classify the document {title: 'apple', body: ''} (or a body such as 'the of and' that the analyzer reduces to stop words), expecting a class with a finite score, as the DocumentClassifier.assignClass javadoc and the '0-1 range' normalisation comment imply and as the same document without the body value gets (fruit). Instead getClasses returns fruit=NaN and vehicle=NaN, and assignClass returns null. calculateLogLikelihood returns result / tokenizedText.length, which is 0.0 / 0 = NaN for a value with no tokens; assignNormClasses adds that NaN to every class, and neither the log-sum-exp normalisation nor the 'score > maxscore' test in assignClass can recover from it.",
   "impact_class": "silent wrong results",
   "introduced_commit": "71cea88773e8fe1086d0f2d7829b17b9c23bcc63 'LUCENE-6631 - added document classification api and impls' (svn trunk r1709522; committed by GitHub tteofili from a JIRA patch by alessandrobenedetti; migrated issue apache/lucene#7689; no pull request) [read]. git blame on main :222 points to 552c367c5d2 (LUCENE-5698, 2019-01-18, apache/lucene-solr#544), which only inlined the division and dropped its comment (behaviour unchanged).",
   "introduced_date": "2015-10-20",
   "first_affected_version": "6.0.0 [exec] (tagged 2016-04-07, the first release with the class: CHANGES 6.0.0 'LUCENE-6631: Lucene Document classification'; 5.5.0 and 5.5.5 lack the API [exec])",
   "affected_versions": "Every release from 6.0.0 to 10.5.2 and main ea57360912ed; not fixed upstream (upstream main cf398bfb142c, 2026-10-26, still divides at line 222). [exec] the finder's JUnit fails 2 of 2 on 6.0.0 (-ea and -da), 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da), with API-spelling variants for older releases; the independent reproduction's JUnit fails 3 of 6 (controls pass) on main (-ea and -da), 10.5.2, 9.12.3, 8.11.4 and 6.0.0. [read] the division is present in all 83 release tags of the history clone that contain the file (6.0.0 to 10.5.2; 8.8.2-8.11.3 are not tagged there, 8.11.4 was executed).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-380.html",
   "repro": "repro/LFV-380/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-395",
   "priority": "medium",
   "priority_rank": 186,
   "novelty": "new",
   "withheld": false,
   "area": "classification / BooleanPerceptronClassifier (weights FST)",
   "title": "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)",
   "summary": "You index two documents, 'P P P' labelled true and 'N' labelled false, where P is U+F900 (a CJK compatibility ideograph) and N is U+1D400 (mathematical bold capital A), train BooleanPerceptronClassifier with the default bias (the average term frequency, here 2), and expect assignClass(P) = (true, 0.393), which is what the same corpus gives with ASCII terms or with ordinary CJK ideographs. Instead the constructor throws AssertionError 'inputs are added out of order lastInput=[f0 9d 90 80] vs input=[ef a4 80]' with -ea, and with -da assignClass(P) returns (false, 0.632) because P's weight can no longer be found in the FST. The classifier keeps its weights in a ConcurrentSkipListMap<String, Double>, whose String order (UTF-16 code units) puts U+1D400 (D835 DC00) before U+F900, and adds their UTF-8 encodings in that order to an FSTCompiler that requires UTF-8 byte order (EF before F0) and checks it only with an assert.",
   "impact_class": "silent wrong results",
   "introduced_commit": "05940e34ab8c2a961fef8498b39d592f4099e8e2 (trunk, svn r1519590, message 'LUCNE-4818 - added boolean perceptron classifier'; issue LUCENE-4818 'Create a boolean perceptron classifier', migrated as GitHub issue #5883; by GitHub tteofili; svn era, no pull request): the first version of the class already keyed the weights in a TreeMap<String,Double> (String order) and added their copyChars UTF-8 encodings in that order to a BYTE1 FST Builder whose input order is checked only by an assert [read]. It reached a release through the branch_5x bulk backport 55594bad9b0 (LUCENE-5944, svn r1626055, same pattern) [read].",
   "introduced_date": "2013-09-03 (05940e34ab8, trunk); 2014-09-18 (branch_5x backport 55594bad9b0); first release 5.0.0, tagged 2015-02-19",
   "first_affected_version": "5.0.0 [exec] (the 5.0.0 classification jar contains BooleanPerceptronClassifier and the history test fails there: -ea AssertionError in Builder.add, -da NullPointerException in updateWeights; 4.10.4 and earlier lack the class [exec]; the JIRA fix version of LUCENE-4818 says 6.0, but the class shipped in 5.0.0)",
   "affected_versions": "Every release from 5.0.0 to 10.5.2 and main ea57360912ed; not fixed upstream (upstream main cf398bfb142c and branch_10x, 2026-10-26: BooleanPerceptronClassifier.java last changed by 942065cc3e7, 2024-09-10, a record conversion; no open PR touches it). [exec] follow-up history test (corpus 'P P P' -> true, 'N' -> false with P = U+F900 and N = U+1D400 in both roles; oracle = the ASCII control trained in the same run; the low-BMP control U+4E00 + U+1D400 passes everywhere): 5.0.0 and 5.5.5 fail with -ea (AssertionError in Builder.add) and -da (NullPointerException in updateWeights, training aborts; the swapped case is masked); 6.6.6 fails with -ea and -da (wrong class; the swapped case is masked); 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main fail both trigger cases with -ea (AssertionError) and -da (wrong class or score); main with the fix shadowed passes with -ea and -da. The finder's, the independent reproduction's, the intended-behaviour check's and the adjudication's JUnits fail on main (-ea and -da), and the finder's, the independent reproduction's and the intended-behaviour check's on 10.5.2 and 9.12.3 (the independent reproduction also on 8.11.4). [read] all 98 release tags of the history clone from 5.0.0 to 8.8.1 and from 9.0.0 to 10.5.2 have the String-keyed sorted map, copyChars and INPUT_TYPE.BYTE1 in this class; 8.8.2-8.11.x are not tagged in the clone (8.11.4 was executed). Not affected: 4.10.4 and earlier (class absent). All runs used JDK 25; the failing path (Java collection order plus FST construction) does not depend on the JDK.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-395.html",
   "repro": "repro/LFV-395/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-209",
   "priority": "medium",
   "priority_rank": 187,
   "novelty": "known",
   "withheld": false,
   "area": "spatial3d / Geo3DPoint shape queries (PointInShapeIntersectVisitor per-document test against GeoStandardCircle and other cap-shaped boundaries)",
   "title": "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",
   "summary": "You index locations as Geo3DPoint on the default WGS84 model and run Geo3DPoint.newDistanceQuery with a small radius, say 10 m, expecting the points within 10 m (the javadoc allows up to 0.5% error). Instead the query misses about half of the points inside the radius, even a document located exactly at the query centre, and returns points about 100 m away, while LatLonPoint gives the right answer on the same data. The cause is that each document's stored x/y/z is decoded to a point a few millimetres off the planet surface, and that point is tested against the circle's cutting plane, which for a small circle meets the surface at a grazing angle and turns millimetres into 100-190 m.",
   "impact_class": "silent wrong results",
   "introduced_commit": "31b17203f2c (branch_5x, svn r1700887, first released in 5.4.0) and 03e5bcfa739 (trunk, svn r1700883, first released in 6.0.0), the same change: LUCENE-6699 'add geo3d + BKD for fast, accurate earth-surface point-in-shape queries' (apache/lucene#7757, companion LUCENE-6759 = #7817), committed by mikemccand on 2015-09-02, no GitHub pull request (SVN era). It added the first geo3d point field and point-in-shape query, whose per-document check decodes each stored x/y/z to the centre of its encoding cell and calls shape.isWithin on that off-surface triple [read]. The single-plane circle test is older (2015 spatial-module commits) and correct for exact surface points [exec]. Later commits kept the defect: LUCENE-7150 (0dcf822f40f / bf0e59223d0, 2016-03-31, released in 6.1.0) added newDistanceQuery with its 'points within this distance' and '0.5% error' javadoc; LUCENE-7168 (c2289de3c71, 1848477bd83, 2016-04-06/07) introduced decode to the cell centre, moved the check into PointInShapeIntersectVisitor and made isWithin(quantized point) the test oracle; LUCENE-7225 (22a23f66f77, 2016-04-16) left today's visit() code",
   "introduced_date": "2015-09-02 (LUCENE-6699 on trunk and branch_5x)",
   "first_affected_version": "5.4.0 [exec] (first release with a geo3d point query: bkdtree3d.Geo3DPointField with PointInGeo3DShapeQuery and a GeoCircle); 5.3.0, 5.3.2 and earlier have no geo3d point query [exec]; Geo3DPoint.newDistanceQuery, whose javadoc the canonical repro asserts, first ships in 6.1.0",
   "affected_versions": "every release from 5.4.0 to 10.5.2 and main ea57360912ed; no release that has the API is unaffected and none has a fix. [exec] version-neutral public-API probes (four API families) fail on 5.4.0, 5.4.1, 5.5.0, 5.5.5, 6.0.0, 6.0.1, 6.1.0, 6.2.0, 6.2.1, 6.3.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.4.1, 8.5.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main with -ea (and with -da on 5.4.0, 6.1.0, 9.12.3, 10.5.2 and main); the canonical JUnit fails on 9.12.3, 10.0.0, 10.5.2 and main; the independent reproduction's own test fails on 10.5.2 and 9.12.3 and the intended-behaviour check's centre test on 10.5.2. Symptom by era for a 10 m query at 40N 74W with rings at 5 m and 100 m: 5.4.0-6.0.1 164 of 360 near points missed and 88 of 360 far points matched; 6.1.0-6.2.1 183 missed and 0 matched (LUCENE-7221's tight pre-filter hides the far matches in this scenario, the misses remain); 6.3.0-8.4.1 183 and 13 (LUCENE-7430's outward-rounded bounds let far matches through; isolated both ways with shadow classes); 8.5.0-main 186 and 13. [read] at every release tag in the history clone from 5.4.0 to 10.5.2 the per-document check calls isWithin on the decoded triple without projecting it; 8.8.2-8.11.3 are not tags in the clone and are inferred (8.5.0 and 8.11.4 fail, the code is unchanged). Not affected: 5.3.x and earlier (API absent).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/13056",
    "https://issues.apache.org/jira/browse/LUCENE-6699",
    "https://github.com/apache/lucene/issues/7757",
    "https://github.com/apache/lucene/issues/7817",
    "https://issues.apache.org/jira/browse/LUCENE-7168",
    "https://github.com/apache/lucene/issues/8223"
   ],
   "doc": "",
   "repro": "repro/LFV-209/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-736",
   "priority": "medium",
   "priority_rank": 188,
   "novelty": "new",
   "withheld": false,
   "area": "spatial3d / geom path membership (GeoStandardPath end caps; Geo3DPoint.newPathQuery, Geo3DDocValuesField.newPathSort)",
   "title": "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",
   "summary": "You run Geo3DPoint.newPathQuery (or Geo3DDocValuesField.newPathSort) on WGS84 with a north-south path, for example from (44N,20E) to (45N,20E), and expect it to match the points within pathWidthMeters of the path, with round end caps of that radius around the first and last points, as it does on PlanetModel.SPHERE. Instead both end caps are shifted about 21 km toward the equator: with pathWidthMeters 20000 the query misses documents 12 and 16 km beyond the north end (sort value +Infinity), and with pathWidthMeters 1000 it matches documents 10 to 40 km south of the first point (sort values 10006 to 40034 m). The end-cap plane (GeoStandardPath.CutoffSingleCircleSegmentEndpoint, built by CircleSegmentEndpoint through the two segment corners with its normal inside the origin-containing cutoff plane) points along the end point's geocentric direction, which on an ellipsoid is not the surface normal there, so the cap circle is centred equatorward of the end point.",
   "impact_class": "silent wrong results",
   "introduced_commit": "560f3a1a010407f9fd8ed1d84636464891248172 (2015-05-27, lucene6487 branch, 'LUCENE-6487: Geo3D with WGS84 in-progress with David's mods'; JIRA LUCENE-6487, now apache/lucene#7546; patch by DaddyWri (Karl Wright), committed by dsmiley (David Smiley); svn era, no pull request), merged to trunk as 77de0ed1cf8 and to branch_5x as 8c3e6b0ed32 (2015-06-02). In GeoPath.SegmentEndpoint case (2) (path start and end) it replaced the sphere-only cap new SidedPlane(point, point, -originDistance) (normal = the end point's direction, exact on the unit sphere) with SidedPlane.constructNormalizedPerpendicularSidedPlane(point, cutoffPlane, topEdgePoint, bottomEdgePoint), added in the same commit (plane through the two corners, normal inside the cutoff plane). Later changes kept the geometry: LUCENE-6544/6632 (2015) and LUCENE-8696 (2019, interior joints only) did not touch end caps, and the 2022 hierarchical refactor (fc7ce768514 on main, 83a81262b85 on 9.x, first in 9.5.0; #11965) re-expressed it as SidedPlane.constructSidedPlaneFromTwoPoints, the same plane. [read]",
   "introduced_date": "2015-05-27 (branch commit); merged 2015-06-02 (trunk and branch_5x)",
   "first_affected_version": "5.3.0 [exec], the first release with the WGS84 planet model (CHANGES: 'LUCENE-6487: Spatial Geo3D API now has a WGS84 ellipsoid world model option'); 5.2.1, the last release before, is unit-sphere only and cannot show the bug [exec]",
   "affected_versions": "every release from 5.3.0 through 10.5.2 (the last release before 10.6.0), 10.6.0 (by reading) and main a9779ef3c193; never fixed. Executed with a version-portable geometry main() (WGS84 path 50.0N->50.3N at 10E, half-width 15 km: 3 of 3 probes at 0.4/0.6/0.8 w beyond the poleward end missed, north cap reach 0.31 w; path 45.0N->45.2N, half-width 1 km: 4 of 4 points 5/10/20/30 km south of the first point wrongly inside, south reach 42.81 km; SPHERE control correct) on 5.3.0, 5.5.5, 6.0.0, 6.0.1, 6.1.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.4.2, 9.5.0, 9.12.3, 10.0.0, 10.5.2 and main, with identical numbers to two decimals in every one. End-to-end JUnits (newPathQuery, newPathSort) fail on 9.12.3, 10.5.2 and main (-ea and -da on main). Other 5.3-10.5 minor releases are inferred from the unchanged construction [read]. Upstream main a95c754ee003, branch_10x, branch_10_6 and branch_10_5 carry the same code at the fix site [read]. Not affected: 5.2.1 and older (sphere only). All runs on JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-736.html",
   "repro": "repro/LFV-736/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-551",
   "priority": "medium",
   "priority_rank": 189,
   "novelty": "new",
   "withheld": false,
   "area": "spatial3d / Geo3DDocValuesField sort comparators (Geo3DPointDistanceComparator, Geo3DPointOutsideDistanceComparator; all seven Geo3D sort factories)",
   "title": "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)",
   "summary": "You index documents with Geo3DDocValuesField, at least one of them with two or more points (the javadoc allows this and says the closest one is used), and ask for the top 2 hits sorted by Geo3DDocValuesField.newDistanceSort; you expect the head of the full sorted order, each hit carrying its own closest distance. Instead the top 2 come back in the wrong order and a hit reports the distance of the next document, because the comparator reads the document's values once in compareBottom (or compareTop) and again in copy without re-positioning the SortedNumericDocValues iterator, which its javadoc forbids ('Do not call this more than docValueCount times'), so the second read takes the following document's values or runs past the end of the data and throws EOFException. The same happens with searchAfter paging and all seven Geo3D sort factories, and because document order decides which value is read, a hit can report the distance of a document that a filter, a live-docs wrapper or a delete hides from the search.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f7aa200d406dbd05a35d6116198302d90b92cb29 (LUCENE-7407 'Explore switching doc values to an iterator API', migrated GitHub issue #8460, committed by mikemccand from a patch attached to the JIRA issue; no pull request) [read]. It converted Geo3DPointDistanceComparator and Geo3DPointOutsideDistanceComparator from setDocument(doc)/valueAt(i) (idempotent random access) to advance(doc)/docValueCount()/nextValue() (a forward-only cursor) with no per-document cache, while the same commit added the valuesDocID/currentValues cache to LatLonPointDistanceComparator. The sort API itself came earlier with LUCENE-7212 (07af00d8e7b and cc263413457 on master, 8a407f0399c and aa339a2f075 on branch_6x, 2016-05-17/18) and was correct then.",
   "introduced_date": "2016-09-21 (f7aa200d406, LUCENE-7407); the sort API dates from 2016-05-17/18 (LUCENE-7212)",
   "first_affected_version": "7.0.0 [exec] (the first release containing f7aa200d406); not affected: 6.1.0, 6.2.1 and 6.6.6 [exec] (random-access doc values API; the Geo3D sort API first shipped in 6.1.0), and no 6.x release contains the commit [read]",
   "affected_versions": "every release from 7.0.0 to 10.5.2 plus main ea57360912ed; never fixed. [exec] the follow-up's history probe (main(), public API, WGS84, newDistanceSort and newOutsideDistanceSort, FS and heap directories) fails on 7.0.0, 7.7.3, 8.0.0, 8.4.1, 8.5.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) and passes on 6.1.0, 6.2.1 and 6.6.6; the finder's JUnit fails 5 of 5 on main (-ea, -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 10 of 10 on main (-ea, -da), 10.5.2 and 9.12.3; the intended-behaviour check's probe fails on main and 10.5.2; the security probe fails 7 of 7 on main (-ea, -da), 10.5.2 and 9.12.3. The last-document layout returns a silently wrong distance on 7.x and 8.x and throws (IndexOutOfBoundsException or RuntimeException(EOFException)) from 9.0.0, a change attributed to the Lucene90 doc-values codec by observation, not bisected. [read] 65 release tags contain f7aa200d406, plus 8.8.2-8.11.4 cut from the old combined repository's branch_8x (8.11.4 executed); the read loops are unchanged since f7aa200d406; upstream main (ffa9d816eeb, 2026-10-26) and branch_10x have not touched either comparator since 2021. Not executed: the releases between the executed points and the 10.6.x/10.7.x branches",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-551.html",
   "repro": "repro/LFV-551/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-544",
   "priority": "medium",
   "priority_rank": 190,
   "novelty": "new",
   "withheld": false,
   "area": "spatial3d / Geo3DDocValuesField sort comparators (Geo3DPointDistanceComparator, Geo3DPointOutsideDistanceComparator: compareTop under searchAfter paging)",
   "title": "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)",
   "summary": "You sort by Geo3DDocValuesField.newDistanceSort (or the path or outside-distance sorts) on the default WGS84 planet model, take the last FieldDoc of page 1 and call IndexSearcher.searchAfter(last, query, n, sort), expecting the next hits in distance order, as searchAfter documents. Instead the comparator's value() returns the distance in meters (as the factories' javadoc says), but compareTop compares that meters cursor with the document's distance in planet units (distances on a planet of mean radius 1), so every document with a finite distance looks 'already collected on a previous page' and is skipped. With six documents 3 to 8 degrees north of the origin and page size 2, page 2 should be [2, 3, 4, 5] and is []; on PlanetModel.SPHERE, where meters and planet units coincide, the same paging is correct.",
   "impact_class": "silent wrong results",
   "introduced_commit": "07af00d8e7bc4ce2820973e2ab511bfe536654c6 (LUCENE-7212 'Add Geo3D sorted document fields', now apache/lucene#8267, still open; distance and path sorts) and cc263413457c826914c3f3c1c26f885330a931aa (LUCENE-7212 'Add outside distance classes and methods'; outside sorts); the branch_6x copies 8a407f0399c6 and aa339a2f0756 are the commits in 6.1.0; no PR (committed from JIRA) [read]. Not a regression: the meters javadoc and the mismatch arrived in the same commit",
   "introduced_date": "2016-05-17 (distance and path comparator); 2016-05-18 (outside-distance comparator)",
   "first_affected_version": "6.1.0 [exec] (first release with the Geo3D sort API; 6.0.1 [exec] has no Geo3DDocValuesField, the probe does not compile)",
   "affected_versions": "Every release from 6.1.0 through 10.5.2, and main ea57360912ed and a9779ef3c193; never fixed (upstream main still has the unconverted compareTop at Geo3DPointDistanceComparator.java:159-161, and the last upstream commit to either comparator is the 2021 LUCENE-9570 reformat, both checked read-only on 2026-10-26). [exec] the follow-up's version-portable main() probes (all seven factories; from 8.5.0 also CLARKE_1866 and a SPHERE control) lose every page-2 hit on 6.1.0, 6.6.6, 7.7.3, 8.4.1, 8.5.0, 8.11.4, 9.12.3, 10.5.2 and main, while a cursor hand-divided by the mean radius pages correctly on all of them; the finder's main() probes also fail on 7.0.0; the finder's JUnit fails 5 of 6 (SPHERE control passes) on main (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's JUnits fail 7 of 10 (3 controls pass) on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's probe fails 2 of 5 (3 controls pass) on main (-ea and -da), 10.5.2 and 9.12.3; re-runs on main, 10.5.2 and a9779ef3c193 agree. [read] a scan of 81 release tags (162 comparator file versions, 6.1.0-10.5.2) finds compareTop and setTopValue unchanged in every one; the history clone lacks the 8.8.2-8.11.4 tags (8.11.4 executed). Releases older than 9.12.3 were executed with main() probes, not the JUnit",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-544.html",
   "repro": "repro/LFV-544/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-807",
   "priority": "medium",
   "priority_rank": 191,
   "novelty": "new",
   "withheld": false,
   "area": "queries / intervals (Intervals.ordered and unorderedNoOverlaps with equal consecutive sub-sources: OrderedIntervalsSource.deduplicate, RepeatingIntervalsSource)",
   "title": "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",
   "summary": "You ask for two occurrences of X in order with Intervals.ordered(X, X), for example X = unordered(a, b) ('a near b', twice) or X = phrase(a, a), and expect the usual ordered rule that the sub-intervals do not overlap (the fn:ordered documentation says 'Source intervals must not overlap'). Instead, because the two arguments are equal, OrderedIntervalsSource.build merges them into a RepeatingIntervalsSource, which joins consecutive intervals of a single sub-iterator without checking that they are disjoint, so ordered(unordered(a, b), unordered(a, b)) matches 'a b a', which has only one b, and ordered(phrase(a, a), phrase(a, a)) matches 'a a a'. The same query with an equivalent but unequal second source, ordered(X, or(X, a term that occurs nowhere)), correctly finds nothing, and so did Lucene 8.4.1.",
   "impact_class": "silent wrong results",
   "introduced_commit": "7c1ba1aebeea540b67ae304deee60162baee2e12 (master) and its branch_8x backport aa916bac3c3369a461afa06e384e070657c32973 (the same day; the first released form, in 8.5.0): 'LUCENE-9099: Correctly handle repeats in ORDERED and UNORDERED intervals' (apache/lucene-solr#1097 by romseygeek, one approving review by jimczi, no inline review comments; the JIRA issue is now apache/lucene#10141). It created RepeatingIntervalsSource and added OrderedIntervalsSource.deduplicate(), called from build() for every ordered() source [read] [exec]. Later commits to the two files (LUCENE-9418, LUCENE-10140, #12214, #13819, #13871, #13937, #15889) left the deduplication unchanged [read]",
   "introduced_date": "2020-02-06 (7c1ba1aebee and the branch_8x backport aa916bac3c3)",
   "first_affected_version": "8.5.0 [exec] (8.4.1, the last release before LUCENE-9099, passes [exec]; 8.5.0 with only the deduplicate() call removed passes [exec])",
   "affected_versions": "every release from 8.5.0 through 10.5.2 (52 releases: 8.5.0 to 8.11.4, all 9.x and all 10.x) [exec]; main a9779ef3c193 [exec]; branch_10_6 head 4ae946e5a9b [exec], so the released 10.6.0 has it; upstream main 20ced71c1e6 [read]. Not affected [exec]: 8.2.0, 8.3.0, 8.3.1, 8.4.0 and 8.4.1. Reachable from query text (fn:ordered, fn:unorderedNoOverlaps) since 9.1.0 (LUCENE-10223); 8.5.0 to 9.0.0 through the Java Intervals API only. All three shapes (repeated phrase, repeated unordered pair, repeated nested ordered) fail from 8.5.0 on [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-807.html",
   "repro": "repro/LFV-807/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-306",
   "priority": "medium",
   "priority_rank": 192,
   "novelty": "new",
   "withheld": false,
   "area": "queries / intervals (Intervals.ordered/unordered with equal sub-sources: RepeatingIntervalsSource, maxgaps)",
   "title": "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",
   "summary": "You search with an interval query that repeats a multi-word piece, for example maxgaps(0, ordered(phrase(new, york), phrase(new, york))) on the text 'new york new york', and expect a match because the two phrases sit back to back with no gap. Instead it finds nothing: Lucene turns equal sub-sources into a RepeatingIntervalsSource whose iterator adds start - end + 1 instead of end - start + 1 for each copy, so width() is 0 instead of 4, gaps() is 4 instead of 0, and maxgaps rejects the interval. The Matches path of the same class uses the right formula, so Weight#matches returns a match for the very document the scorer rejected; repeats of single words are unaffected because their start equals their end.",
   "impact_class": "silent wrong results",
   "introduced_commit": "aa916bac3c3369a461afa06e384e070657c32973 (branch_8x, the commit first released, in 8.5.0) and 7c1ba1aebeea540b67ae304deee60162baee2e12 (master, the same patch on the same day, first released in 9.0.0): 'LUCENE-9099: Correctly handle repeats in ORDERED and UNORDERED intervals' (apache/lucene-solr#1097, the JIRA issue is now apache/lucene#10141; author romseygeek; one approving review by jimczi, no inline review comments) [read] [exec]. The same commit added the Matches twin DuplicateMatchesIterator.width() with the correct end - start + 1. Present since the class was created, not a regression; #13819 (first released in 10.1.0, stops flattening nested ordered sources) later widened the query shapes that reach it without touching the file",
   "introduced_date": "2020-02-06 (aa916bac3c3 and 7c1ba1aebee)",
   "first_affected_version": "8.5.0 [exec] (8.4.1, the last release before LUCENE-9099, is not affected [exec]; 8.5.0 with only the sign of its line 159 corrected passes every check [exec]; JIRA fixVersion 8.5 and the 8.5.0 CHANGES entry for LUCENE-9099 [read])",
   "affected_versions": "every release from 8.5.0 through 10.6.0 (10.6.0 by reading; the 52 releases through 10.5.2: all 8.5.x to 8.11.x, 9.x and 10.x) and main ea57360912ed [exec] by the follow-up history probe RepeatWidthHistoryProbe (a portable main() probe with the JUnit's assertions; 5 checks fail and 3 controls pass, with byte-identical failing-check text on 8.5.0, 9.0.0, 10.5.2 and main; -ea, and main also -da); the finder's JUnit fails 2 of 2 on 9.1.0, 9.12.3, 10.5.2 and main (-ea and -da), the independent reproduction's JUnit 7 of 9 on main (-ea and -da), 10.5.2 and 9.12.3, and the security probe 6 of 8 on main (-ea and -da), 10.5.2 and 9.12.3. Not affected [exec]: 8.2.0, 8.3.0, 8.3.1, 8.4.0 and 8.4.1 (no RepeatingIntervalsSource; ordered/unordered gaps were computed from sub-iterator positions). Not affected [read]: releases before 8.2.0 (intervals lived in the sandbox and the class did not exist). Trigger shapes: the phrase form and a nested ordered repeated inside unordered from 8.5.0; a nested ordered(X, X) repeated inside ordered only from 10.1.0, because before #13819 it was flattened into ordered(a, b, a, b) [exec]. 8.8.2 and 8.9.0 to 8.11.4 were executed but their tags are not in the local history clone. Not fixed: the line is unchanged on upstream main, branch_10x, branch_10_6 and branch_10_5, and no open PR touches the file [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-306.html",
   "repro": "repro/LFV-306/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-809",
   "priority": "medium",
   "priority_rank": 193,
   "novelty": "new",
   "withheld": false,
   "area": "queries / intervals (gap-sensitive disjunction rewrite of LUCENE-8477 vs repeated equal sub-sources: RepeatingIntervalsSource.pullUpDisjunctions, Ordered/UnorderedIntervalsSource.deduplicate)",
   "title": "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",
   "summary": "You build an interval query that uses the same OR twice, for example maxgaps(0, unordered(X, X)) with X = or(b, phrase(c, b)), and expect what the Intervals.or javadoc promises ('Automatically rewrites if wrapped by an interval source that is sensitive to internal gaps'), so that 'c b c b' matches through b at position 1 followed by the phrase 'c b' at positions 2-3, which do not overlap and leave no gap. Instead, because the two arguments are equal, Lucene merges them into one RepeatingIntervalsSource whose pullUpDisjunctions() returns only itself, so the rewrite never runs, the longer 'c b' alternative is minimized away inside X, and the query returns no hits. maxgaps(0, ordered(X, X)) and phrase(a, ordered(X, X)) miss in the same way, and so does Intervals.analyzedText for the query text 'york york' with a synonym york -> 'new york' (unordered, maxGaps 0) on the document 'new york new york'.",
   "impact_class": "silent wrong results",
   "introduced_commit": "7c1ba1aebeea540b67ae304deee60162baee2e12 (master, released from 9.0.0) and its branch_8x backport aa916bac3c3369a461afa06e384e070657c32973 (the first released form, in 8.5.0), both 2020-02-06: 'LUCENE-9099: Correctly handle repeats in ORDERED and UNORDERED intervals' (apache/lucene-solr#1097 by romseygeek, one approving review by jimczi; the JIRA issue is now apache/lucene#10141). It added Ordered/UnorderedIntervalsSource.deduplicate, which folds equal sub-sources into RepeatingIntervalsSource, and RepeatingIntervalsSource.pullUpDisjunctions returning Collections.singleton(this) [read] [exec]",
   "introduced_date": "2020-02-06 (7c1ba1aebee and the branch_8x backport aa916bac3c3)",
   "first_affected_version": "8.5.0 [exec] (8.4.1, the last release before LUCENE-9099, passes [exec]; the commit-level A/B on the 8.5.0 jars pins it to aa916bac3c3 [exec]). For the unordered shape and a run of equal sources inside a longer ordered, 8.4.1 returned the hit only through the pre-LUCENE-9099 over-match (the two copies shared one position, which also matched a lone 'b'), so those shapes were never right; the two-argument ordered and phrase shapes are a clean regression",
   "affected_versions": "every release from 8.5.0 through 10.5.2 [exec] [read]; branch_10_6 head 4ae946e5a9b [exec], so the released 10.6.0 has it; main a9779ef3c193 [exec]; upstream main 20ced71c1e6 [read]. Not affected: 8.4.1 [exec]. Reachable from query text through StandardQueryParser fn: functions (fn:maxgaps, fn:unordered, fn:or) on main [exec]; the fn: syntax arrived in 9.1.0 (LUCENE-10223) [read]; before that, through the Java Intervals API only",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-809.html",
   "repro": "repro/LFV-809/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-810",
   "priority": "medium",
   "priority_rank": 194,
   "novelty": "known",
   "withheld": false,
   "area": "queries / intervals (a whole ordered/unordered of equal sub-sources nested in another operator: RepeatingIntervalsSource width(), Ordered/UnorderedIntervalsSource.deduplicate)",
   "title": "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'",
   "summary": "You nest a repeated pair inside another interval operator, for example ordered(ordered(a, a), a), and filter it with maxgaps(0, ...): the IntervalIterator#gaps javadoc counts only the gaps between the parent's immediate sub-intervals, so 'a x a a' (sub-intervals [0,2] and [3,3]) should match, just as maxgaps(0, ordered(ordered(a, b), a)) matches 'a x b a'. Instead, because the two arguments of the inner ordered(a, a) are equal, Lucene builds it as a RepeatingIntervalsSource whose width() is the sum of its two copies (2) rather than its span (3), so the parent counts the inner 'x' as its own gap (gaps 1) and maxgaps(0) silently drops the document. The same happens for ordered(unordered(a, a), b), unordered(ordered(a, a), b) and ordered(x, ordered(a, a)), while wrapping the inner pair in a no-op filter such as maxwidth(100, ...) brings the hit back.",
   "impact_class": "silent wrong results",
   "introduced_commit": "7c1ba1aebeea540b67ae304deee60162baee2e12 (master, first released in 9.0.0) and its branch_8x backport aa916bac3c3369a461afa06e384e070657c32973 (the same day; first released in 8.5.0): 'LUCENE-9099: Correctly handle repeats in ORDERED and UNORDERED intervals' (apache/lucene-solr#1097 by romseygeek, one approving review by jimczi; the JIRA issue is now apache/lucene#10141). It changed ordered/unordered gaps() to span minus the sum of the children's width(), added IntervalIterator#width() and RepeatingIntervalsSource with a summed width(), and made deduplicate() replace a whole ordered(a, a)/unordered(a, a) by a RepeatingIntervalsSource that only setName(\"ORDERED\"/\"UNORDERED\") marks [read] [exec]. For the same-operator shapes the defect shows as its own bug only from 10.1.0, after #13819 (82b08045fd3c on main, 0f2fac699a35 on branch_10x) removed flattening; #13819 did not introduce it [exec]",
   "introduced_date": "2020-02-06 (7c1ba1aebee and the branch_8x backport aa916bac3c3)",
   "first_affected_version": "8.5.0 [exec] for the cross-operator shapes ordered(unordered(a, a), b) and unordered(ordered(a, a), b); 10.1.0 [exec] for the same-operator shapes ordered(ordered(a, a), a) and ordered(x, ordered(a, a)), whose unequal-term controls also fail before 10.1.0 because of the flattening that #13819 removed; 8.4.1 and earlier are not affected in this form [exec]",
   "affected_versions": "every release from 8.5.0 through 10.5.2 (52 releases, each executed once with the independent reproduction's 11-test per-shape probe, -ea): 8.5.0 to 10.0.0 show the two cross-operator shapes failing while their unequal-term controls pass; 10.1.0 to 10.5.2 show all four shapes failing while every control passes [exec]; main a9779ef3c193 [exec]; branch_10_6 [exec], so the released 10.6.0 has it; upstream main 20ced71c1e6e [read]. Not affected [exec]: 8.2.0 to 8.4.1 (there ordered(unordered(a, a), b) is wrong in another way, the single-'a' match that LUCENE-9099 fixed). Reachable from query text: fn:maxgaps(0 fn:ordered(fn:ordered(a a) a)) misses 'a x a a' on main and 10.5.2 [exec]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/13819",
    "https://github.com/apache/lucene/issues/10141",
    "https://issues.apache.org/jira/browse/LUCENE-9099",
    "https://github.com/apache/lucene/issues/9643",
    "https://issues.apache.org/jira/browse/LUCENE-8597",
    "https://github.com/apache/lucene/issues/16913"
   ],
   "doc": "",
   "repro": "repro/LFV-810/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-247",
   "priority": "medium",
   "priority_rank": 195,
   "novelty": "new",
   "withheld": false,
   "area": "spatial3d / Geo3DDocValuesField distance sorts (Geo3DPointDistanceComparator, Geo3DPointOutsideDistanceComparator; GeoStandardCircle membership test on the decoded doc value)",
   "title": "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",
   "summary": "You store locations with Geo3DDocValuesField on the default WGS84 model and sort hits with Geo3DDocValuesField.newDistanceSort(field, lat, lon, 1000, WGS84), expecting ascending distance from the centre with the distance in metres (and, with newOutsideDistanceSort, 0.0 for points inside the circle). Instead about half of the documents inside the 1 km radius, even ones 10 m from the centre, get +Infinity and sort last as if they had no location, some documents 2-3 km away get finite distances and sort ahead of them, and inside documents get outside distances of up to 988 m, while LatLonDocValuesField's distance sort orders the same points correctly. The cause: each doc value decodes to a point up to about 4.5 m off the planet surface, and the comparators pass that point unprojected to the circle's membership test, a single plane that for a 1 km circle lies only about 8 cm below the surface at the centre, so the decode error, not the distance, decides in or out.",
   "impact_class": "silent wrong results",
   "introduced_commit": "07af00d8e7bc4ce2820973e2ab511bfe536654c6 (master, 2016-05-17, 'LUCENE-7212: Add Geo3D sorted document fields.' by DaddyWri: Geo3DPointDistanceComparator, Geo3DPointSortField and newDistanceSort) and cc263413457c826914c3f3c1c26f885330a931aa (2016-05-18, 'LUCENE-7212: Add outside distance classes and methods.': Geo3DPointOutsideDistanceComparator and newOutsideDistanceSort); 6.1.0 shipped their branch_6x backports 8a407f0399c6 and aa339a2f0756; both comparators passed the raw decoded x,y,z to computeDistance/computeOutsideDistance from their first version; precondition 351878223ddb / backport 0e9ec477d76d (2016-05-12, 'LUCENE-7212: Add geo3d doc values field', the 21-bit-per-dimension encoding, also new in 6.1.0); committed from the JIRA patch, no pull request; LUCENE-7212 is apache/lucene#8267, still open [read]",
   "introduced_date": "2016-05-17 (newDistanceSort, Geo3DPointDistanceComparator); 2016-05-18 (newOutsideDistanceSort, Geo3DPointOutsideDistanceComparator)",
   "first_affected_version": "6.1.0 [exec] (release tag 2016-06-12; the first release with Geo3DDocValuesField and its sorts; fails with -ea and -da, the 50 km control passes and a shadowed surface-projection fix passes); 6.0.1 and earlier have no Geo3DDocValuesField [exec]",
   "affected_versions": "every release from 6.1.0 through 10.5.2 (the last release before 10.6.0) and main ea57360912ed. [exec] a version-neutral public-API main() (two API-era variants that differ in 3 calls) fails with identical counts on 6.1.0 (-ea and -da), 6.3.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.4.1, 8.5.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (17 of 36 documents 500 m from the centre get +Infinity under a 1 km sort, 14 of 36 documents 3 km away get finite distances, 17 of 36 inside documents get an outside distance above 1 m); the finder's JUnit fails on main (-ea, -da), 10.5.2 and 9.12.3, the independent reproduction's JUnit and the intended-behaviour check's probe on main (-ea, -da), 10.5.2 and 9.12.3. [read] the decode-then-test code in both comparators is unchanged since the 2016 commits: the later changes (LUCENE-7430 bounds slop, LUCENE-7407 iterator API, LUCENE-6228 Scorable, LUCENE-9150 PlanetModel API, LUCENE-9263 metres-to-radians, LUCENE-9570 formatting) did not change what reaches computeDistance, and the executed releases on both sides of each change fail the same way; unexecuted intermediate releases are inferred. Not fixed on main; no open PR touches the comparators (#14775 only adds inverseSort to the sort fields). Not affected: 6.0.1 and earlier (API absent) [exec]. All runs with JDK 25.0.3 on an aarch64 host.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-247.html",
   "repro": "repro/LFV-247/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-701",
   "priority": "medium",
   "priority_rank": 196,
   "novelty": "new",
   "withheld": false,
   "area": "core / document: LatLon point geometry queries (LatLonDocValuesQuery CONTAINS on the doc-values path vs LatLonPoint.newGeometryQuery, and their IndexOrDocValuesQuery pairing)",
   "title": "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",
   "summary": "You index points with LatLonPoint and LatLonDocValuesField and ask for the documents that contain both P1 and P2 (CONTAINS with two Point geometries); a document that holds only P1 must not match, and LatLonPoint.newGeometryQuery, which builds one MUST clause per query point, indeed matches none. LatLonDocValuesField.newSlowGeometryQuery, which its javadoc says to pair with that query in an IndexOrDocValuesQuery (whose two queries 'must match the same documents'), accepts a document as soon as any one of its points equals any one query point, so it computes an OR instead of an AND. In the repro (1000 one-point documents, half at P1 and half at P2) the points query returns 0 hits, the doc-values query returns all 1000, and 'id:7 AND IndexOrDocValuesQuery(points, docValues)' returns document 7, with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "14009f4424d847ce84fa23a71d8066dfe6c70da0 (LUCENE-9641 'Support for spatial relationships in LatLonPoint', apache/lucene-solr#2155, issue now apache/lucene#10680; author iverase; branch_8x backport f73f6b11f0ed4bcbfce445152d813adb3327d249, apache/lucene-solr#2188, shipped in 8.8.0) [read]. The same commit made LatLonPoint.newGeometryQuery(CONTAINS) a conjunction (makeContainsGeometryQuery; commit message 'Equivalent to LatLonShape'), so the bug is as old as the feature.",
   "introduced_date": "2021-01-08",
   "first_affected_version": "8.8.0 [exec] (the relation-taking factories first appear there; 8.7.0 lacks them [exec])",
   "affected_versions": "Every release that has the API: 8.8.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2, and main a9779ef3c193; never fixed. [exec] the version-portable main() port fails on 8.8.0, 8.8.1, 8.8.2, 8.9.0, 8.10.1, 8.11.4, 9.0.0, 9.1.0, 9.11.1, 9.12.0, 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.2.2, 10.3.0, 10.4.0, 10.5.2 and main (-ea and -da), with LatLonPoint CONTAINS(P1,P2) = 0 and LatLonDocValuesField CONTAINS(P1,P2) = 1000 (expected 0) on every one; the finder's JUnit fails on main (-ea, -da), 10.5.2, 10.0.0, 9.12.3 and 9.1.0; the independent reproduction's and the intended-behaviour check's own tests fail on main, 10.5.2 and 9.12.3. On 10.0.0-10.2.0 the MUST(id)+FILTER(IndexOrDocValuesQuery) form returned 0 because a separate, fixed planner bug (apache/lucene#14542, fixed by #14543 in 10.2.1 and 10.3.0) made IndexOrDocValuesQuery run the points side; the doc-values query alone and the FILTER(id)+FILTER(IndexOrDocValuesQuery) form still fail there. The LatLonDocValuesQuery.contains() source is identical in the 35 local release tags from 8.8.0 to 10.5.2 and on main, and the LatLonDocValuesQuery class files of the 8.8.0 and 8.11.4 jars are byte-identical [read]. All runs with JDK 25 and SHA-1-checked release jars.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-701.html",
   "repro": "repro/LFV-701/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1132",
   "priority": "medium",
   "priority_rank": 197,
   "novelty": "new",
   "withheld": false,
   "area": "core / document: XY distance sort (XYDocValuesField.newDistanceSort, XYPointDistanceComparator)",
   "title": "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)",
   "summary": "You sort three documents, (cat b, distance 1), (cat a, no location) and (cat a, distance 3), with Sort(new SortField(\"cat\", STRING), XYDocValuesField.newDistanceSort(\"loc\", 0, 0)) and ask for the top 1; you expect the (a, 3) document, because ties on cat are broken by ascending distance and a missing location counts as +Infinity and sorts last. Instead you get the (a, no location) document: when it becomes the queue bottom, setBottom skips rebuilding the comparator's bounding box because +Infinity is not below Float.MAX_VALUE, so the box built for the earlier bottom at distance 1 stays, and compareBottom rejects the (a, 3) document as outside it. The same stale box arises after 1024 bottom updates, when only every 64th update rebuilds it and the bottom grows on another one; a nearest-first distance sort is not affected because its bottom only shrinks.",
   "impact_class": "silent wrong results",
   "introduced_commit": "c653c04bb1717f9813e50d2fd2cef1d323ee6036 (master, now main; branch_8x copy d9787406f895d166e0d13eb5ce8a98865f1f3e39), 'LUCENE-9243: Add fudge factor when creating a bounding box of a xycircle (#1278)' by iverase (migrated issue apache/lucene#10283, PR apache/lucene-solr#1278, one 'LGTM' review), for the missing-value trigger of the minimal repro: it added 'bottom < Float.MAX_VALUE &&' to the rebuild condition in setBottom because the new XYRectangle.fromPointDistance throws on a non-finite radius, where the code before it built the full box for an infinite bottom (Math.max(-Float.MAX_VALUE, x - bottom) and so on) [exec]. The stale box as such (rebuild only while setBottomCounter < 1024 or on every 64th call) came with the class in 88dd1c3f3d4eb37c522b9b00a5ccce979e6efad6 (master; branch_8x copy 53cb6acf912f54a07b870fe6726bfee329b62d06), 'LUCENE-9238: Add new XYPointField, queries and sorting capabilities (#1272)' by iverase (migrated issue apache/lucene#10278, PR apache/lucene-solr#1272, 'Adaptation of LatLonPoint to generic cartesian space'), whose rebuild rule comes from LatLonPointDistanceComparator (LUCENE-7099, 2016) [exec]. Both landed before the first release with the API, so no release was ever correct",
   "introduced_date": "2020-03-02 (author date of c653c04bb17, the missing-value trigger); 2020-02-21 (author date of 88dd1c3f3d4, the class and its sampling rule)",
   "first_affected_version": "8.5.0 [exec]",
   "affected_versions": "every release from 8.5.0 through 10.6.0, and main 5adff78bb168 (unreleased 12.0.0-SNAPSHOT) [exec]. Not affected: 8.4.1 and earlier (API absent) [exec]. Not new in 10.6. Not fixed upstream: upstream main 1c2072f0284 (2026-11-02), branch_11x and branch_10_6 carry the same blob, and the file's last upstream commit is still 2d6ad2fee6d (2020-12-23, reformatting) on 2026-11-02. All runs on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1132.html",
   "repro": "repro/LFV-1132/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-612",
   "priority": "medium",
   "priority_rank": 198,
   "novelty": "new",
   "withheld": false,
   "area": "spatial-extras / prefix-tree strategies (NumberRangePrefixTreeStrategy over DateRangePrefixTree or a custom NumberRangePrefixTree; the pointsOnly TermQuery shortcut in RecursivePrefixTreeStrategy.makeGridShapeIntersectsQuery)",
   "title": "NumberRangePrefixTreeStrategy with setPointsOnly(true): an Intersects query for a date or number unit coarser than full precision (a year, month, day, ...) matches no documents",
   "summary": "You index full-precision dates such as 2014-10-23T21:22:33.159 with a NumberRangePrefixTreeStrategy over DateRangePrefixTree on which you called setPointsOnly(true), and search makeQuery(new SpatialArgs(SpatialOperation.Intersects, tree.parseShape(\"2014-10\"))). You expect the documents from October 2014, because each point lies inside that month, IsWithin with the same shape and the same query with pointsOnly=false find them, and the LUCENE-7845 CHANGES entry describes this pointsOnly TermQuery shortcut as an optimization for 'a simple date interval (e.g. 1 month)'. Instead RecursivePrefixTreeStrategy.makeGridShapeIntersectsQuery builds a TermQuery on the month's token plus the leaf byte, a term that pointsOnly indexing at full precision, the normal path, never writes (each point stores every coarser level only as a non-leaf prefix term), so the query matches nothing; the same happens for a year, day, hour, minute or second and for a range that normalizes to one unit.",
   "impact_class": "silent wrong results",
   "introduced_commit": "d4f87b4a36ca50c4361d7ec4e0858b18d9eaebe8 'LUCENE-7845: RPT query by point (or simple date interval) optimization' (by GitHub dsmiley; a JIRA patch, no GitHub PR; migrated issue apache/lucene#8896). In one commit it made setPointsOnly(true) usable with NumberRangePrefixTreeStrategy (isPointShape override accepting a unit at the maximum level), declared every UnitNRShape with level > 0 grid-aligned (isGridAlignedShape) and routed grid-aligned Intersects queries under pointsOnly to TermQuery(cell.getTokenBytesWithLeaf); the 'assert cell.isLeaf()' line came with the follow-up 6b022c98f9a (2017-06-05, also in 7.0.0) [read]",
   "introduced_date": "2017-05-26",
   "first_affected_version": "7.0.0 [exec]; 6.6.0 and 6.6.6 [exec] cannot build the trigger, because pointsOnly indexing of any date shape throws IllegalArgumentException there, and LUCENE-7845 was never backported to 6.x [read]",
   "affected_versions": "every release from 7.0.0 through 10.6.0 (10.6.0 by reading) and main a9779ef3c193 [exec]; the releases in between by code history [read]. The brief's test also fails on 10.5.2 (-ea, -da) and 9.12.3 (-da) [exec]. Not fixed upstream: upstream main head 20ced71c1e6e (2026-10-27; RecursivePrefixTreeStrategy.java last changed 2025-06-22, NumberRangePrefixTreeStrategy.java 2021-01-05) [read]; branch_10x and branch_10_6 have the same code [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-612.html",
   "repro": "repro/LFV-612/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-671",
   "priority": "medium",
   "priority_rank": 199,
   "novelty": "new",
   "withheld": false,
   "area": "spatial-extras / spatial4j bridge to spatial3d (Geo3dRectangleShape.getCrossesDateLine), read by PointVectorStrategy and BBoxStrategy",
   "title": "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",
   "summary": "You use the Geo3d spatial context (Geo3dSpatialContextFactory) with PointVectorStrategy or BBoxStrategy and query or index a box that crosses the dateline, such as rect(170, -170, -10, 10), or one that spans longitude 0, such as rect(-10, 10, -10, 10). You expect getCrossesDateLine() to follow the spatial4j Rectangle contract (true exactly when the box crosses the -180/180 meridian, that is minX > maxX, as spatial4j's RectangleImpl and this class's own getWidth() assume), so a point at longitude 175 is found inside 170..-170 and an indexed box -10..10 does not match a query box at 100..110. Instead Geo3dRectangleShape.getCrossesDateLine() returns getMaxX() > 0 && getMinX() < 0 ('spans longitude 0'), which is false for 170..-170 and true for -10..10: PointVectorStrategy searches the empty range 170..-170 and returns 0 hits (also for circle(180, 0, 5)), and BBoxStrategy stores xdl=F for the dateline box and misses it (0 hits instead of 1), but stores xdl=T for -10..10, reads it as [-10, 180] plus [-180, 10] and matches it against 100..110 (1 hit instead of 0).",
   "impact_class": "silent wrong results",
   "introduced_commit": "035523ba7a86773500c053129f65c9a6dc4fd384 (master) and its branch_7x cherry-pick 85491401d54c59e1593a5c9f13dca7bfcdda31a2 (the commit that shipped in 7.1.0): LUCENE-7951 'Spatial4j implementations using Geo3d' (migrated as apache/lucene#9000), from PR apache/lucene-solr#246 by GitHub iverase, committed directly by GitHub dsmiley (the PR was closed without a GitHub merge). The new class Geo3dRectangleShape had 'return (getMaxX() > 0 && getMinX() < 0);' from the start [read]. In the PR's first commit ea31e5ce0f getWidth() used the same test; cfbac2fb00 rewrote getWidth() to the wrap convention and left getCrossesDateLine() unchanged [read]. A regression for users of Geo3dShape: before 7.1.0 its getBoundingBox() returned a spatial4j RectangleImpl with the correct flag [exec].",
   "introduced_date": "2017-09-20 (commit date 23:09:46 -0400, i.e. 2017-09-21T03:09:46Z)",
   "first_affected_version": "7.1.0 [exec]; 7.0.0 and 7.0.1 are not affected [exec]",
   "affected_versions": "Every release from 7.1.0 through 10.6.0 (10.6.0 by reading) and main a9779ef3c193; not fixed upstream. [exec] the finder's JUnit (run by the finder and the follow-up; the 7.x and 8.x runs use a source variant that differs only in the LuceneTestCase import) fails 5 of 5 on 7.1.0, 7.7.3, 8.0.0, 8.11.4, 9.12.3, 10.5.2 and main (-ea and -da), and the bisection test fails 5 of 5 on the same releases and main and passes on 7.0.0 and 7.0.1 (follow-up); the independent reproduction's JUnit fails 5 of 5 on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's JUnit fails 5 of 8 on main (-ea and -da) and 10.5.2. [read] the line is unchanged since 035523ba7a8 except for the 2021 reformat; the 8.9.0-8.10.x tags are not in the local clone (inferred affected from 8.8.1 and the executed 8.11.4); upstream main, branch_10x and branch_10_6 still have the line (read 2026-10-27).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-671.html",
   "repro": "repro/LFV-671/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-673",
   "priority": "medium",
   "priority_rank": 200,
   "novelty": "new",
   "withheld": false,
   "area": "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()",
   "title": "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)",
   "summary": "You use the Geo3d spatial context and relate a Geo3d shape to a spatial4j rectangle that the Geo3d shape factory did not build, for example a 10-degree circle against the context's own ctx.getWorldBounds(), or run a SerializedDVStrategy IsWithin(ctx.getWorldBounds()) query over that circle, and expect WITHIN (the circle lies inside the world) and one hit. Instead relate() returns CONTAINS and the query matches nothing, while Contains(world bounds) matches the circle: Geo3dShape.relate(Rectangle) asks spatial3d how this shape relates to the rectangle but then applies the mapping written for the opposite question (how the other shape relates to this one), so the two nested answers come out swapped, whereas the same box built by the Geo3d factory relates correctly. Lucene builds such rectangles itself, so RecursivePrefixTreeStrategy over PackedQuadPrefixTree, whose cells are plain spatial4j rectangles, treats a cell that contains a small query circle as lying inside the circle and returns every document in that cell, for example a point at (100.3, 37.7) for a half-degree circle at (1, 1).",
   "impact_class": "silent wrong results",
   "introduced_commit": "035523ba7a86773500c053129f65c9a6dc4fd384 (main) and its identical branch_7x cherry-pick 85491401d54c59e1593a5c9f13dca7bfcdda31a2 (the commit that shipped in 7.1.0): LUCENE-7951 'Spatial4j implementations using Geo3d' (issue apache/lucene#9000), code from apache/lucene-solr#246 by GitHub iverase (closed unmerged 2017-09-29), committed by GitHub dsmiley [read]. A regression; later commits on these lines (0673c57ecf4, d66d9549d7c, 2cbf261032d, dfd536186fe / #15889) are behaviour-neutral.",
   "introduced_date": "2017-09-20 (both commits); first release 7.1.0 (tag 2017-10-16)",
   "first_affected_version": "7.1.0 [exec]; 7.0.1 and 6.6.6 pass the same-source tests [exec] (old, correct mapping; the finder's JUnit does not compile there because Geo3dSpatialContextFactory and the generic Geo3dShape<T> first appear in 7.1.0)",
   "affected_versions": "Every release from 7.1.0 to 10.6.0 (10.6.0 by reading: the doc reads branch_10_6) and main a9779ef3c193; not fixed upstream. [exec] the finder's JUnit fails 3 of 3 on 7.1.0, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main (-ea; main also -da); the independent reproduction's JUnit fails 4 of 4 on 8.11.4, 9.12.3, 10.5.2 and main (-ea; main also -da); the independent reproduction's PackedQuad RPT probe fails on 10.5.2 and main; the follow-up's same-source tests fail on 7.1.0, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main (main with -ea and -da) and pass on 6.6.6 and 7.0.1. [read] a source scan of 63 local release tags from 7.1.0 to 10.5.2 shows the same swapped path (8.8.2-8.11.4 are not tagged locally; 8.11.4 was executed from its release jar); 6.6.6, 7.0.0 and 7.0.1 have the old correct mapping; main, branch_10x and branch_10_3 have the same behaviour (main in the #15889 switch-pattern form, the branches in the 10.x form), and the only open PR touching the file (#12295) is a refactor that keeps the mapping.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-673.html",
   "repro": "repro/LFV-673/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-679",
   "priority": "medium",
   "priority_rank": 201,
   "novelty": "known",
   "withheld": false,
   "area": "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",
   "title": "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)",
   "summary": "You use the Geo3d spatial context and build a point from longitude 30, latitude 10 and an elevation of 0, with ShapeFactory.pointXYZ(30, 10, 0) or by reading the GeoJSON position [30, 10, 0], and expect the point (30, 10), which is what spatial4j's own factory returns and what its contract implies (pointXYZ is pointXY plus a third dimension that an implementation may ignore or reject). Instead you get longitude 18.43, latitude 0: Geo3dShapeFactory.pointXYZ and the builders' shared Geo3dPointBuilder.pointXYZ hand the three numbers to spatial3d's new GeoPoint(x, y, z), which reads them as a geocentric Cartesian vector, so points, lines and multi-points built this way silently land elsewhere (a multi-point relates DISJOINT to its own vertex) and a polygon whose vertices all have z = 0 is rejected with InvalidShapeException 'Invalid polygon, all points are coplanar'. The reviewer of the original change had noted that these x, y, z are longitude, latitude and a user-defined value, 'not geo-centric coordinates', but the code was committed unchanged in 2017.",
   "impact_class": "silent wrong results",
   "introduced_commit": "035523ba7a86773500c053129f65c9a6dc4fd384 (master, first released in 8.0.0) and its branch_7x backport 85491401d54c59e1593a5c9f13dca7bfcdda31a2 (first released in 7.1.0): LUCENE-7951 'Spatial4j implementations using Geo3d' (issue apache/lucene#9000), code from apache/lucene-solr#246 by GitHub iverase (closed unmerged 2017-09-29), committed by GitHub dsmiley [read]. PR history: the builder pointXYZ was geocentric from the first revision ea31e5ce0f (2017-09-07), in which the factory pointXYZ still threw UnsupportedOperationException; 9f2f3e3e20 (2017-09-12) made the factory pointXYZ geocentric for a new internal caller (Geo3dDistanceCalculator.pointOnBearing) and kept the throw as a comment; review comment r138331920 objected the same day; 60289de3ac (same day) moved pointOnBearing off pointXYZ, leaving both geocentric bodies with no caller. Later commits on these lines are formatting only (LUCENE-9570, 2cbf261032d).",
   "introduced_date": "2017-09-20 (both commits); first release 7.1.0 (October 2017)",
   "first_affected_version": "7.1.0 [exec]; 7.0.1 and earlier have no Geo3d spatial context or Geo3dShapeFactory (the repro does not compile on 7.0.1 [exec])",
   "affected_versions": "Every release from 7.1.0 to 10.6.0 (10.6.0 by reading) and main a9779ef3c193; not fixed upstream (the Geo3dShapeFactory.java blob on upstream main and branch_10x, 5404d85d6335, equals the tested one). [exec] the finder's JUnit fails 2 of 2 on 7.1.0, 7.5.0, 7.6.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (main with -ea and -da); the independent reproduction's JUnit fails 4 of 4 on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's JUnit fails 2 of 2 on main (-ea and -da) and 10.5.2. Symptom change: on 7.1.0-7.5.0 the z = 0 polygon is built around a null shape and throws NullPointerException on its first relate(); from 7.6.0 (LUCENE-8522) build() throws InvalidShapeException 'all points are coplanar'; the point relocation is identical in every version. [read] releases between the executed ones carry the same code by blame (only the LUCENE-9570 reformatting); the head of branch_10_6, from which 10.6.0 was released on 2026-10-29, and the unreleased branch_10x head in the local clone carry the same code.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene-solr/pull/246",
    "https://github.com/apache/lucene/issues/9000",
    "https://issues.apache.org/jira/browse/LUCENE-7951",
    "https://github.com/apache/lucene/issues/9568",
    "https://issues.apache.org/jira/browse/LUCENE-8522",
    "https://github.com/apache/lucene/issues/9267"
   ],
   "doc": "",
   "repro": "repro/LFV-679/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-308",
   "priority": "medium",
   "priority_rank": 202,
   "novelty": "new",
   "withheld": false,
   "area": "core / document: shape doc-values queries (BaseShapeDocValuesQuery via SpatialQuery) and the query cache",
   "title": "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",
   "summary": "You keep a shape in a doc-values-only field (LatLonShape.createDocValueField or XYShape.createDocValueField), run LatLonShape/XYShape.newSlowDocValuesBoxQuery through a query cache, then move one document's shape out of the box with IndexWriter#updateDocValues and reopen the reader. You expect the reopened searcher to stop matching that document, because a query that reads doc values must report itself not cacheable once those doc values have been updated (SegmentCacheable). Instead its Weight#isCacheable stays true (inherited from SpatialQuery#queryIsCacheable, which always returns true), the segment keeps its core cache key, and the cache keeps serving the pre-update result (5 hits instead of 4 in the repro) until the segment is merged away or the entry is evicted.",
   "impact_class": "silent wrong results",
   "introduced_commit": "d7fd48c9502c (LUCENE-10654 'Add new ShapeDocValuesField for LatLonShape and XYShape', apache/lucene#1017 by nknize, main; branch_9x backport ddf0d0acf4e4, #1064) [read]; inside the PR, the first commit 3554306677 had the shape doc-values query return DocValues.isCacheable(ctx, field) and the refactor commit 2cf24b47c0b6 (2022-07-20) dropped it [read]; not a regression in any release: the API shipped with the defect",
   "introduced_date": "2022-08-09 (#1017 merged on main; #1064 backport the same day); in-PR refactor commit 2022-07-20",
   "first_affected_version": "9.4.0 [exec] (first release with the API; 9.3.0 gives compile_error because the API is absent [exec])",
   "affected_versions": "all 29 releases from 9.4.0 to 10.5.2 (17 on 9.x, 12 on 10.x) and main ea57360912ed with an installed LRUQueryCache [exec]; with zero configuration (default IndexSearcher cache and caching policy, 12,000-doc segment) 9.4.0, 9.12.3, 10.0.0 and 10.5.2 [exec], not main, which has had no default query cache since GITHUB#14187 (unreleased) [exec]; 10.6.0 (branch_10_6) not executed, same source [read]; not fixed upstream: the lines are unchanged on upstream main e1c4184cb983, branch_10x and branch_10_6 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-308.html",
   "repro": "repro/LFV-308/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-200",
   "priority": "medium",
   "priority_rank": 203,
   "novelty": "known",
   "withheld": false,
   "area": "search / phrase queries (SloppyPhraseMatcher Matches support: endPosition/endOffset read after advanceRpts)",
   "title": "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",
   "summary": "You run a sloppy phrase query that repeats a word, such as \"very very\"~1, on the text 'very very good very' and ask Weight#matches (or the default UnifiedHighlighter) where it matched; you expect positions 0-1, 'very very'. Lucene reports positions 0-3, 'very very good very', because after finding the match the sloppy matcher moves the second 'very' on to the later occurrence to resolve a collision between the two copies of the term, and endPosition()/endOffset() are read only afterwards, from that moved state. The reported span is not the window of any valid match (positions 0 and 3 are two moves apart, the slop is 1); the hit itself and its score are correct.",
   "impact_class": "silent wrong results",
   "introduced_commit": "7d9059ef13df70838da18161a91ef4328a3ce82f (master) and its branch_7x copy 6705632810f700e81ab04a9516ad42feb35aaf64 (the released one), LUCENE-8249 'Implement Matches API for phrase queries' (romseygeek; JIRA patch, migrated apache/lucene#9296, no GitHub PR) [read]: the first Matches support for sloppy phrases already read the end from the live PhrasePositions after advanceRpts [exec]. The current form of endPosition/endOffset (maximum over the live positions of every non-lead PhrasePositions, only the lead snapshotted) is LUCENE-8306, 028c86b1fa70faeec4f7705698a59557f58bcbb0 (master) / 2376d7dded3c0c03fa3bb9c75cc7d8c58bfcb319 (branch_7x), 2018-07-22, first released in 7.5.0; it fixed the lead-advanced case but kept the live read of repeats moved by advanceRpts [exec]. advanceRpts itself is LUCENE-3821 (187bfe2ebc4, 2012) and predates the Matches API. Not a regression: present since the API exists",
   "introduced_date": "2018-05-10 (LUCENE-8249); current end computation 2018-07-22 (LUCENE-8306)",
   "first_affected_version": "7.4.0 [exec] (the first release with Weight#matches; 7.3.1 has no Matches API [exec]); the finder's 'to be or not to be' shape is first affected in 7.5.0 [exec]",
   "affected_versions": "[exec] 7.4.0 (2 of 3 probe cases; 932 of 4,539 repeated-term intervals bad in the bounded-exhaustive scope), 7.5.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main ea57360912ed with -ea and -da (3 of 3 probe cases; 484 of 4,539 bad, output byte-identical from 7.5.0 to main); releases in between [read]. Not fixed upstream: branch_10x and branch_10_6 have the same lazy endPosition [read], so 10.6.0 (released 2026-10-29) has it too (by reading), and no open PR changes captureLead/endPosition/endOffset. Highlighting exposure [read]: UnifiedHighlighter WEIGHT_MATCHES exists since 7.5.0 (LUCENE-8286) and is the default since 9.0.0 (LUCENE-9431)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16913"
   ],
   "doc": "",
   "repro": "repro/LFV-200/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-236",
   "priority": "medium",
   "priority_rank": 204,
   "novelty": "known",
   "withheld": false,
   "area": "join / block-join and global-ordinals join Weight#matches (ToChildBlockJoinQuery, GlobalOrdinalsWithScoreQuery)",
   "title": "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)",
   "summary": "You index parent/child blocks, search +ToChildBlockJoinQuery(color:red) +body:shirt and highlight the hit with the default UnifiedHighlighter, and expect 'small cotton <b>shirt</b>', because Weight#matches must return Matches for every hit of its query and null for every other document. Instead the join's weight inherits FilterWeight#matches, which answers for the wrapped parent query: it returns Matches for the red parent and null for the child hits, so the conjunction's Matches is null and the hit comes back as 'small cotton shirt'; JoinUtil's scoring global-ordinals join has the same defect and reports Matches on every to-side document, not only the joined ones. The search hits themselves are correct; only Weight#matches and the features built on it (Matches-based highlighting, Lucene Monitor's HighlightsMatch matcher) are wrong.",
   "impact_class": "silent wrong results",
   "introduced_commit": "040a9601b1b346391ad37e5a0a4f2f598e72d26e (master, first release 8.0.0) and its branch_7x backport 502fd4bf12b8860b8eea504a96ad1b49dd52938c (first release 7.4.0), LUCENE-8229 'Add Weight.matches() to iterate over match positions' (romseygeek; JIRA era, migrated as apache/lucene#9276, reviewed as JIRA patches; GitHub PR apache/lucene-solr#345 closed unmerged) [read]. Not a regression: the two classes were wrong from the first release with the API, and no later commit adds matches() to either (git log -G 'matches\\(' on both files; #13319, #15469 (merged and reverted) and #15510 left the FilterWeight forward unchanged)",
   "introduced_date": "2018-04-11 (LUCENE-8229, master and branch_7x)",
   "first_affected_version": "7.4.0 [exec] (7.3.1 and earlier have no Weight#matches API: compile error [exec]); on the 8.x line 8.0.0 [exec]. The default-UnifiedHighlighter symptom starts with 9.0.0 [exec] (LUCENE-9431 turned weight matches on by default); on 8.11.4 the highlighter shows it only with the opt-in WEIGHT_MATCHES flag (LUCENE-8286) [exec]",
   "affected_versions": "every release from 7.4.0 to 10.5.2, 10.6.0 (by reading) and main ea57360912ed; not fixed. [exec] the finder's contract test (version-portable variants repro/src, repro/src-8x and, same logic) fails 4 of 4 on 7.4.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.5.2 (-ea and -da) and main (-ea and -da), and does not compile on 7.3.1 (API absent); the default UnifiedHighlighter test fails on 9.0.0, 9.12.3, 10.5.2 and main (-ea and -da), and on 8.11.4 it passes with default flags and fails with the opt-in WEIGHT_MATCHES flag; the independent reproduction's own test fails 6 of 8 on 10.5.2 and 9.12.3, the cross-model review's CheckHits oracle 3 of 3 on 10.5.2 and 9.12.3, the intended-behaviour check's 2 of 2 on 10.5.2, and the Lucene Monitor repro 3 of 3 on 10.5.2 and 9.12.3; a 7.4.0 shadow fix with the ToParent-style matches() body makes the bug assertions pass (one remaining 7.4.0 failure is an unrelated pre-9.0 limitation of DOCS-only TermQuery matches, LUCENE-9462). [read] a source scan of the release tags in the full-history clone (7.4.0-7.7.3, 8.0.0-8.8.1, 9.0.0-9.12.3, 10.0.0-10.5.2) finds the forward and no override in both classes at every tag (the 8.9-8.11 tags are absent from the clone; 8.11.4 was executed); main, branch_10x and branch_10_6 were last changed by #15510 (count() overrides, 2026-01-19). Only single-segment indexes were executed (no OrdinalMap); the code path does not depend on it (read)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15469",
    "https://github.com/apache/lucene/issues/15452",
    "https://github.com/apache/lucene/issues/15450",
    "https://github.com/apache/lucene/issues/15510",
    "https://github.com/apache/lucene/issues/15502",
    "https://github.com/apache/lucene/issues/9276"
   ],
   "doc": "",
   "repro": "repro/LFV-236/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-515",
   "priority": "medium",
   "priority_rank": 205,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter WEIGHT_MATCHES path (FieldOffsetStrategy field-matcher remap)",
   "title": "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",
   "summary": "You index a document with text 'red shirt sale', title 'summer collection' and the keyword status 'active', search +title:summer +text:shirt (or +text:shirt #status:active), and highlight 'text' with UnifiedHighlighter.builder(searcher, analyzer).withFieldMatcher(f -> true).build(). You expect 'red <b>shirt</b> sale', which the default field matcher and the same matcher with withWeightMatches(false) both return. Instead you get 'red shirt sale' with no highlight, because the WEIGHT_MATCHES path makes every accepted field read the highlighted field's terms, so the required clause on title (or status) finds no 'summer' ('active') in text, Weight#matches of the whole query is null, and the highlighter treats the hit as not matching.",
   "impact_class": "silent wrong results",
   "introduced_commit": "b19ae942f154924b9108c4e0409865128f2a07d4 (master, first released in 8.0.0) and its branch_7x backport bf7d1078e4ef6c99abaf5c76eccf56ed0f09f553 (first released in 7.5.0), LUCENE-8286 'UH initial support for Weight.matches' (apache/lucene-solr PR #409 by dsmiley, squash-merged with 'Closes #409', 0 comments and 0 reviews; issue apache/lucene#9333), which added HighlightFlag.WEIGHT_MATCHES and FieldOffsetStrategy#createOffsetsEnumsWeightMatcher with the field-matcher remap; inside the PR the remap was written in commit 93c4663a763 (2018-07-11) [read] [exec]; default exposure 2719cf6630e (LUCENE-9431, apache/lucene PR #362, merged 2021-10-23, 9.0.0: WEIGHT_MATCHES on by default) [exec]",
   "introduced_date": "2018-08-29 (b19ae942f15 on master and bf7d1078e4e on branch_7x; the remap was first written on 2018-07-11 in PR commit 93c4663a763); default exposure 2021-10-23 (2719cf6630e, LUCENE-9431)",
   "first_affected_version": "7.5.0 when the application enables WEIGHT_MATCHES through a getFlags override [exec]; 9.0.0 with the default flags [exec]; last unaffected release 7.4.0 (no WEIGHT_MATCHES flag) [exec]",
   "affected_versions": "WEIGHT_MATCHES enabled by the application: 7.5.0 (-ea and -da), 7.7.3, 8.0.0 and 8.11.4 [exec]; default flags: 9.0.0 [exec], 9.1.0, 9.12.3, 10.0.0, 10.5.2 (the last release before 10.6.0) and main ea57360912ed [exec]; the 2020 list-thread query shape fails on 8.4.1 and main [exec]; default flags on 7.5.0 and 8.11.4 pass, because WEIGHT_MATCHES was off by default before 9.0.0 [exec]; the releases in between carry the same code [read]; the default field matcher (requireFieldMatch=true) is unaffected in every version; not fixed upstream (no commit to uhighlight on upstream main since 2026-05-13, and no open PR changes the remap) [read]",
   "security": "none",
   "upstream_links": [
    "https://lists.apache.org/thread/5jm6l2lp1wstqcc73vjmkxrklgd3s4p5",
    "https://github.com/apache/lucene/issues/9333",
    "https://issues.apache.org/jira/browse/LUCENE-8286",
    "https://github.com/apache/lucene/issues/9396",
    "https://issues.apache.org/jira/browse/LUCENE-8349",
    "https://github.com/apache/lucene/issues/10751"
   ],
   "doc": "",
   "repro": "repro/LFV-515/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-505",
   "priority": "medium",
   "priority_rank": 206,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter WEIGHT_MATCHES path (FieldOffsetStrategy, OverlaySingleDocTermsLeafReader) with block-join queries",
   "title": "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",
   "summary": "You index parent/child blocks whose parents and children share a text field, search with +text:shirt +ToParentBlockJoinQuery(+text:small #type:child), and highlight 'text' with a default UnifiedHighlighter. You expect 'red <b>shirt</b> sale' and 'blue <b>shirt</b>', which is what withWeightMatches(false) returns and what Weight#matches on the searched index reports. Instead you get 'red shirt sale' and 'blue shirt' with no highlight, because the highlighter evaluates Weight#matches on OverlaySingleDocTermsLeafReader, where the highlighted field holds only the hit document, so the child query matches no child, the required join clause does not match, and the whole query's Matches is null.",
   "impact_class": "silent wrong results",
   "introduced_commit": "b19ae942f154 (LUCENE-8286 'UnifiedHighlighter: new HighlightFlag.WEIGHT_MATCHES for MatchesIterator API', dsmiley, 2018-08-29, master; branch_7x backport bf7d1078e4ef, shipped in 7.5.0; 'Closes #409' of apache/lucene-solr, committed directly; JIRA now apache/lucene#9333) added HighlightFlag.WEIGHT_MATCHES, FieldOffsetStrategy#createOffsetsEnumsWeightMatcher and OverlaySingleDocTermsLeafReader, opt-in [read]; widened by 54cc70127b22 / branch_8x df4ebaf030cd (LUCENE-8848, 2019-06-21, 8.2.0: a join is an unrecognized query part, so a field with offsets in postings is re-analysed too) [exec]; default exposure 2719cf6630eb (LUCENE-9431, apache/lucene#362, merged 2021-10-23, 9.0.0, WEIGHT_MATCHES on by default) [exec]; prerequisite ToParentBlockJoinQuery#matches from LUCENE-8229 (040a9601b1b, 2018-04-11, 7.4.0); no commit-level bisect, the release pairs 7.4.0/7.5.0, 8.1.1/8.2.0 and 8.11.4/9.0.0 bracket the three changes [exec]",
   "introduced_date": "2018-08-29 (b19ae942f154, LUCENE-8286, opt-in WEIGHT_MATCHES path); 2019-06-21 (54cc70127b22, LUCENE-8848, offsets-in-postings fields re-analysed for joins); default exposure 2021-10-23 (2719cf6630eb, LUCENE-9431)",
   "first_affected_version": "7.5.0 when the application enables WEIGHT_MATCHES (re-analysis and term vectors; offsets in postings from 8.2.0); 9.0.0 with the default flags [exec]",
   "affected_versions": "default flags: 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2, 10.6.0 (by reading) and main ea57360912ed [exec], every offset source (re-analysis, offsets in postings, term vectors); WEIGHT_MATCHES enabled by the application: 7.5.0, 7.7.3, 8.0.0 and 8.1.1 (re-analysis and term vectors; offsets in postings still correct) and 8.2.0 and 8.11.4 (all three sources) [exec]; releases in between carry the same overlay code [read]; not affected: 7.4.0 and earlier (no WEIGHT_MATCHES path) [exec]; releases before 9.1.0 ran a port of the test to the old API; not fixed anywhere as of upstream main a9779ef3c193, branch_10x and branch_10_6 (no touched file changed after ea57360912ed)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9333",
    "https://issues.apache.org/jira/browse/LUCENE-8286",
    "https://github.com/apache/lucene/issues/9891",
    "https://issues.apache.org/jira/browse/LUCENE-8848",
    "https://github.com/apache/lucene/issues/10471",
    "https://issues.apache.org/jira/browse/LUCENE-9431"
   ],
   "doc": "",
   "repro": "repro/LFV-505/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-243",
   "priority": "medium",
   "priority_rank": 207,
   "novelty": "new",
   "withheld": false,
   "area": "core / search: MultiTermQuery rewrite methods (DocValuesRewriteMethod, DOC_VALUES_REWRITE) and the Matches API (Weight#matches)",
   "title": "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)",
   "summary": "You keep a keyword field as doc values only, filter on it with SortedSetDocValuesField.newSlowSetQuery or a PrefixQuery with DOC_VALUES_REWRITE (DocValuesRewriteMethod says it 'can be used to perform these queries against an unindexed docvalues field'), and expect Weight#matches to return non-null Matches (MATCH_WITH_NO_TERMS) for every hit, as its javadoc promises for DocValues queries and as newSlowExactQuery on the same field does. Instead matches() looks the matched terms up in the field's postings, which do not exist, so it returns null for every hit; for +body:fruit #tags:(banana) the UnifiedHighlighter with default settings returns 'a ripe fruit in a basket' with no highlighted term, while the same query with newSlowRangeQuery as the filter highlights '<b>fruit</b>'. As a MUST_NOT clause the same null makes Weight#matches non-null for documents the clause excludes; hits, counts and scores stay correct.",
   "impact_class": "silent wrong results",
   "introduced_commit": "040a9601b1b346391ad37e5a0a4f2f598e72d26e on master and its branch_7x backport 502fd4bf12b (the commit that 7.4.0 contains), 'LUCENE-8229: Add Weight.matches() to iterate over match positions' by romseygeek, committed from the JIRA patch (apache/lucene-solr#345 was closed unmerged; LUCENE-8229 is GitHub issue #9276) [read]: the commit created Weight#matches, its javadoc, the scorer-based default that returns MATCH_WITH_NO_TERMS, CheckHits.checkMatches and DocValuesRewriteMethod's matches() override on top of the postings-only fromTermsEnum helper, so the defect is as old as the API; later commits on the two methods (LUCENE-8306, LUCENE-8422, LUCENE-8941, LUCENE-9570, LUCENE-10398, #1020) never consult doc values. Entry-point regression: #12129 and #12175 (gsmiller, merged 2023-03-01, first released in 9.6.0) moved newSlowSetQuery from SortedSetDocValuesSetQuery / the sandbox DocValuesTermsQuery, which had no matches() override, onto TermInSetQuery with DOC_VALUES_REWRITE [exec]",
   "introduced_date": "2018-04-11 (DocValuesRewriteMethod#matches, LUCENE-8229); 2023-03-01 (#12175 merged: newSlowSetQuery moved onto DOC_VALUES_REWRITE)",
   "first_affected_version": "7.4.0 [exec] (release tag 2018-06-22; any MultiTermQuery with setRewriteMethod(new DocValuesRewriteMethod())); 7.3.1 and earlier have no Weight#matches API [exec]; by entry point: newSlowSetQuery, MultiTermQuery.DOC_VALUES_REWRITE and TermInSetQuery(DOC_VALUES_REWRITE, ...) since 9.6.0 [exec], and lost highlights with default UnifiedHighlighter flags since 9.0.0 [exec]",
   "affected_versions": "every release from 7.4.0 through 10.5.2, 10.6.0 (by reading) and main ea57360912ed [read]; not affected: 7.3.1 and earlier (the API does not exist); not fixed on main; 10.6.0 (released 2026-10-29) was not run, but branch_10_6 (2763db11b0a, 2026-10-24) has DocValuesRewriteMethod.java and BooleanWeight.java identical to main [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-243.html",
   "repro": "repro/LFV-243/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-832",
   "priority": "medium",
   "priority_rank": 208,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / vectorhighlight FieldPhraseList and FieldTermStack (FastVectorHighlighter phrase search over stacked tokens)",
   "title": "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)",
   "summary": "You index 'my dogs' with an index-time synonym filter that stacks 'dog' on 'dogs' (term vectors with positions and offsets), search dogs OR \"dog house\", which matches through dogs (Weight#matches reports offsets 3-7), and call FastVectorHighlighter.getBestFragment, expecting 'my <b>dogs</b>', which the TermQuery alone gives. Instead you get null, with no error. FieldPhraseList starts a candidate with the first token at that position that has any entry in the query's phrase map ('dog', which sorts first and only starts the phrase \"dog house\"), finds that the phrase does not continue, adds nothing and never tries 'dogs' at the same position; Lucene 4.7.0 highlights this correctly, and the LUCENE-5538 fix in 4.7.1 introduced the loop.",
   "impact_class": "silent wrong results",
   "introduced_commit": "673b1f8d73cedf8e3afd04d7389466c41be91f61 (LUCENE-5538 'FastVectorHighlighter fails with booleans of phrases', trunk svn r1579255, by rmuir with a +1 from jpountz on the issue; a JIRA patch, no pull request; the issue is now apache/lucene#6601), backported the same day as 6c9608f484d (branch_4x, r1579264) and 88df0bca7cc (lucene_solr_4_7, r1579269, the commit that shipped in 4.7.1). It collapsed the tokens of one position into one FieldTermStack entry with a circular next list (FieldTermStack.java:108-130 at a9779ef3c193) and added the start loop that scans those alternatives only while currMap == null (FieldPhraseList.java:73-81) [exec]. A regression: before it every stacked token was its own stack entry, so a dead-end start fell through to the next token at the same position",
   "introduced_date": "2014-03-19 (commit date of 673b1f8d73c and of both backports)",
   "first_affected_version": "4.7.1 [exec] (tag 2014-04-01, via 88df0bca7cc); 4.7.0 (2014-02-25) highlights the same input correctly [exec]; on the 4.8 line 4.8.0 [exec] via the branch_4x backport",
   "affected_versions": "every release from 4.7.1 through 10.5.2, 10.6.0 (by reading) and main a9779ef3c193 [exec]; unaffected: 2.9.0 (the first release with FastVectorHighlighter) through 4.7.0, which lack the loop [exec]; not fixed on origin/main 20ced71c1e6, branch_10x 657014b3c579 or branch_10_6 4ae946e5a9b9 (2026-10-26/27) [read]",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-5538",
    "https://github.com/apache/lucene/issues/6601",
    "https://github.com/apache/lucene/issues/5799",
    "https://issues.apache.org/jira/browse/LUCENE-4734",
    "https://github.com/apache/lucene/issues/8644",
    "https://issues.apache.org/jira/browse/LUCENE-7593"
   ],
   "doc": "",
   "repro": "repro/LFV-832/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-827",
   "priority": "medium",
   "priority_rank": 209,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / original Highlighter, QueryScorer and WeightedSpanTermExtractor (phrase-to-span conversion)",
   "title": "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",
   "summary": "You index 'rock roll rock and roll' with a stop-word analyzer, search for the phrase \"rock and roll\" (QueryParser and QueryBuilder make it rock at position 0 and roll at position 2, slop 0, and Weight#matches reports the only match at positions 2-4), and highlight the hit with Highlighter and QueryScorer, expecting 'rock roll <B>rock</B> and <B>roll</B>'. Instead you get '<B>rock</B> <B>roll</B> <B>rock</B> and <B>roll</B>', and on 'rock roll roll', which matches only as the first rock plus the last roll, you get '<B>rock</B> <B>roll</B> roll', with the matching last word unmarked. WeightedSpanTermExtractor turns the phrase's one hole into slop 1 of an ordered SpanNearQuery, which accepts 0 or 1 words between the terms instead of exactly 1 and keeps only the shortest span per start; MultiPhraseQuery has the same conversion, and the UnifiedHighlighter with weight matches turned off reaches it through PhraseHelper.",
   "impact_class": "silent wrong results",
   "introduced_commit": "35c7eb36dfb (svn r652164, LUCENE-794, now apache/lucene#1869, Mark Harwood, 2008-04-29) created the PhraseQuery/MultiPhraseQuery to SpanNearQuery conversion; its MultiPhraseQuery branch already wrote today's 'new SpanNearQuery(clauses, slop + positionGaps, inorder = (slop == 0))' (git blame -w -M -C of main :215-232), while its PhraseQuery branch ignored holes (a predecessor defect: the true match was never highlighted); LUCENE-2003 (#3078; 6cd7218a428 on lucene_2_9, r829128, first released in 2.9.1; trunk twin 9609a2cb4db, r829129, first in 3.0.0; Mark Miller, 2009-10-23) turned PhraseQuery holes into slop; LUCENE-5503 (#6566; 4c40ad78c94 on branch_5x, first in 5.4.0; trunk twin c5b49baa592, first in 6.0.0; patch by Tim Allison, committed by David Smiley, 2015-09-13) wrote today's PhraseQuery line and fixed only the reversed-order case [read] [exec]. Present since the code was written, not a regression; svn era, so no pull request",
   "introduced_date": "2008-04-29 (35c7eb36dfb, LUCENE-794: conversion created, MultiPhraseQuery holes as slop); 2009-10-23 (LUCENE-2003: PhraseQuery holes as slop); 2015-09-13 (LUCENE-5503: today's PhraseQuery line)",
   "first_affected_version": "2.4.0 [exec] (release 2008-10-08), through the opt-in SpanScorer that LUCENE-794 added: MultiPhraseQuery with holes shows this symptom from 2.4.0, PhraseQuery from 2.9.1 (in 2.4.0-2.9.0 a predecessor defect ignored PhraseQuery holes, so the repro also fails there, differently: the true match is never highlighted); the default QueryScorer is position-aware from 2.9.0 (LUCENE-1685); 2.3.2 has no position-aware scorer [exec]",
   "affected_versions": "every release from 2.4.0 through 10.5.2, 10.6.0 (by reading) and main a9779ef3c193; no version has a fix [exec] [read]. Releases between the executed ones are covered by reading. The UnifiedHighlighter weight-matches-off path (PhraseHelper reuses the extractor since 6.3.0, read) was executed on main only. 10.6.0 (released 2026-10-29) was read (the same two lines at 4ae946e5a9b), not executed",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/3078",
    "https://issues.apache.org/jira/browse/LUCENE-2003",
    "https://github.com/apache/lucene/issues/6269",
    "https://issues.apache.org/jira/browse/LUCENE-5205",
    "https://github.com/apache/lucene/issues/11645",
    "https://github.com/apache/lucene/issues/5568"
   ],
   "doc": "",
   "repro": "repro/LFV-827/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-516",
   "priority": "medium",
   "priority_rank": 210,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter WEIGHT_MATCHES path (FieldOffsetStrategy) with statistics-dependent query rewrites (CommonTermsQuery, MoreLikeThisQuery)",
   "title": "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",
   "summary": "You search with CommonTermsQuery(SHOULD, MUST, 0.5) over 'the' (in 5 of 6 documents) and 'fox' (2 of 6), which the searcher rewrites to +fox the, and highlight the hit 'quick brown fox' with a default UnifiedHighlighter built on that same searcher. You expect 'quick brown <b>fox</b>', which the highlighter returns with WEIGHT_MATCHES off and the legacy Highlighter and FastVectorHighlighter also give. Instead the snippet has no mark, because FieldOffsetStrategy rewrites the query again on the hit's own segment or a one-document view of it, where 'the' counts as rare and becomes required (+the +fox), so the hit no longer matches; the result changes with segment layout alone, and MoreLikeThisQuery with its default minDocFreq rewrites there to an empty query, so its hits are never highlighted.",
   "impact_class": "silent wrong results",
   "introduced_commit": "b19ae942f154 (LUCENE-8286 'UnifiedHighlighter: new HighlightFlag.WEIGHT_MATCHES for MatchesIterator API', dsmiley, 2018-08-29; branch_7x cherry-pick bf7d1078e4ef the same day, shipped in 7.5.0; JIRA now apache/lucene#9333, PR apache/lucene-solr#409 closed by the commit, not merged on GitHub) added FieldOffsetStrategy#createOffsetsEnumsWeightMatcher with new IndexSearcher(leafReader) + rewrite, made UnifiedHighlighter pass the hit's own leaf, and made the re-analysis and term-vector strategies pass a one-document OverlaySingleDocTermsLeafReader; FieldOffsetStrategy.java:141-147 still blames to it apart from a reformatting (6faa4f98e04, LUCENE-9570) and a record-accessor rename (942065cc3e7, #13328) [read]; default exposure: 2719cf6630eb (LUCENE-9431 'UnifiedHighlighter WEIGHT_MATCHES is now true by default', apache/lucene#362, dsmiley, 2021-10-22, 9.0.0) [read]; no commit-level bisect: the release pairs 7.4.0/7.5.0 (flag absent / affected) and 8.11.4/9.0.0 (opt-in / default) bracket the two changes [exec]",
   "introduced_date": "2018-08-29 (b19ae942f154, LUCENE-8286, the WEIGHT_MATCHES path, opt-in); default exposure 2021-10-22 (2719cf6630eb, LUCENE-9431)",
   "first_affected_version": "7.5.0 (tagged 2018-09-22, release commit 2018-09-17) when the application enables WEIGHT_MATCHES; 9.0.0 (tagged 2021-12-06, release commit 2021-12-01) with the default flags [exec]",
   "affected_versions": "default flags: 9.0.0, 9.12.3, 10.0.0, 10.5.2 (the last release before 10.6.0) and main ea57360912ed [exec]; WEIGHT_MATCHES enabled by the application: 7.5.0, 7.7.3, 8.0.0, 8.1.0, 8.2.0, 8.11.4 [exec]; every executed release gives the same result (offsets in postings on 2 segments, re-analysis and term vectors lose the highlight, the 1-segment postings control highlights, the pre-rewritten query highlights all cases, MoreLikeThisQuery with defaults is not highlighted); the rewrite line is present at all 57 release tags 7.5.0 to 10.5.2 in the history clone [read]; not affected: 7.4.0 and earlier (no WEIGHT_MATCHES path) [exec]; regression framing: with default flags 8.1.0 to 8.11.4 highlight the CommonTermsQuery hits correctly (classic path) and 9.0.0 does not; 7.5.0 to 8.0.0 threw UnsupportedOperationException for CommonTermsQuery on the classic path (a separate, older defect); MoreLikeThisQuery hits were never highlighted by the UnifiedHighlighter in any executed release; the same fix ported to 7.5.0 and 8.2.0 removes the CommonTermsQuery failures [exec]; not fixed anywhere as of ea57360912ed (no change to the rewrite upstream since, no open PR changes it)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/11807",
    "https://github.com/apache/lucene/issues/5793",
    "https://issues.apache.org/jira/browse/LUCENE-4728",
    "https://github.com/apache/lucene/issues/11490",
    "https://issues.apache.org/jira/browse/LUCENE-10454",
    "https://github.com/apache/lucene/issues/10751"
   ],
   "doc": "",
   "repro": "repro/LFV-516/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-150",
   "priority": "medium",
   "priority_rank": 211,
   "novelty": "known",
   "withheld": false,
   "area": "search / sorting (TopFieldCollector competitive iterator x DenseConjunctionBulkScorer collectRange shortcut)",
   "title": "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)",
   "summary": "You run a top-10 search sorted on a LONG field with points (or a STRING field with a terms index, or a LONG field with a skip index) with MatchAllDocsQuery over one 100,000-doc segment that has no deletions. You expect Lucene to skip non-competitive documents, as 10.2.2 does for this exact search (about 1,000-1,750 docs collected) and as a TermQuery matching the same docs still does on main (about 8,200). Instead main and every release since 10.3.0 collect all 100,000 docs, because the comparator's competitive iterator starts as all docs and since #14532 reports a run up to maxDoc, so DenseConjunctionBulkScorer collects the whole segment in one collectRange call before the comparator narrows the iterator; the top hits are still correct, only the pruning is lost.",
   "impact_class": "minor",
   "introduced_commit": "81f2517f985 on main / ba405038ca2 on branch_10x (apache/lucene#14532 'Make competitive iterators more robust.', by jpountz, approved by gf2121; no CHANGES entry; its body calls '#docIDRunEnd on all competitive iterators' a side-effect) [read]. It combines with two older pieces that are harmless alone and shipped in 10.2.0, which prunes: #14293 (the competitive iterator becomes a DenseConjunctionBulkScorer clause) and #14400 (full-run shortcut when every clause fully matches; #14401 renamed its call to collectRange). #14550 (removal of DISIDocIdStream, merged the same minute) is not needed [exec].",
   "introduced_date": "2025-05-20 (81f2517f985 on main and ba405038ca2 on branch_10x)",
   "first_affected_version": "10.3.0 [exec]",
   "affected_versions": "10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main through ea57360912ed [exec]; not affected [exec]: 9.12.3, 10.0.0, 10.2.0 and 10.2.2 (MatchAllDocsQuery collects 1,037 / 1,750 docs, the same as the TermQuery control); the trigger is old public API, so these are real negatives; the skip-index variant is affected since skip-index sort pruning first shipped (#14672, 10.3.0); not fixed on upstream main or branch_10x [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16542",
    "https://github.com/apache/lucene/issues/16857",
    "https://github.com/apache/lucene/issues/16163",
    "https://github.com/apache/lucene/issues/16133",
    "https://github.com/apache/lucene/issues/14395",
    "https://github.com/apache/lucene/issues/14532"
   ],
   "doc": "",
   "repro": "repro/LFV-150/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-709",
   "priority": "medium",
   "priority_rank": 212,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-smartcn / HHMM segmenter bigram dictionary (BigramDictionary.getBigramItemIndex, AbstractDictionary.hash2; reached through SmartChineseAnalyzer and HMMChineseTokenizer)",
   "title": "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",
   "summary": "You analyze Chinese text written with ASCII punctuation, for example '我们要发展经济和文化,加强法律,增加资金,继续努力,共同进步.', with the default SmartChineseAnalyzer; its bigram dictionary is an open-addressing hash table with double hashing, so you expect each bigram frequency lookup to take a handful of probes and the text to cost about as much as the same sentence with full-width punctuation, which gives the same tokens. Instead AbstractDictionary.hash2 computes ((33h + d) & 0xFF) and then ((33h + d) >> 8), because '+' binds tighter than '&' and '>>' (AbstractDictionary.java:195-196), so the probe step is always in [0, 288] and is 0 for some keys whose last char is below U+0100, such as '对@,' or '文化@,'; when such a key's home slot holds another bigram, BigramDictionary.getBigramItemIndex (BigramDictionary.java:213-233) re-reads that same slot until i reaches PRIME_BIGRAM_LENGTH = 402,137 and then returns 'not found'. The tokens stay correct, but that sentence repeated 100 times takes about 220 ms of CPU instead of about 2.6 ms (85x on main), and 1x with a one-line guard.",
   "impact_class": "minor",
   "introduced_commit": "e01aad89fe24f2482eb2e8c0e39f8272704abe80 (svn r774718), LUCENE-1629 'contrib intelligent Analyzer for Chinese' (JIRA, migrated as apache/lucene#2703; a patch contributed from the imdict-chinese-analyzer project and committed by mikemccand; no pull request): the commit that added the whole smartcn module, including hash2's precedence slip, the probe loops of getBigramItemIndex and getAvaliableIndex without a hash2 == 0 guard, PRIME_BIGRAM_LENGTH = 402137, the bundled bigramdict.mem and the raw-punctuation 'word@delimiter' bigram keys [read]",
   "introduced_date": "2009-05-14",
   "first_affected_version": "2.9.0 [exec] (the first release with smartcn; 2.4.1 has no smartcn API [exec], and the Maven Central version list starts at 2.9.0)",
   "affected_versions": "Every release from 2.9.0 through 10.5.2 and main a9779ef3c193 [exec]. Both default tokenizer chains are affected: SentenceTokenizer + WordTokenFilter (2.9.0-4.7.2) and HMMChineseTokenizer (4.8.0 on) [exec]. All 136 release tags in the history clone that contain e01aad89fe24 have the same normalized hash2(char[]), getBigramItemIndex, getAvailableIndex, PRIME_BIGRAM_LENGTH and bigramdict.mem blob [read]; releases without a local tag (2.9.3, 2.9.4, 3.0.2, 3.0.3, 8.9.0-8.11.3) are inferred from their neighbours. Not fixed: upstream main a95c754ee003 (2026-10-26) has the same code, the last upstream commit under cn/smart/hhmm is 54283150a81 (2026-06-14, typo fixes), and no open PR changes the lookup or hash2 [read].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/3098",
    "https://issues.apache.org/jira/browse/LUCENE-2023",
    "https://github.com/apache/lucene/issues/2703",
    "https://issues.apache.org/jira/browse/LUCENE-1629",
    "https://github.com/apache/lucene/issues/8560",
    "https://github.com/apache/lucene/issues/8559"
   ],
   "doc": "",
   "repro": "repro/LFV-709/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-297",
   "priority": "medium",
   "priority_rank": 213,
   "novelty": "known",
   "withheld": false,
   "area": "search / rescoring",
   "title": "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",
   "summary": "You wrap a query in RescoreTopNQuery, for example full-precision rescoring of a kNN query with a filter, and on this index the inner query matches nothing (the filter matches no document, the term is absent, or the index is empty). You expect 0 hits, which is what the inner query alone returns. Instead the search throws an AssertionError with assertions enabled, or ArrayIndexOutOfBoundsException 'Index 0 out of bounds for length 0' without them, because rewrite() hands its empty top-n list to a helper that reads the first entry; the kNN query's own rewrite checks for this case and returns MatchNoDocsQuery.",
   "impact_class": "crash",
   "introduced_commit": "3404496b3d77 (#14009 'Add Query for reranking KnnFloatVectorQuery with full-precision vectors', by GitHub dungba88, main), released through its branch_10x backport 4fcb6d6d50de (#14860) [read]. #14009 moved the helper (with its 'assert len > 0', #12146) out of AbstractKnnVectorQuery, kept that caller's empty-topK guard (LUCENE-9614) and added RescoreTopNQuery as a second caller without one; not a regression, the guard was never there",
   "introduced_date": "2025-06-28 (#14009 merged; backport #14860 merged 2025-06-29)",
   "first_affected_version": "10.3.0 [exec]",
   "affected_versions": "10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main ea57360912ed, each with -ea (AssertionError) and -da (ArrayIndexOutOfBoundsException) [exec]; not applicable to 10.2.2 and 9.12.3, where RescoreTopNQuery does not exist and the repro does not compile [exec]; upstream main e1c4184cb983, branch_10x, branch_10_6 (10.6.0, released 2026-10-29) and branch_10_5 have the same unguarded call as of 2026-10-26 [read]; fixed on main by 645d4fe14a20 (#16926, 2026-10-28) [exec] and on branch_11x by f85446cb1af [read]; still fixed on main e1faeba08bd [exec] and on branch_11x da3ea39fa59 [read]; still affected: 10.3.0-10.5.2, 10.6.0 [exec] and branch_10_6 91eaab4fb29 (the 10.6.1 work) [exec]; branch_10x 657014b3c57 carried the 10.5.2 file until it was decommissioned on 2026-10-29 (48cf3f515d6, #16911)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/14009",
    "https://github.com/apache/lucene/issues/14860",
    "https://github.com/apache/lucene/issues/14729",
    "https://github.com/apache/lucene/issues/16628",
    "https://github.com/apache/lucene/issues/16705",
    "https://github.com/apache/lucene/issues/16686"
   ],
   "doc": "",
   "repro": "repro/LFV-297/",
   "triage_status": "fixed",
   "triage_by": "Greg Miller (Lucene committer, PR #16926)",
   "triage_date": "2026-10-28",
   "triage_link": "https://github.com/apache/lucene/pull/16926",
   "triage_note": "Greg Miller fixed it on main and branch_11x (11.0) by returning MatchNoDocsQuery when the inner query leaves nothing to rescore, the same guard as our fix. They left it out of 10.6 because they were not sure it is severe enough, so the 10.x line keeps the bug.",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-815",
   "priority": "medium",
   "priority_rank": 214,
   "novelty": "known",
   "withheld": false,
   "area": "search / rescoring (SortRescorer; expressions ExpressionRescorer inherits it)",
   "title": "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",
   "summary": "You rescore the top hits with new SortRescorer(sort) or expression.getRescorer(bindings) and expect the same order and sort values that IndexSearcher#search(query, n, sort) gives for the same Sort on the same searcher, because DoubleValuesSource tells clients to rewrite against the searcher and IndexSearcher does that for sorted searches. Instead SortRescorer builds its collector from the Sort as given (SortRescorer.java:48-49): for a sort on new QueryValueSource(q, 0).asDoubleValuesSource() on a ClassicSimilarity searcher the hits come back in BM25 order with BM25 values (doc0=0.1468, doc1=0.1246 instead of doc1=1.0, doc0=0.894), and ValueSource sort fields or fromQuery sorts throw. Passing sort.rewrite(searcher) inside rescore() fixes every case.",
   "impact_class": "silent wrong results",
   "introduced_commit": "03afeb7766a39996de3c85e8a6ab24d2a352dd1c on branch_7x (the copy first released, in 7.2.0); master equivalent 2a4dd499bbd2f5ed1f481e17eeaee4f32b927185. LUCENE-7736 'Expose some IndexReader stats via DoubleValuesSources' (apache/lucene#8787; JIRA patch, no GitHub PR; author romseygeek) made IndexSearcher#search(Query, int, Sort) call sort.rewrite(this) (IndexSearcher.java:730 on main, blame 2a4dd499bbd) and told DoubleValuesSource clients to rewrite against the top-level searcher, but left SortRescorer unchanged, although the author's issue comment of 2017-04-10 names it ('we already have a Sort.rewrite() method, but it wasn't being called by IndexSearcher or SortRescorer'). A consumer left behind, not a line added to SortRescorer: its Sort-as-given code dates from LUCENE-5545 (cbd8cacc50c, 2014-03-23, 4.8.0), when every consumer needed a caller-rewritten Sort [exec]",
   "introduced_date": "2017-11-15 (LUCENE-7736 committed on master and branch_7x; author date 2017-03-28); first released in 7.2.0 (tagged 2017-12-19). SortRescorer itself: 2014-03-23 (LUCENE-5545)",
   "first_affected_version": "7.2.0 [exec]: the per-variant history probes diverge from IndexSearcher#search for the ValueSource#getSortField sort, the silent query() function sort and the fromQuery sort; 7.1.0 is the last unaffected release [exec]: both consumers behave the same there (both throw, or both use the default Similarity), as on 4.8.0, 4.10.4, 5.5.5, 6.4.0 and 6.6.6 [exec]; 4.7.2 has no SortRescorer. The Expression#getRescorer + fromQuery variant diverges only from 8.6.0 [exec], because before LUCENE-9362 IndexSearcher#search failed on it too (8.5.2 consistent [exec]).",
   "affected_versions": "every release from 7.2.0 to 10.5.2, 10.6.0 (by reading) and main a9779ef3c193 (unreleased 11.0); branch_10x and branch_10_6 [read]; not fixed upstream (SortRescorer.java last changed upstream by e5eb7e763acb, author and committer date 2025-06-30, #14852, unrelated; ExpressionRescorer.java by 945b1cb87262, 2021-03-23, unrelated; checked 2026-10-28). [exec] the follow-up's 4 per-variant history probes (68 runs) diverge on 7.2.0, 7.7.1, 7.7.2, 7.7.3, 8.0.0, 8.1.0, 8.6.0, 8.11.4, 9.12.3, 10.5.2 and main (-ea and -da on 7.2.0 and main); the finder's JUnit fails 4 of 4 on main (-ea and -da), 10.5.2, 9.12.3, 10.0.0, 9.1.0, 9.0.0, 8.11.4 and 7.7.3 (3 of 4 on 8.0.0 and 7.2.0, see the caveat); the independent reproduction's JUnit fails 5 of 9 on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's fails 2 of 6 on main (-ea and -da) and 10.5.2. [read] releases between the executed ones are inferred from code identity (SortRescorer never calls Sort#rewrite, git log -S rewrite on the file is empty; IndexSearcher rewrites since 7.2.0). Caveat: in 7.2.0-7.7.1 and 8.0.0 a Sort object that an IndexSearcher#search had already rewritten carried that searcher (mutating rewrite, removed by LUCENE-8726), which masks the silent variant for that reuse pattern only; fresh Sorts show it there too. All runs JDK 25 on Linux aarch64.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/8787",
    "https://issues.apache.org/jira/browse/LUCENE-7736",
    "https://github.com/apache/lucene/issues/5619",
    "https://issues.apache.org/jira/browse/LUCENE-4553",
    "https://github.com/apache/lucene/issues/6608",
    "https://issues.apache.org/jira/browse/LUCENE-5545"
   ],
   "doc": "",
   "repro": "repro/LFV-815/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-814",
   "priority": "medium",
   "priority_rank": 215,
   "novelty": "known",
   "withheld": false,
   "area": "facet / sorted-search helpers (FacetsCollectorManager static search/searchAfter, DrillSideways sorted search)",
   "title": "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",
   "summary": "You run a faceted search with FacetsCollectorManager.search(searcher, query, n, sort, fcm) or DrillSideways.search(query, filter, after, n, sort, doDocScores), sorted by a function of a query's score, and expect the same hits, order and sort values as IndexSearcher#search(query, n, sort), which rewrites the Sort against the searcher first. Instead both helpers hand the caller's Sort to TopFieldCollectorManager as given: on a ClassicSimilarity searcher a QueryValueSource(body:a) sort returns [doc0=0.147, doc1=0.125] (scores from a fresh default-BM25 searcher) where IndexSearcher#search returns [doc1=1.0, doc0=0.894]. A DoubleValuesSource.fromQuery sort throws 'This DoubleValuesSource must be rewritten' from both helpers, and a ValueSource#getSortField sort throws 'SortField needs to be rewritten'.",
   "impact_class": "silent wrong results",
   "introduced_commit": "03afeb7766a39996de3c85e8a6ab24d2a352dd1c on branch_7x (first released in 7.2.0); master twin 2a4dd499bbd2f5ed1f481e17eeaee4f32b927185 (first released in 8.0.0). LUCENE-7736 'Expose some IndexReader stats via DoubleValuesSources' (apache/lucene#8787; JIRA patch, no GitHub PR; author romseygeek) added 'final Sort rewrittenSort = sort.rewrite(this);' to IndexSearcher's sorted searchAfter and gave DoubleValuesSource a rewrite(IndexSearcher), but left the facet helpers unchanged (its only facet file is the test TestRangeFacetCounts) [exec]. The helpers themselves never rewrote the Sort: DrillSideways sorted search since LUCENE-4748 (e01492bbee4, 2013-02-26, 4.2.0), the FacetsCollector static sorted helpers since LUCENE-5339/LUCENE-5371 (7477fde1cb0, 2014-01-04, 4.7.0), moved to FacetsCollectorManager by #13733 (47c0a6ed183, 10.0.0) and #13737 (04d0170bac8, 9.12.0) without a rewrite [read]. DoubleValuesSource.fromQuery, the main throwing trigger, came with LUCENE-7998 (c6171019d5f on branch_7x, committed 2017-11-16) in the same 7.2.0 release.",
   "introduced_date": "2017-11-15 (LUCENE-7736 committed on branch_7x and master; git author date 2017-03-28); LUCENE-7998 committed 2017-11-16",
   "first_affected_version": "7.2.0 [exec]; 7.1.0 is the last unaffected release [exec]; 6.6.6 and 7.0.0 also pass [exec]; before 4.2.0 the sorted facet helpers did not exist.",
   "affected_versions": "every release from 7.2.0 to 10.5.2 (7.2.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2), 10.6.0 (by reading) and main a9779ef3c193 (unreleased 11.0); upstream main 20ced71c1e6e (2026-10-27) and branch_10x / branch_10_6 have the same code at both sites [read]; never fixed upstream. [exec] the follow-up probe fails on 7.2.0, 7.2.1, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.11.1, 9.12.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da on 7.2.0 and main); the finder's JUnit fails 4 of 4 on main (-ea, -da), 10.5.2, 9.12.3 and 9.12.0; the independent reproduction's JUnit fails 6 of 9 on main (-ea, -da), 10.5.2 and 9.12.3. [read] all 62 release tags 7.2.0-10.5.2 in the history clone have sort.rewrite(this) in IndexSearcher and no Sort rewrite in FacetsCollector, FacetsCollectorManager or DrillSideways (8.8.2 and 8.9.0-8.11.3 are not tagged in the clone; 8.11.4 was executed). On 7.2.0-7.7.1 and 8.0.0 (before LUCENE-8726) a Sort object that already went through IndexSearcher#search carries that searcher into a later helper call and masks the silent variant; a freshly built Sort shows it there too, and the throwing variants are not affected.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/5619",
    "https://issues.apache.org/jira/browse/LUCENE-4553",
    "https://issues.apache.org/jira/browse/LUCENE-7736",
    "https://github.com/apache/lucene/issues/13334",
    "https://github.com/apache/lucene/issues/16707",
    "https://github.com/apache/lucene/issues/15221"
   ],
   "doc": "",
   "repro": "repro/LFV-814/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-816",
   "priority": "medium",
   "priority_rank": 216,
   "novelty": "known",
   "withheld": false,
   "area": "grouping / GroupingSearch (convenience API)",
   "title": "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",
   "summary": "You group with GroupingSearch and set a group sort or within-group sort that depends on the query or the searcher, for example a sort on new QueryValueSource(q, 0).asDoubleValuesSource(), and expect the groups and their documents in the order IndexSearcher#search(query, n, sort) gives for the same Sort on the same searcher, because IndexSearcher rewrites the Sort and GroupingSearch#search is handed that searcher. Instead GroupingSearch passes both Sorts to its collectors as given (GroupingSearch.java:148, 160, 201-202, 228-233): on a ClassicSimilarity searcher the documents of one group come back as doc0=0.101, doc1=0.088, doc2=0.088 (default-BM25 scores) instead of doc1=1.0, doc2=1.0, doc0=0.894, the first group is g0 instead of g1, and ValueSource sort fields or fromQuery sorts throw. Rewriting both Sorts against the searcher at the start of groupByFieldOrFunction and groupByDocBlock fixes every case.",
   "impact_class": "silent wrong results",
   "introduced_commit": "03afeb7766a39996de3c85e8a6ab24d2a352dd1c on branch_7x (the copy first released, in 7.2.0); master equivalent 2a4dd499bbd2f5ed1f481e17eeaee4f32b927185. LUCENE-7736 'Expose some IndexReader stats via DoubleValuesSources' (apache/lucene#8787; JIRA patch, no GitHub PR; author romseygeek) made IndexSearcher#search(Query, int, Sort) call sort.rewrite(this) (IndexSearcher.java:730 on main) and gave DoubleValuesSource sort fields and ValueSource#asDoubleValuesSource() views their searcher only through rewrite, but did not touch GroupingSearch. A consumer left behind, not a line added to GroupingSearch: its Sort-as-given code dates from LUCENE-3778 (89b55566d83, 2012-03-22, first released in 4.0.0-alpha), when every consumer, IndexSearcher included, needed a caller-rewritten Sort; GroupingSearch's only rewrite in its whole history is of the groupEndDocs query (LUCENE-8242) [exec]",
   "introduced_date": "2017-11-15 (LUCENE-7736 committed on master and branch_7x; author date 2017-03-28); first released in 7.2.0 (tag 2017-12-19). GroupingSearch itself: 2012-03-22 (LUCENE-3778)",
   "first_affected_version": "7.2.0 [exec]: the within-group order diverges from IndexSearcher#search and a ValueSource group sort throws only in GroupingSearch; the group-order test passes there only because WrappedDoubleValuesSource kept the searcher of an earlier IndexSearcher#search in the shared Sort object (removed by LUCENE-8726 in 7.7.2 and 8.1.0), and with separately built Sort objects (TestGroupingSearchFreshSortProbe) it fails on 7.2.0, 7.7.1, 8.0.0 and 8.1.0. 7.1.0 is the last unaffected release [exec]: both APIs agree there, as on 6.6.6 and 7.0.0, because IndexSearcher did not rewrite Sorts either (it rejects the ValueSource sort itself); GroupingSearch does not exist before 4.0.0-alpha.",
   "affected_versions": "every release from 7.2.0 to 10.5.2, 10.6.0 (by reading) and main a9779ef3c193 (unreleased 11.0); branch_10_6 [read]; not fixed upstream (upstream main 20ced71c1e6 has a byte-identical GroupingSearch.java; last upstream change 3afffeef5a8, author and committer date 2026-07-08, #16247, unrelated; checked 2026-10-28). [exec] the finder's JUnit (with API-adapted copies for 9.1-9.12, 8.x/9.0.0 and 6.6.6-7.7.3) fails 3 of 3 on main (-ea and -da), 10.5.2, 10.0.0, 9.12.3, 9.0.0, 8.11.4, 8.1.0, 7.7.3 and 7.7.2, and 2 of 3 on 8.0.0, 7.7.1 and 7.2.0 (group-order test masked, see first_affected_version); the fresh-Sort probe fails on 7.2.0, 7.7.1, 8.0.0 and 8.1.0 and passes on 7.1.0; the independent reproduction's JUnit fails 5 of 6 on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's re-run of the finder's JUnit fails 3 of 3 on main (-ea and -da) and 10.5.2. All runs JDK 25 on Linux aarch64.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/5619",
    "https://issues.apache.org/jira/browse/LUCENE-4553",
    "https://issues.apache.org/jira/browse/LUCENE-3778",
    "https://github.com/apache/lucene/issues/8787",
    "https://issues.apache.org/jira/browse/LUCENE-7736",
    "https://github.com/apache/lucene/issues/4851"
   ],
   "doc": "",
   "repro": "repro/LFV-816/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-114",
   "priority": "medium",
   "priority_rank": 217,
   "novelty": "known",
   "withheld": false,
   "area": "search / kNN query layer (KnnSearchStrategy.Seeded, optimistic re-entry pass, SeededKnnVectorQuery)",
   "title": "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)",
   "summary": "You build a kNN query with an explicit null search strategy, for example new KnnFloatVectorQuery(field, target, k, null, null), whose javadoc says 'If null, the default strategy will be used', and run it wrapped in SeededKnnVectorQuery, or as a plain query on a multi-segment index where the optimistic second pass re-enters a segment. You expect the same hits as with KnnSearchStrategy.Hnsw.DEFAULT. Instead Lucene wraps the null in KnnSearchStrategy.Seeded for the seeded HNSW walk, and Seeded.nextVectorsBlock() calls originalStrategy.nextVectorsBlock() without a null check, so the search throws 'NullPointerException: Cannot invoke KnnSearchStrategy.nextVectorsBlock() because this.originalStrategy is null' (KnnSearchStrategy.java:169) and returns nothing.",
   "impact_class": "crash",
   "introduced_commit": "b6e57da01a5 on main (10.x backport 586dc103361, same KnnSearchStrategy hunk), apache/lucene#15063 'Add optimistic collection to DiversifyingNearestChildren* vector queries' (benwtrent; closes #15059; approved by msokolov and tteofili): its one KnnSearchStrategy hunk changed Seeded.nextVectorsBlock() from the no-op '{}' to 'originalStrategy.nextVectorsBlock();' with no null check, and the same commit gave the DiversifyingChildren* queries the optimistic re-entry pass [read]. Pieces that predate it and were harmless while Seeded.nextVectorsBlock was a no-op: the null-means-default constructors and javadoc and SeededKnnVectorQuery's wrapping of the possibly-null strategy in Seeded (0614fe9ebd7, #14160, first released in 10.2.0), and the plain query's re-entry pass wrapping it the same way (d279af1961f, #14226, first released in 10.3.0)",
   "introduced_date": "2025-08-25 (b6e57da01a5, #15063 merged to main); pre-existing pieces 2025-02-13 (#14160) and 2025-05-05 (#14226)",
   "first_affected_version": "10.3.0 (release tag 2025-09-13) [exec]",
   "affected_versions": "10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main through ea57360912ed [exec]; upstream main, branch_10x and branch_10_6 (10.6.0, released 2026-10-29) still have the unguarded delegation on 2026-10-26 [read], so 10.6.0 (released 2026-10-29) has it, and 11.0.0 ships it unless fixed; not affected: 10.2.0, 10.2.1, 10.2.2 [exec]; the API does not exist in 10.1.0 and older or in any 9.x release [exec]; executed query variants: float plain multi-segment, float SeededKnnVectorQuery, float block-join (DiversifyingChildrenFloatKnnVectorQuery) and, by the independent reproduction, byte plain multi-segment; KnnFloat16VectorQuery and the byte and float16 join variants share the code path by reading only [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15708",
    "https://github.com/apache/lucene/issues/15063",
    "https://github.com/apache/lucene/issues/14160",
    "https://github.com/apache/lucene/issues/14170",
    "https://github.com/apache/lucene/issues/14094",
    "https://github.com/apache/lucene/issues/14226"
   ],
   "doc": "",
   "repro": "repro/LFV-114/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-041",
   "priority": "medium",
   "priority_rank": 218,
   "novelty": "known",
   "withheld": false,
   "area": "queryparser / classic and flexible",
   "title": "An invalid regular expression lets IllegalArgumentException escape QueryParser.parse() and StandardQueryParser.parse()",
   "summary": "You parse a query string that contains an invalid /regex/ with the classic, MultiField or flexible query parser. You expect a ParseException (or QueryNodeException). Instead the RegExp IllegalArgumentException escapes parse().",
   "impact_class": "wrong error",
   "introduced_commit": "unknown (not yet bisected)",
   "introduced_date": "unknown (not yet bisected)",
   "first_affected_version": "unknown (not yet bisected; since at least 4.10.4 [read])",
   "affected_versions": "since at least 4.10.4 [read]; 9.12.3, 10.1.0, main [exec]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/7761",
    "https://issues.apache.org/jira/browse/LUCENE-6703"
   ],
   "doc": "",
   "repro": "repro/LFV-041/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-217",
   "priority": "medium",
   "priority_rank": 219,
   "novelty": "new",
   "withheld": false,
   "area": "join / JoinUtil numeric (point-based) query-time join",
   "title": "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",
   "summary": "You build JoinUtil.createJoinQuery(\"fromF\", false, \"toF\", Float.class, fromQuery, searcher, ScoreMode.None) where the from documents store -1 and -2 in a FloatDocValuesField and the to documents index FloatPoint -1, -2 and 3, and expect a query that matches the two to documents with -1 and -2, because the javadoc lists Float and Double as supported numeric types with no sign restriction. Instead createJoinQuery throws IllegalArgumentException 'values are out of order: saw [40 7f ff ff] before [3f ff ff ff]' (that is, -1 before -2; releases before 10.4.0 show an UnsupportedOperationException raised while that message is built), and Double and every scoring ScoreMode fail the same way. The cause is that JoinUtil sorts the collected Float/Double join values as raw IEEE bits in signed-long order, which for negative numbers is the reverse of numeric order, and streams them in that order into PointInSetQuery / PointInSetIncludingScoreQuery, which require strictly ascending points.",
   "impact_class": "crash",
   "introduced_commit": "2babaf8c3d1710280ef53da3d7ba286615e7293e on master (LUCENE-7095 'Add point values support to the numeric field query time join', by martijnvg, reviewed by mikemccand; JIRA patch era, migrated as apache/lucene#8151), with same-day backports 5733f05c70d (branch_6_0, in 6.0.0) and e26a4431942 (branch_6x, from 6.1.0) [read]; it collected the values into a TreeSet<Long> of raw bits (signed-long order). Kept by f70999980c7 (apache/lucene#13392, 2024-05-21, LongHashSet + Arrays.sort, still signed-long order); apache/lucene#14676 (first released in 10.4.0) changed only the visible exception from UnsupportedOperationException to IllegalArgumentException. The defect was in the API's first version",
   "introduced_date": "2016-03-25",
   "first_affected_version": "6.0.0 [exec]",
   "affected_versions": "every release from 6.0.0 to 10.5.2 and main (11.0.0-SNAPSHOT) through ea57360912ed [exec]; visible exception: UnsupportedOperationException from BytesRefBuilder.hashCode while the 'values are out of order' message is built on 6.0.0-10.3.x, IllegalArgumentException 'values are out of order' from 10.4.0 on; not applicable: 5.5.x [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-217.html",
   "repro": "repro/LFV-217/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-804",
   "priority": "medium",
   "priority_rank": 220,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter passage scoring (PassageScorer match labels)",
   "title": "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",
   "summary": "You search with a TermInSetQuery of 886 UUID-shaped ids (or 4,000 short terms) on a field indexed with offsets, get the hit, and call the default UnifiedHighlighter's highlight() on that field, expecting the snippet with the matching id in <b>, as the equivalent ConstantScoreQuery over a SHOULD BooleanQuery of the same ids gives. Instead highlight() throws BytesRefHash$MaxBytesLengthExceededException 'bytes can be at most 32766 in length; got 32786' from PassageScorer.score. For a multi-term set query the highlighter labels each match with the query's whole toString(), which lists every term, and PassageScorer groups those labels in a BytesRefHash, which rejects entries over 32766 bytes; 885 ids (a 32,749-byte toString()) still work.",
   "impact_class": "crash",
   "introduced_commit": "4be69c8540b51f52355f9926cd84f3b3de985180 on branch_8x (main twin 267d70b66b6ac30db1d48f131b294512420f468c, first released in 9.0.0): LUCENE-9349 'TermInSetQuery should use consumeMatchingTerms in visit()' (apache/lucene-solr#1465 by romseygeek, issue now apache/lucene#10389), the regression for default flags: TermInSetQuery.visit switched to consumeTermsMatching, so the highlighter labels its matches with query.toString() [exec]. The size limit itself, which is the fix site, came with LUCENE-8145 (aa5c3a5c222 on branch_7x, main 9422609a5d4, apache/lucene-solr#317 by romseygeek, 7.3.0), which added the BytesRefHash to PassageScorer.score [exec]. With WEIGHT_MATCHES switched on (opt-in until LUCENE-9431 made it the default in 9.0.0) the same query fails from 8.1.0, independently of LUCENE-9349: LUCENE-3041 (apache/lucene-solr#581, 8.1.0) made TermInSetQuery highlightable, and the LUCENE-8286 label is then all terms joined by spaces [exec]. #12156 (9.6.0) adds only the secondary 2-term case.",
   "introduced_date": "2020-04-29 (LUCENE-9349, merged); the label limit 2018-01-30 (LUCENE-8145)",
   "first_affected_version": "8.6.0 [exec] with default flags (8.5.2 passes [exec]); 8.1.0 [exec] with the then opt-in WEIGHT_MATCHES flag; the 32766-byte label limit in PassageScorer exists since 7.3.0 [exec]",
   "affected_versions": "every release from 8.6.0 to 10.5.2 (the last before 10.6.0) and main a9779ef3c193 with default flags [exec]; 8.1.0 to 8.5.2 only with WEIGHT_MATCHES switched on [exec]; 8.0.0 and older do not highlight a TermInSetQuery at all (the design then, LUCENE-6415) and throw nothing [exec]; branch_10_6 head 4ae946e5a9b has the same code as 10.5.2 [read], so 10.6.0 (released 2026-10-29) is very likely affected (not executed); not fixed on main, branch_10x or branch_10_6 (PassageScorer last changed 2023-10-23, #12682)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/11808",
    "https://github.com/apache/lucene/issues/13391",
    "https://github.com/apache/lucene/issues/10649",
    "https://github.com/apache/lucene/issues/10389",
    "https://issues.apache.org/jira/browse/LUCENE-9349",
    "https://github.com/apache/lucene/issues/16905"
   ],
   "doc": "",
   "repro": "repro/LFV-804/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-806",
   "priority": "medium",
   "priority_rank": 221,
   "novelty": "known",
   "withheld": false,
   "area": "queries / intervals (Intervals.atLeast Matches path: MinimumShouldMatchIntervalsSource, CachingMatchesIterator)",
   "title": "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",
   "summary": "You index 'a c b a' and ask Weight#matches, or the default UnifiedHighlighter, for Intervals.atLeast(2, term a, term b, or(term c, term d)); you expect the positions [0,1] [1,2] [2,3] that the query's own interval iterator returns and that the control atLeast(2, a, b, c) gives, and the snippet '<b>a</b> <b>c</b> <b>b</b> <b>a</b>'. Instead iterating the Matches throws IllegalStateException (AssertionError with -ea) from DisjunctionIntervalIterator.currentOrd and the whole highlight call fails, also for the query text 'fn:atLeast(2 a b fn:or(c d))': atLeast's match callback asks every source for its sub-matches, including the or() source that has no interval left and that atLeast has already dropped. For some documents Weight#matches itself throws (atLeast(2, or(c, d), b, phrase(a, b)) on 'c a b').",
   "impact_class": "crash",
   "introduced_commit": "ca073c98fa83c3f8d73552e9078eff4f5fe36c19 'LUCENE-10140: Correct minimizing iterator sub-matches (#370)' by @romseygeek with a co-author (apache/lucene#370; JIRA LUCENE-10140, migrated as apache/lucene#11177; an earlier attempt, #341, was closed unmerged): it added the cache-on-match callback MinimizingConjunctionIntervalsSource.cacheIterators and passes it every atLeast source [read]. The precondition it breaks, the assert and IllegalStateException in DisjunctionIntervalIterator.currentOrd, is older (LUCENE-9099, 7c1ba1aebee, 2020-02-06, first in 8.5.0) and was harmless before ca073c98fa8 because nothing asked an exhausted disjunction for sub-matches. A regression in 9.0.0, not a day-one bug",
   "introduced_date": "2021-10-12",
   "first_affected_version": "9.0.0 [exec]; last unaffected 8.11.4 [exec]: the 8.x line never received LUCENE-10140 (the 8.11.x jars have no MinimizingConjunctionIntervalsSource$MatchCallback)",
   "affected_versions": "every release from 9.0.0 through 10.5.2, 10.6.0 (by reading) and main a9779ef3c193; not fixed upstream. [exec] all 33 releases 9.0.0-10.5.2 fail the test-framework-free history probe 2 of 2 with -ea and -da (B1 atLeast(2, a, b, or(c, d)) on 'a c b a'; B2 atLeast(2, or(c, d), b, phrase(a, b)) on 'c a b'), controls pass on each; the finder's JUnit fails 2 of 3 on main (-ea, -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 4 of 5 on main (-ea, -da), 10.5.2 and 9.12.3; 8.0.0, 8.1.1, 8.2.0, 8.4.1, 8.5.0, 8.9.0, 8.10.1, 8.11.0 and 8.11.4 pass. [read] branch_10_6 head 4ae946e5a9b has the same defect lines (cacheIterators(lookup.values()) at :83, onMatch.onMatch() at :235, the currentOrd assert and ISE at :214/:220), so the released 10.6.0 has it (not executed); upstream main 20ced71c1e6e is 4 commits ahead of a9779ef3c193 and none touches intervals or the highlighter. The query-text route through StandardQueryParser fn:atLeast/fn:or exists from 9.1.0 (LUCENE-10223). Caveats: JDK 25 on aarch64 only; old releases run on a modern JDK",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/11113",
    "https://issues.apache.org/jira/browse/LUCENE-10075",
    "https://issues.apache.org/jira/browse/LUCENE-10140",
    "https://github.com/apache/lucene/issues/11177",
    "https://github.com/apache/lucene/issues/370",
    "https://github.com/apache/lucene/issues/10783"
   ],
   "doc": "",
   "repro": "repro/LFV-806/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1097",
   "priority": "medium",
   "priority_rank": 222,
   "novelty": "known",
   "withheld": false,
   "area": "core/search / multi-term rewrites (ScoringRewrite with FuzzyQuery boosts)",
   "title": "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)",
   "summary": "You highlight the parsed query cat~ with the classic Highlighter over 'a cat sat on a mat', or search FuzzyQuery('cat', 2) with SCORING_BOOLEAN_REWRITE over an index holding the term 'a', and expect highlights or two hits. Instead the rewrite throws IllegalArgumentException 'boost must be a positive float, got -1.0': FuzzyTermsEnum gives 'a' a negative boost, and ScoringRewrite passes it to BoostQuery, while TopTermsRewrite clips such boosts to 0.",
   "impact_class": "crash",
   "introduced_commit": "unknown (not bisected); [read] since 8.0, when LUCENE-7996 made BoostQuery reject negative boosts on top of fuzzy boosts that can be negative",
   "introduced_date": "unknown (not bisected)",
   "first_affected_version": "unknown (not bisected); 8.0 by reading [read]; oldest executed 9.12.3 [exec]",
   "affected_versions": "9.12.3, 10.5.2, 10.6.0, main 645d4fe14a20 [exec]; main e1faeba08bde with -ea and -da [exec].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/10608",
    "https://issues.apache.org/jira/browse/LUCENE-9568"
   ],
   "doc": "",
   "repro": "repro/LFV-1097/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-824",
   "priority": "medium",
   "priority_rank": 223,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / classic Highlighter (QueryScorer, WeightedSpanTermExtractor term-vector path)",
   "title": "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)",
   "summary": "You store a text field with term vectors (positions and offsets), search with a query such as +body:fox plus a FieldExistsQuery filter on another field, and highlight the hit with the classic Highlighter from its term vectors; you expect 'the quick brown <B>fox</B>', which 10.4.0 and earlier return. Since 10.5.0 the call throws IllegalStateException 'FieldExistsQuery requires that the field indexes doc values, norms or vectors, but field 'shadowed_field' exists and indexes neither of these data structures', naming an internal field the user never created. The highlighter rewrites the query against its own one-field reader built from the term vectors, whose field info has no norms or doc values, and since GITHUB#15678 it no longer skips FieldExistsQuery as GITHUB#12088 had made it do.",
   "impact_class": "crash",
   "introduced_commit": "a8b3d1a9481d97c74c2fc06b15d5983288078e3b on main and 7ddd1898b3891c6cc8cf1a2edc513ab1ae3bfbac on branch_10x (GITHUB#15678 'Fix Highlighter crash by implementing getFieldInfos in DelegatingLeafReader', author Simranjeet Singh (GitHub sjs004), merged by romseygeek, fixing #15668): it made DelegatingLeafReader.getFieldInfos answer every field name with the shadowed field's FieldInfo and, on a reviewer's suggestion ('maybe let's remove the special-casing for FieldExistsQuery as well?'), removed the 'query instanceof FieldExistsQuery -> nothing' branch that GITHUB#12088 (fc7b937affe, 9.5.0) had added [exec]. Older ingredients, harmless before: TermVectorLeafReader's FieldInfo without norms, doc values or vectors (LUCENE-6034, 978aac31848, 5.0.0) and FieldExistsQuery.rewrite's IllegalStateException branch (LUCENE-10436, 91e29405d8e, 9.2.0) [read]",
   "introduced_date": "2026-02-09 (author date 2026-02-09T16:57:13Z on both commits; committed to main at 16:57:13Z and to branch_10x at 17:10:50Z)",
   "first_affected_version": "10.5.0 [exec] (tagged 2026-06-25, the first release containing 7ddd1898b38; its CHANGES lists GITHUB#15668 under Bug Fixes); last unaffected 10.4.0 [exec] (cut from branch_10_4, which lacks the backport); the 9.x line never received #15678 (9.12.3 passes [exec])",
   "affected_versions": "10.5.0, 10.5.1 and 10.5.2 [exec]; branch_10_6 head 4ae946e5a9b (10.6.0-SNAPSHOT jars, SHA-1-checked) [exec], so the released 10.6.0 has it too; main a9779ef3c193 [exec]; main 645d4fe14a2 [exec]; branch_10x 657014b3c579 and branch_10_5 e85bb7b2c86d [read]. Not affected: 9.5.0-10.4.0 [exec]. 9.2.0-9.4.2 fail differently, with the older UnsupportedOperationException on every token-stream path, the re-analysed control included (the GITHUB#12088 bug, fixed in 9.5.0) [exec]; 9.1.0 and older have no FieldExistsQuery [exec]. Not fixed upstream.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/7450",
    "https://issues.apache.org/jira/browse/LUCENE-6390",
    "https://github.com/apache/lucene/issues/16907",
    "https://github.com/apache/lucene/issues/16056",
    "https://github.com/apache/lucene/issues/15678",
    "https://github.com/apache/lucene/issues/15668"
   ],
   "doc": "bugs/LFV-824.html",
   "repro": "repro/LFV-824/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-803",
   "priority": "medium",
   "priority_rank": 224,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter re-analysis offset strategies (MemoryIndexOffsetStrategy, TokenStreamOffsetStrategy)",
   "title": "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",
   "summary": "You build UnifiedHighlighter.builder(null, analyzer).withFieldMatcher(f -> true) (the documented requireFieldMatch=false switch) and call highlightWithoutSearcher(\"body\", query, \"hello world\", 1) with query = SHOULD id:<binary bytes 9F 12 FF 00 41> + SHOULD body:hello, and expect \"<b>hello</b> world\", because binary terms are documented Lucene input (StringField's BytesRef constructor), the id term can never occur in analyzed text, the byte-based POSTINGS and TERM_VECTORS offset sources do not throw on such a term, and the classic Highlighter and the default field matcher highlight the same query. Instead the call throws: the default MemoryIndexOffsetStrategy passes the raw term bytes to Automata.makeStringUnion, which is documented to take UTF-8 and throws IllegalArgumentException 'Invalid UTF8 header byte: 0x9f', and TokenStreamOffsetStrategy (withPassageRelevancyOverSpeed(false)) calls BytesRef.utf8ToString, which throws AssertionError with -ea and ArrayIndexOutOfBoundsException with -da. The same happens through highlight() on a stored text field without offsets, and on a field with offsets when the query also has a prefix clause on it.",
   "impact_class": "crash",
   "introduced_commit": "722e82712435ecf46c9868137d885484152f749b (LUCENE-7438 'New UnifiedHighlighter', patch era with no pull request, migrated as apache/lucene#8490, committed by dsmiley; branch_6x cherry-pick 4b6794368df373df1f68ccf27f7556914efeb95e the same day): from its first version AnalysisOffsetStrategy decoded every extracted query term as UTF-8 at two sites (convertTermsToAutomata -> MultiTermHighlighting.makeStringMatchAutomata -> BytesRef.utf8ToString, and buildCombinedAutomaton -> Automata.makeStringUnion over the raw bytes). The realistic route, a binary term from another field, arrived with LUCENE-7575 (2e948fea300f, branch_6x 4e7a7dbf9a56, apache/lucene#8626, 2016-12-05, contributed by jimczi, committed by dsmiley), which added the field matcher (requireFieldMatch=false). Later commits only moved the sites or changed the exception: LUCENE-7526 (7af454ad767c, #8577, 6.4.0, split into TokenStreamOffsetStrategy and MemoryIndexOffsetStrategy), LUCENE-9062 (bed694ec8811, 8.4.0, union moved into CharArrayMatcher.fromTerms), #11808 (188a78d76975, 9.5.0, length filter only) and #12305 (3e4ca4042cf, 9.7.0, makeStringUnion decodes with UnicodeUtil.codePointAt, so the MemoryIndex site throws IllegalArgumentException instead of AssertionError or ArrayIndexOutOfBoundsException) [read]",
   "introduced_date": "2016-10-04 (LUCENE-7438, the UnifiedHighlighter itself); 2016-12-05 (LUCENE-7575, the field matcher that opens the cross-field route)",
   "first_affected_version": "6.3.0 [exec] for a binary term on the highlighted field itself (the first release with the UnifiedHighlighter; 6.2.1 has none [exec]); 6.4.0 [exec] for the realistic route through the field matcher, which 6.3.0 lacks [exec]",
   "affected_versions": "every release from 6.3.0 to 10.5.2 (the last before 10.6.0) and main a9779ef3c193 [exec]; branch_10_6 head 2763db11b0a has the same strategy files [read], so 10.6.0 (released 2026-10-29) is very likely affected (not executed); downstream reports show the same Lucene stack on 7.5, 8.9 and 10.2.2; not fixed on main",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/11808",
    "https://github.com/apache/lucene/issues/16881",
    "https://github.com/apache/lucene/issues/10466",
    "https://issues.apache.org/jira/browse/LUCENE-9426",
    "https://github.com/apache/lucene/issues/8770",
    "https://issues.apache.org/jira/browse/LUCENE-7719"
   ],
   "doc": "",
   "repro": "repro/LFV-803/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-503",
   "priority": "medium",
   "priority_rank": 225,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter WEIGHT_MATCHES path (FieldOffsetStrategy) with reader-bound join queries",
   "title": "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",
   "summary": "You search with a query that contains a JoinUtil global-ordinals join, for example +text:shirt +JoinUtil.createJoinQuery(\"join\", text:great, type:to, searcher, scoreMode, null), and highlight the hits with a UnifiedHighlighter built on that same searcher with default flags. You expect the snippet 'red <b>shirt</b>', which is what the highlighter returns with WEIGHT_MATCHES off. Instead highlight() throws IllegalStateException 'Creating the weight against a different index reader than this query has been built for.', because FieldOffsetStrategy re-creates the query's Weight on a new IndexSearcher over the hit's single leaf, which the join's reader check rejects; the same substitute searcher makes ParentChildrenBlockJoinQuery read its top-level parent doc id as a local id of the hit's segment, so a hit in a later segment loses its highlight ('size small' instead of '<b>size</b> small') or crashes.",
   "impact_class": "crash",
   "introduced_commit": "b19ae942f154 (LUCENE-8286 'UnifiedHighlighter: new HighlightFlag.WEIGHT_MATCHES for MatchesIterator API', dsmiley, 2018-08-29; branch_7x backport bf7d1078e4ef the same day, shipped in 7.5.0; JIRA now apache/lucene#9333, its PR apache/lucene-solr#409 was closed unmerged because the commit was pushed directly) added FieldOffsetStrategy#createOffsetsEnumsWeightMatcher with its new IndexSearcher(leafReader); lines 141-142 and 146-147 still blame to it [read]; default exposure: 2719cf6630eb (LUCENE-9431 'UnifiedHighlighter WEIGHT_MATCHES is now true by default', apache/lucene#362, dsmiley with apanimesh061, 2021-10-22, 9.0.0) [read]; the query-side ingredients are older: the global-ordinals reader check edafcbad1448 / 3a0c2a691d4f (LUCENE-7755 'Join queries should not reference IndexReaders', jpountz, 2017-03-30, 6.5.1) and ParentChildrenBlockJoinQuery's top-level parentDocId e327efb676e0 / 91a62079373 (LUCENE-6959, 2017-01-29, 6.5.0) [read]; no commit-level bisect, the release pairs 7.4.0/7.5.0 and 8.11.4/9.0.0 bracket the two changes [exec]",
   "introduced_date": "2018-08-29 (b19ae942f154, LUCENE-8286, the WEIGHT_MATCHES path, opt-in); default exposure 2021-10-22 (2719cf6630eb, LUCENE-9431)",
   "first_affected_version": "7.5.0 (tagged 2018-09-22) when the application enables WEIGHT_MATCHES (the ParentChildren symptoms; the global-ordinals throw at this code site from 8.1.0, because before 8.1.0 an older term-extraction path threw first); 9.0.0 (tagged 2021-12-06) with the default flags [exec]",
   "affected_versions": "default flags: 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 (the last release before 10.6.0) and main ea57360912ed [exec]: the global-ordinals IllegalStateException for every ScoreMode, the missing ParentChildren highlight and the large-docBase crash on each; the 9.x and 10.x releases not run carry the same code [read]; WEIGHT_MATCHES enabled by the application: 7.5.0, 7.7.3, 8.0.0, 8.1.0 and 8.11.4 [exec]; not affected, no WEIGHT_MATCHES path: 7.4.0 and earlier [exec]; a separate older manifestation at different code: from 6.5.1 to 8.0.0 the default highlighter threw the same IllegalStateException for global-ordinals joins from UnifiedHighlighter#extractTerms (a Weight built on a static empty IndexSearcher), gone in 8.1.0 with LUCENE-3041 [exec], so 8.1.0 to 8.11.4 highlight these hits correctly with default flags and 9.0.0 regressed them; releases before 9.1.0 ran a port to the pre-builder API; not fixed anywhere as of ea57360912ed (no touched file changed upstream since, no open PR changes the mechanism)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9333",
    "https://issues.apache.org/jira/browse/LUCENE-8286",
    "https://github.com/apache/lucene/issues/9891",
    "https://issues.apache.org/jira/browse/LUCENE-8848",
    "https://github.com/apache/lucene/issues/10471",
    "https://issues.apache.org/jira/browse/LUCENE-9431"
   ],
   "doc": "",
   "repro": "repro/LFV-503/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-602",
   "priority": "medium",
   "priority_rank": 226,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / uhighlight + matchhighlight: default offset-source choice on composite readers (core index FieldInfos.getMergedFieldInfos)",
   "title": "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",
   "summary": "You build two indexes in which a field is declared slightly differently, for example 'body' with norms in one and without norms in the other (both with offsets), open them together as new MultiReader(r1, r2), search body:alpha and get both hits. You expect UnifiedHighlighter.highlight(\"body\", query, topDocs) to return both snippets ('<b>alpha</b> beta', '<b>alpha</b> gamma'), as it does when both indexes use the same options or when each index is highlighted on its own. Instead it throws IllegalArgumentException 'cannot change field \"body\" from omitNorms=false to inconsistent omitNorms=true' (and 'cannot change field \"tag\" ...' when only an unrelated field differs), because the default offset-source choice builds FieldInfos.getMergedFieldInfos over the whole MultiReader, which applies the per-index field-consistency check across the two indexes; MatchRegionRetriever's default strategies fail the same way.",
   "impact_class": "crash",
   "introduced_commit": "4b6794368df373df1f68ccf27f7556914efeb95e (LUCENE-7438 'UnifiedHighlighter', branch_6x, first released in 6.3.0; the same change on master is 722e82712435ecf46c9868137d885484152f749b, first in 7.0.0): from its first version the default getOffsetSource()/getFieldInfo() builds MultiFields.getMergedFieldInfos (later FieldInfos.getMergedFieldInfos, LUCENE-7875) over the searcher's whole reader, which already rejected doc-values-type and point-dimension conflicts [read]. The triggers were widened by 890e8a51f83 (LUCENE-8134, by jpountz, 8.0.0: index options no longer downgraded) and d03662c48bf (LUCENE-9334, apache/lucene PR #11, by mayya-sharipova, 9.0.0: norms, term vectors, DOCS vs NONE, doc values, points and vectors must match), neither of which touched the highlighters; MatchRegionRetriever calls getMergedFieldInfos from its first commit 150a8dacb59 (LUCENE-9463, by dweiss, 9.0.0) [read]",
   "introduced_date": "2016-10-04 (LUCENE-7438); widened 2018-02-15 (LUCENE-8134) and 2021-04-14 (LUCENE-9334); MatchRegionRetriever 2020-08-14 (LUCENE-9463)",
   "first_affected_version": "6.3.0 [exec]; 8.0.0 for offsets in one index only [exec]; 9.0.0 for the norms-only and unrelated-field (indexed vs doc-values-only) triggers and for MatchRegionRetriever [exec]; 6.2.1 has no UnifiedHighlighter",
   "affected_versions": "every release with UnifiedHighlighter, 6.3.0 through 10.5.2, and main a9779ef3c193, for some trigger; never fixed. By trigger: doc-values type 6.3.0+ [exec]; offsets in one index only 8.0.0+ [exec]; norms-only and unrelated field 9.0.0+ [exec]; MatchRegionRetriever 9.0.0+ [exec]; the candidate JUnit fails 4/5 on 10.0.0 and 10.5.2 (-ea) and on main (-ea and -da). Releases between the executed ones are inferred from git history [read]. 7.7.3 passes the four headline cases [exec]. Luke (IndexUtils.getFieldInfos) executed on main only. Releases were run on JDK 25; upstream main a95c754ee003 has no later commit on the affected files (2026-10-26).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/1007",
    "https://github.com/apache/lucene/issues/661",
    "https://github.com/apache/lucene/issues/12829",
    "https://issues.apache.org/jira/browse/LUCENE-10314",
    "https://github.com/apache/lucene/issues/11350",
    "https://issues.apache.org/jira/browse/LUCENE-10518"
   ],
   "doc": "",
   "repro": "repro/LFV-602/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-349",
   "priority": "medium",
   "priority_rank": 227,
   "novelty": "known",
   "withheld": false,
   "area": "monitor / presearcher query analysis (QueryAnalyzer, QueryTree; default TermFilteredPresearcher)",
   "title": "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",
   "summary": "You register a query with a Lucene Monitor that contains a clause matching no term, for example 'text:apple OR id:()' where the id list happens to be empty, or the inverted range 'text:[m TO c]' typed into the classic QueryParser. You expect it to be registered: it is a legal query, and the Monitor already indexes queries it cannot analyse under a catch-all token. Instead register() throws IllegalArgumentException 'Cannot build a conjunction with no children', and the other queries passed in the same call (the same internal chunk) are not registered either.",
   "impact_class": "crash",
   "introduced_commit": "251dbe7cea8126cb7ecadc921ba444c63d06c618 (LUCENE-8766 'Add monitor subproject', by GitHub romseygeek, main; branch_8x twin b8773d13ad8 with identical QueryAnalyzer.java and QueryTree.java; JIRA migrated as apache/lucene#9811, no PR number) [read]; not a regression for the throw itself (later commits 2cbf261032d, 78b4f75a2c6, 2ee537ce160, b0ebaaed565, ab453b9541a are cosmetic); the inverted-range and RegexpQuery '#' triggers came from the core change LUCENE-9062 (#10104; bed694ec881 on main, e681f9dca46 on branch_8x, 2019-11-27, first released in 8.4.0 [exec]), which made AutomatonQuery.visit report nothing for an empty language and touched no monitor file; LUCENE-9349 (267d70b66b6, 8.6.0) changed only the message for an empty TermInSetQuery from 'disjunction' to 'conjunction'",
   "introduced_date": "2019-06-13 (251dbe7cea8 and b8773d13ad8; first released in 8.2.0); 2019-11-27 for the automaton triggers (LUCENE-9062, first released in 8.4.0)",
   "first_affected_version": "8.2.0 [exec] (the first lucene-monitor release; 8.1.1 has no monitor module: no Maven Central artifact (HTTP 404) and no lucene/monitor in the source tag)",
   "affected_versions": "every lucene-monitor release from 8.2.0 to 10.5.2 and main ea57360912ed; not fixed anywhere. [exec] the finder's JUnit fails 2 of 2 on 8.2.0, 8.3.1, 8.4.0, 8.11.4 and 9.0.0 (import-only legacy variant), 9.12.3, 10.0.0, 10.5.2 and main (main also with -da); the public-API history probe fails on 8.2.0, 8.3.1, 8.4.0, 8.5.2, 8.6.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main; the independent reproduction's JUnit fails 7 of 10 on main (-ea, -da), 10.5.2 and 9.12.3. Trigger set by version [exec]: 8.2.0 and 8.3.1 reject the empty TermInSetQuery (alone and as a disjunct) but register the inverted range and RegexpQuery '#'; 8.4.0 and later reject all probed triggers. [read] all 48 release tags 8.2.0-10.5.2 in the history clone have both throws and no guard (8.8.2-8.11.3 are not in the clone; 8.11.4 was executed); upstream main still has them and no open PR touches QueryAnalyzer.java or QueryTree.java (read-only check 2026-10-26)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/10092",
    "https://issues.apache.org/jira/browse/LUCENE-9050",
    "https://github.com/apache/lucene/issues/11606",
    "https://issues.apache.org/jira/browse/LUCENE-10570"
   ],
   "doc": "",
   "repro": "repro/LFV-349/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-483",
   "priority": "medium",
   "priority_rank": 228,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / analysis-common miscellaneous filters (DateRecognizerFilterFactory, DateRecognizerFilter)",
   "title": "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",
   "summary": "You build an analyzer with CustomAnalyzer from a whitespace tokenizer and the dateRecognizer filter (datePattern=yyyy-MM-dd, locale=en-US) and analyse text such as '2024-01-15 foo 1999-12-31' from four threads at once, as IndexWriter does with its indexing threads. You expect every thread to get the same date tokens as a single-threaded run, because Analyzer gives each thread its own set of token stream components. Instead some analyses throw NumberFormatException ('multiple points', 'For input string: \"\"') or ArrayIndexOutOfBoundsException, because DateRecognizerFilterFactory creates one java.text.DateFormat, which is not thread-safe, and create() passes that same instance to the filter of every thread.",
   "impact_class": "crash",
   "introduced_commit": "073dbdc17e31708077dadbfb316220f76d7b10df (LUCENE-6973 'Improve TeeSinkTokenFilter', migrated as apache/lucene#8030, Shai Erera; trunk svn r1724789, SVN era, no pull request) and its branch_5x backport 1ff4e84f89f804998d7f6f9486bc9dcb692e5846 (svn r1724795), which shipped in 5.5.0. It added DateRecognizerFilter (replacing sinks/DateRecognizerSinkFilter, which took a caller-supplied DateFormat and had no factory) and DateRecognizerFilterFactory with the single DateFormat field [read]. Not a regression: the sharing is in the factory's first version, and git diff -w 5.5.0..main shows only imports, the SPI NAME, the throwing default constructor (LUCENE-8778, LUCENE-9281), formatting and the catch variable name",
   "introduced_date": "2016-01-15 (trunk 073dbdc17e3 and branch_5x 1ff4e84f89f the same day; first released in 5.5.0)",
   "first_affected_version": "5.5.0 [exec] (the first release with DateRecognizerFilterFactory; 5.4.1 has no such API [exec] and only sinks/DateRecognizerSinkFilter, whose caller supplies the DateFormat); 6.0.0 [exec] on the trunk line",
   "affected_versions": "every release from 5.5.0 through 10.5.2 and main ea57360912ed; never fixed. [exec] 5.5.0, 5.5.5, 6.0.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main: the factory-built analyzer fails 3 of 3, the per-component control passes 3 of 3; -ea -dsa on 5.5.0 and main gives the same rates as -da; the finder's JUnit fails on main (-ea and -da) and on 9.12.3 and 10.5.2 (-ea), the independent reproduction's JUnit on 9.12.3, 10.5.2 and main (-ea and -da), the intended-behaviour check's IndexWriter JUnit on main (-ea, -da) and 10.5.2 (-ea). [read] javap of create() in every executed jar shows getfield dateFormat passed straight to the filter, with no clone; the other releases have the same source (git diff -w 5.5.0..main); 8.9-8.11 come from the separate lucene-solr repository and were checked through 8.11.4 only. Upstream main a9779ef3c193 and branch_10x still pass the shared instance [read]. Every target ran on JDK 25 (aarch64): the Lucene-side sharing is identical in every release, but rates and exception types under the JDKs current at each release (Java 7/8 for 5.x) were not measured",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-483.html",
   "repro": "repro/LFV-483/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-526",
   "priority": "medium",
   "priority_rank": 229,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-common / pattern tokenizers (SimplePatternTokenizer String constructors)",
   "title": "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'",
   "summary": "You build a tokenizer with new SimplePatternTokenizer(\"ab|ac\") (or the three-argument String constructor with a determinizeWorkLimit) and expect a working tokenizer for any valid RegExp, as the constructors' javadoc ('See RegExp for the accepted syntax'), the sibling SimplePatternSplitTokenizer and both factories give you. Instead the constructor throws IllegalArgumentException('please determinize the incoming automaton first'): it passes new RegExp(regexp).toAutomaton() unchanged to the Automaton constructor, which rejects non-deterministic automata, and since Lucene 10.0 (LUCENE-10010) RegExp no longer determinizes its result. The determinizeWorkLimit argument is never used.",
   "impact_class": "crash",
   "introduced_commit": "84e4b85b094ccf2dc248ad90a302307d3618b81e (apache/lucene#513, LUCENE-10010 'don't determinize/minimize in RegExp', by rmuir, committed 2021-12-07, merged 2021-12-08) [read]. Older stages: the defective line this(factory, new RegExp(regexp).toAutomaton()) dates from LUCENE-7465 (93fa72f77bd0, 2017-02-13, released 6.5.0) and never used its limit argument; LUCENE-7914 (7dde798473d1, 2017-08-04, 7.0.0) already let a narrower class of patterns, a top-level {m,n} with overlapping copies such as ([a-z]+-?){1,3}, come back as an NFA; LUCENE-9981 (c4cf7aa3e199, 2021-06-01, 9.0.0) wired the limit into the sibling's constructor only",
   "introduced_date": "2021-12-07 (84e4b85b094c; merged 2021-12-08); earlier stages 2017-02-13 (limit ignored) and 2017-08-04 (narrow {m,n} trigger)",
   "first_affected_version": "10.0.0 [exec] for the reported trigger (unions whose branches overlap, e.g. ab|ac); 9.12.3 and every earlier release build it [exec]. Narrower trigger ([a-z]+-?){1,3}: from 7.0.0 [exec]. Ignored determinizeWorkLimit: since 6.5.0, where the class was added [exec]",
   "affected_versions": "main ea57360912ed (-ea and -da) and all 12 10.x releases before 10.6.0 (10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2) [exec]; not affected by that trigger: 6.5.0, 6.6.6, 7.0.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3 [exec]. The narrow {m,n} trigger also fails on 7.0.0, 7.7.3, 8.11.4, 9.0.0 and 9.12.3 [exec]. The ignored limit is visible on 9.0.0 and 9.12.3 (TooComplexToDeterminizeException at the default limit although 10^6 was passed, the sibling accepts) [exec]. branch_10x and branch_10_6 unchanged [read]; upstream main a9779ef3c193 unchanged [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/485",
    "https://github.com/apache/lucene/issues/513",
    "https://github.com/apache/lucene/issues/8517",
    "https://issues.apache.org/jira/browse/LUCENE-7465",
    "https://github.com/apache/lucene/issues/528",
    "https://issues.apache.org/jira/browse/LUCENE-10296"
   ],
   "doc": "",
   "repro": "repro/LFV-526/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-527",
   "priority": "medium",
   "priority_rank": 230,
   "novelty": "new",
   "withheld": false,
   "area": "facet / SortedSetDocValues faceting (AbstractSortedSetDocValueFacetCounts#prepareChildIteration, shared by SortedSetDocValuesFacetCounts and ConcurrentSortedSetDocValuesFacetCounts)",
   "title": "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)",
   "summary": "You declare a facet dimension as hierarchical (FacetsConfig.setHierarchical(\"category\", true)), index SortedSetDocValues facets in which no document has \"category\" yet, and call getTopChildren(10, \"category\") or getAllChildren(\"category\") on SortedSetDocValuesFacetCounts or ConcurrentSortedSetDocValuesFacetCounts, expecting null, because the Facets javadoc says both methods return null 'if this dimension was never seen' and the same call for a flat dimension does. Instead both throw NullPointerException: Cannot read field \"dimStartOrd\" because \"dimTree\" is null (getTopChildren when the query has hits, always with the count-all constructor and the concurrent class; getAllChildren always). The cause is a shortcut added in 9.3.0 to AbstractSortedSetDocValueFacetCounts#prepareChildIteration, which reads dimTree.dimStartOrd for an empty path without checking that state.getDimTree(dim) is non-null, while the flat branch and the path branch next to it return null for the same case.",
   "impact_class": "crash",
   "introduced_commit": "8db1e41fc072920dc1c6554f5859d4dd623dace6 (LUCENE-10585, apache/lucene#915 'Scrub copy/paste code in the facets module and attempt to simplify a bit', by @gsmiller; branch_9x backport 075f5103e9ac7f344d11e4b3ad3699a1f2be9f66, the line that shipped first) [exec]. It replaced the null-safe dv.lookupTerm(pathToString(dim, path)) of the hierarchical branch with 'pathOrd = dimTree.dimStartOrd' for an empty path ('a little more efficient to just look up the dim'), ahead of the 'pathOrd < 0 -> null' check. LUCENE-10550 (#914, 9.3.0) copied the shortcut into the new getAllChildren and #983 (9.3.0) moved both copies into prepareChildIteration (git blame on main points at that move). In the review of LUCENE-10250 (#509, 9.1.0) a dimTree == null check had been removed as unreachable, which was correct while the term lookup ran first.",
   "introduced_date": "2022-05-29 (8db1e41fc07 on main and the branch_9x backport 075f5103e9a)",
   "first_affected_version": "9.3.0 [exec] (tagged 2022-07-28, first release with the backport); not affected: 9.2.0 and 9.1.0 return null [exec]; 9.0.0 and earlier have no hierarchical SortedSetDocValues facets [exec]; on the main line the commit is first released in 10.0.0",
   "affected_versions": "every release from 9.3.0 to 9.12.3 and from 10.0.0 to 10.5.2, plus main ea57360912ed; never fixed. [exec] 9.3.0, 9.10.0, 9.11.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da on 9.3.0, 10.5.2 and main); [read] the unguarded 'pathOrd = dimTree.dimStartOrd;' is present at every 9.x/10.x tag from 9.3.0 to 10.5.2 and on upstream main (line 257) and branch_10x (line 264) on 2026-10-26. Since 9.11.0 (#12408, backport #13300) getTopChildren on SortedSetDocValuesFacetCounts returns null when the query has no hits (9.10.0 still throws there [exec]); getAllChildren, the count-all constructor and ConcurrentSortedSetDocValuesFacetCounts (whose hasCounts() is always true) still throw",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-527.html",
   "repro": "repro/LFV-527/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-725",
   "priority": "medium",
   "priority_rank": 231,
   "novelty": "known",
   "withheld": false,
   "area": "facet / DrillSideways (default buildFacetsResult for the mixed TaxonomyReader + SortedSetDocValuesReaderState constructors)",
   "title": "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)",
   "summary": "You index a taxonomy dimension color with FacetField and a SortedSetDocValues dimension size with SortedSetDocValuesFacetField in its own index field (indexing rejects both kinds in one field), create new DrillSideways(searcher, config, taxoReader, state), whose javadoc says it is for indexes 'where some dimensions were indexed with SortedSetDocValuesFacetField and others were indexed with FacetField', and drill down on color/red; you expect result.facets.getTopChildren(10, \"size\") to return the size counts of the matching documents (large 3, small 1), as SortedSetDocValuesFacetCounts over the result's own drillDownFacetsCollector does. Instead it throws IllegalArgumentException 'dimension \"size\" cannot be found in field \"$facets\", since it was configured to be indexed into field \"ssdv_f\"', because the default buildFacetsResult builds FastTaxonomyFacetCounts on the default field for the drill-down and for every sideways dimension whenever taxoReader != null and never reads the state. In the other layout (size on $facets, color in its own field) size silently returns null and is missing from getAllDims.",
   "impact_class": "wrong error",
   "introduced_commit": "46e67d8f04be8d095e2897132f76d1ac84205249 ('LUCENE-5339: cutover DrillSideways', by mikemccand, svn r1542713 on the lucene5339 development branch) added the constructor (searcher, config, taxoReader, state), javadoc 'where some dimensions are sorted set facets and others are taxononmy facets', with a buildFacetsResult that never read the state; 88f18570790cfe194a29602cf4bc3e770e3f6078 ('LUCENE-5339: cutover more tests; fixed a few bugs', r1544299) gave the method its current shape (taxonomy counts if taxoReader != null, else SortedSetDocValues counts; the state is read only when taxoReader == null); the current constructor javadoc is from 825a02356de; the work reached branch_4x in 7477fde1cb063b5c849369afa531bb28df4566fc (r1555342; trunk merge 9d0b60388da). LUCENE-5339 = apache/lucene#6403; Subversion era, no pull request. The ExecutorService constructor with the same javadoc and the same default came with b4a002f7d88 (LUCENE-7588, #8639, first released in 6.4.0). Later edits (3b67b174932, 7f8b7ffbcad, 3c7a76a148b LUCENE-9962 #143) did not change the choice [read]",
   "introduced_date": "2013-11-17 (46e67d8f04b, development branch); current taxoReader-or-state branch 2013-11-21 (88f18570790); on branch_4x 2014-01-04 (7477fde1cb0)",
   "first_affected_version": "4.7.0 [exec] (first release with the 4-argument constructor; 4.6.1, the last release before it, has only the old facet API, whose DrillSideways cannot take both readers, and the probe does not compile there [exec]); the 5-argument ExecutorService constructor from 6.4.0 [exec]",
   "affected_versions": "Every lucene-facet release on Maven Central from 4.7.0 to 10.5.2 (119 releases: 4.7.0-4.10.4 and every 5.x, 6.x, 7.x, 8.x and 9.x release and 10.0.0-10.5.2, including 8.11.4 and 9.12.3) and main a9779ef3c193 (-ea and -da); never fixed [exec]. Same symptoms everywhere: SSDV dims in their own field throw IllegalArgumentException for drill-down and sideways counts and, from 6.4.0, with the ExecutorService constructor; SSDV dims on $facets silently return null. Only the message changes (4.7.0-8.11.4 'was not indexed into field', 9.0.0 on 'cannot be found in field ...'). The independent reproduction's JUnit also fails on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main. [read] buildFacetsResult is identical on upstream main a95c754ee003 (2026-10-26), branch_10x 1309534296e and branch_10_6 2763db11b0a (contained in 10.6.0, released 2026-10-29), so 10.6.0 is affected too. Executed on aarch64 Linux with JDK 25 only",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/6049",
    "https://github.com/apache/lucene/issues/5860",
    "https://github.com/apache/lucene/issues/6403",
    "https://github.com/apache/lucene/issues/10984",
    "https://github.com/apache/lucene/issues/8639",
    "https://github.com/apache/lucene/issues/149"
   ],
   "doc": "",
   "repro": "repro/LFV-725/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-662",
   "priority": "medium",
   "priority_rank": 232,
   "novelty": "known",
   "withheld": false,
   "area": "suggest / FreeTextSuggester (n-gram model built with ShingleFilter; lookup context counts after analysis holes)",
   "title": "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)",
   "summary": "You build a FreeTextSuggester with the default constructor and the stock EnglishAnalyzer over 'the wizard of oz' and call lookup('the w'), expecting the suggestion 'wizard': lookup documents only IllegalArgumentException and IllegalStateException, and the upstream tests testEndingHole and testTwoEndingHoles assert results for a stop-word analyzer. Instead lookup throws AssertionError at FreeTextSuggester.java:576 with -ea, or NullPointerException in decodeWeight (:724) with -da: the removed 'the' leaves a hole, so the bigram-level query token is '_ w', which matches the stored shingle '_ wizard', and lookup then reads the count of its context '_', which ShingleFilter never emits and the model therefore never stores. The same happens on the upstream testEndingHole model for lookup('wizard of o'), one keystroke after the query that test asserts.",
   "impact_class": "crash",
   "introduced_commit": "b50a2edbb2389797a7354775414052df91b108f6 (trunk, svn r1528517) and its branch_4x backport 9494be7ec2ae84e88b6fc07046c35cac15e790d2 (svn r1528521, byte-identical file; the commit 4.6.0 contains): LUCENE-5214 'Add new FreeTextSuggester, to handle \"long tail\" suggestions' (migrated issue apache/lucene#6278; Subversion era, no pull request; patch by GitHub mikemccand), which added the class with the unguarded context-count read ('assert output != null; contextCount = decodeWeight(output);'), the trailing-hole-only skip ('if (endPosInc > 0 && gram <= endPosInc)') and the ShingleFilter wiring that stores filler-led shingles such as '_ oz' but never a filler-only '_' [read]. Original defect, not a regression; no release before 4.6.0 has the class [exec]",
   "introduced_date": "2013-10-02",
   "first_affected_version": "4.6.0 [exec], the first release with FreeTextSuggester; 4.5.1 and older do not have the class [exec]",
   "affected_versions": "every release from 4.6.0 through 10.5.2 (121 releases), 10.6.0 (by reading) and main a9779ef3c193; never fixed (upstream main a95c754ee003 has the byte-identical file; branch_10x / branch_10_6 differ only in build() resource handling, crash path identical [read]; no upstream commit touches FreeTextSuggester.java after 54283150a816 of 2026-06-14, checked read-only 2026-10-27). [exec] all 121 releases fail with -ea (AssertionError) and with -da (NullPointerException), each at that release's own 'assert output != null' line or the decodeWeight unboxing called from the next line (226 tagged runs OK, 18 runs on 8.8.2-8.11.4 not tagged in the history clone); 18 runs on 5.1.0-6.3.0 first died in build() on JDK 25 (MMapDirectory unmap hack) and all reproduce when re-run with two --add-opens flags. [exec] the finder's JUnit fails 2/2 on main (-ea, -da), 10.5.2, 10.0.0 and 9.12.3 (it cannot compile on 9.0.0, which has no org.apache.lucene.tests.*); the independent reproduction's fails 3/5 on main, 10.5.2 and 9.12.3 (-ea and -da; its 2 controls pass); the intended-behaviour check's configuration matrix fails 2/5 on main (-ea, -da), 10.5.2 and 9.12.3 (-da). [read] all 112 release tags 4.6.0..10.5.2 in the history clone have the unguarded assert and the trailing-hole-only skip. Releases were run on JDK 25.",
   "security": "none",
   "upstream_links": [
    "https://lists.apache.org/thread/sm828gsrzm21q896rrn1p26gzblp6zjh",
    "https://github.com/apache/lucene/issues/13390",
    "https://github.com/apache/lucene/issues/6278",
    "https://issues.apache.org/jira/browse/LUCENE-5214",
    "https://github.com/apache/lucene/issues/6244",
    "https://issues.apache.org/jira/browse/LUCENE-5180"
   ],
   "doc": "",
   "repro": "repro/LFV-662/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-704",
   "priority": "medium",
   "priority_rank": 233,
   "novelty": "known",
   "withheld": false,
   "area": "queryparser / complexPhrase: ComplexPhraseQueryParser (ComplexPhraseQuery.rewrite building a SpanNearQuery)",
   "title": "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",
   "summary": "You parse a quoted phrase such as \"the beat*\" with ComplexPhraseQueryParser and an analyzer that removes the stop word 'the', or \"+john\", or \"john^2\", and search with it; single-clause complex phrases are supported (\"beat*\" and \"john\" work, upstream testSingleTermPhrase) and interior boosts are ignored by design (TestComplexPhraseQuery testBoosts), so you expect the hits of \"beat*\" or \"john\". Instead parse() succeeds and IndexSearcher.search throws IllegalArgumentException: when the contents are a one-clause BooleanQuery, ComplexPhraseQuery.rewrite builds a one-clause SpanNearQuery (ComplexPhraseQueryParser.java:331-333), which SpanNearQuery documents as invalid ('at least 2' clauses, SpanNearQuery.java:115), and ConjunctionSpans throws 'Less than 2 subSpans.size():1'; when the contents are a lone BoostQuery, rewrite throws 'Unknown query type \"org.apache.lucene.search.BoostQuery\" found in phrase query string' (:270-277).",
   "impact_class": "crash",
   "introduced_commit": "c0399fe9a11bd8cb3046b8c1ca1ecdf5fce7e642 (LUCENE-6308 on branch_5x, svn r1670273; trunk d3cfba9b29511279b79071ee8fe6ed1996a2af3c, r1670272; Subversion era, no pull request, JIRA migrated as #7369; committed by Michael McCandless, CHANGES credits Paul Elschot and Robert Muir): it removed the 0- and 1-clause shortcuts from SpanNearQuery.getSpans, added the two-sub-span check (moved into ConjunctionSpans with today's message by LUCENE-6083, 2e2ae5435e72, also first released in 5.2.0) and documented 'at least 2' clauses, without adapting ComplexPhraseQuery.rewrite. The boosted shape comes from LUCENE-6590 (branch_5x fb2a8aaac40bd78dc4749c2df69e00e8eff730b8, svn r1701783, with LUCENE-6783; trunk 962313b83ba9c69379e1f84dffc881a361713ce9, r1701621; by Adrien Grand; JIRA migrated as #7648), which made the parser wrap boosts in BoostQuery and unwrapped BoostQuery only for the clauses inside a BooleanQuery. The unguarded SpanNearQuery construction and the 'Unknown query type' branch are latent since the class's initial commit f7fa57997191 (LUCENE-1486, 2009-07-06) [read]",
   "introduced_date": "2015-03-31 (LUCENE-6308, one-clause shape); 2015-09-08 on branch_5x, 2015-09-07 on trunk (LUCENE-6590, boosted shape)",
   "first_affected_version": "5.2.0 [exec] (5.0.0 and 5.1.0 not affected [exec]); the boosted single clause (\"john^2\") from 5.4.0 [exec] (5.3.0 and 5.3.2 return its hits [exec])",
   "affected_versions": "Every release from 5.2.0 through 10.5.2 and main a9779ef3c193; the boosted shape from 5.4.0 [exec]. 4.x not executed: its SpanNearQuery.getSpans still had the one-clause shortcut [read]. In 5.2.0-6.6.6 the trigger was wider: a leading stop word before a plain term (\"the john\") also threw, because the classic parser split on whitespace by default until 7.0.0 (LUCENE-2605) [exec]; on 7.0.0 and later that form needs splitOnWhitespace=true. Not fixed: upstream main a95c754ee003 (2026-10-26) has the same rewrite, and no open PR touches complexPhrase/, SpanNearQuery.java or ConjunctionSpans.java [read].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9712",
    "https://issues.apache.org/jira/browse/LUCENE-8666",
    "https://github.com/apache/lucene/issues/7369",
    "https://issues.apache.org/jira/browse/LUCENE-6308",
    "https://github.com/apache/lucene/issues/3651",
    "https://issues.apache.org/jira/browse/LUCENE-2577"
   ],
   "doc": "",
   "repro": "repro/LFV-704/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-758",
   "priority": "medium",
   "priority_rank": 234,
   "novelty": "known",
   "withheld": false,
   "area": "search / vector queries (KnnFloat/Byte/Float16VectorQuery, Float/Byte/Float16VectorSimilarityQuery; join DiversifyingChildren*KnnVectorQuery)",
   "title": "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",
   "summary": "You decode a query embedding into a scratch float[], build new KnnFloatVectorQuery(field, scratch, k), decode the next embedding into the same array, build a second query and OR the two; you expect each query to search the vector it was built from, as TermQuery does when built from a reused BytesRef. Instead both queries now search the second vector and compare equal, so the OR returns 1 hit instead of 2 (the neighbour of the first vector is lost); the same holds for KnnByteVectorQuery, KnnFloat16VectorQuery, the three vector-similarity queries and the join DiversifyingChildren*KnnVectorQuery classes. The constructors store the caller's array itself (VectorUtil.checkFinite returns its argument) and search, equals and hashCode all read it, although getTargetCopy() returns a copy precisely so that callers cannot reach that array.",
   "impact_class": "silent wrong results",
   "introduced_commit": "624560a3d706 (LUCENE-9614 'add KnnVectorQuery implementation', apache/lucene#235 by msokolov, merged 2021-08-13) [read]: KnnVectorQuery stored 'this.target = target;' and based equals/hashCode on that field; no version ever copied the target. Every later vector query class repeated the store: KnnByteVectorQuery (72968d30ba1, #12004, 9.5.0; first 'new BytesRef(target)', which wraps without a copy, then the byte[] itself after #12064), KnnFloatVectorQuery (92e67ec626b, #12105, the 9.5.0 rename), the join DiversifyingChildrenFloat/ByteKnnVectorQuery (a65cf8960a1, #12434, renamed in #12510, 9.8.0; their own 'this.query = query' plus the superclass's reference), Float/ByteVectorSimilarityQuery (cd195980ecb, #12679, 9.10.0) and the float16 classes (bfe5c847d3c #16383, 020802ff070 #16735, cb276351c10 #16738; 2026, main only). #12029 (77eca4bb388, 9.5.0) added copying getTargetCopy() getters and left the constructors as they were; #12281 (071461ece54, 9.7.0) wrapped the store in VectorUtil.checkFinite, which returns its argument, so git blame on main stops there",
   "introduced_date": "2021-08-13",
   "first_affected_version": "9.0.0 [exec]; 8.11.x is not affected because the API does not exist there (8.11.0 and 8.11.4 executed: the probe finds none of the classes and the 9.0-API repro does not compile) [exec]",
   "affected_versions": "Every release that has vector queries, 9.0.0 through 10.5.2 (33 releases), 10.6.0 (by reading), and main a9779ef3c193; never fixed (the constructors are unchanged on upstream main f7bcc0abd816 and, for the float and byte classes, on branch_10x; branch_10_6 has the 10.5.2 lines; read 2026-10-27, not executed). [exec] the reflection probe (VectorQueryOwnershipHistoryProbe: build from a buffer, refill, compare with a copy-built twin) reports ALIASED for every vector query class present in each of the 33 releases and on main (9 classes on main), with the TermQuery control COPIED everywhere; hit-level JUnits fail with their controls passing at each class's first release and later: KnnVectorQuery on 9.0.0 (-ea and -da), 9.4.2 and 9.12.3 (2 of 3); KnnFloat/ByteVectorQuery on 9.5.0, 9.12.3, 10.0.0 and 10.5.2 (2 of 2); the join classes on 9.8.0, 9.12.3, 10.0.0, 10.5.2 and main (2 of 3); the similarity queries on 9.10.0, 9.12.3, 10.0.0, 10.5.2 and main (3 of 4); the finder's JUnit 3 of 3 and the independent reproduction's 8 of 10 on main (-ea and -da). The float16 classes exist on main only (unreleased). [read] the releases in between carry the same constructor lines. All runs with JDK 25.0.3 on aarch64; the behaviour is plain Java array sharing, independent of codec and platform",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/12253",
    "https://github.com/apache/lucene/issues/12029",
    "https://github.com/apache/lucene/issues/14009",
    "https://github.com/apache/lucene/issues/12281",
    "https://github.com/apache/lucene/issues/235",
    "https://issues.apache.org/jira/browse/LUCENE-9614"
   ],
   "doc": "",
   "repro": "repro/LFV-758/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-330",
   "priority": "medium",
   "priority_rank": 235,
   "novelty": "new",
   "withheld": false,
   "area": "memory / MemoryIndex stored fields",
   "title": "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)",
   "summary": "You build a MemoryIndex from a document with StringField(\"id\", \"doc-1\", Store.YES), a KeywordField(String, Store.YES) or an IntField(\"count\", 5, Store.YES) and read it back through storedFields().document(0), expecting the same stored values IndexWriter returns, since MemoryIndex has supported stored fields since 9.5.0 (#11999). Instead MemoryIndex stores the field's binaryValue() rather than its storedValue(): the String comes back as its UTF-8 bytes, so Document.get(\"id\") returns null, and the numbers come back as their sortable point bytes (IntField 5 as [80 00 00 05]), so numericValue() returns null. A StoredField built from a StoredFieldDataInput is not stored at all; the BytesRef constructors and plain StoredField values are unaffected.",
   "impact_class": "silent wrong results",
   "introduced_commit": "#12116 (96136b42821 on main, 84dcaa850b1 on branch_9x, 'Improve document API for stored fields') [read]: it added IndexableField#storedValue(), moved IndexWriter to it and gave IntField/LongField/FloatField/DoubleField Store constructors, but did not migrate MemoryIndex.storeValues, which #11999 (66127f6e696, 2022-12-08, first released in 9.5.0) had written and which was correct then (storedValue() did not exist; all 19 lines, 867-885, blame to it, unchanged since). In the same 9.6.0 cycle #12054 (ab074d54839) added KeywordField with a term binaryValue() and #12139 (cce33b07e4f) gave StringField one, which caused the headline StringField(String) regression (#12139 also made MemoryIndex.addField index that binaryValue() as the term, but left storeValues unchanged) [exec]; #14213 (f12e44b6515, 10.2.0) added StoredFieldDataInput, visible only through storedValue(), so MemoryIndex drops it [exec]",
   "introduced_date": "2023-02-06 (#12116); 2023-02-07 (#12054) and 2023-02-21 (#12139) in the same 9.6.0 cycle; 2025-02-19 (#14213, the StoredFieldDataInput case)",
   "first_affected_version": "9.6.0 [exec] (9.5.0 is the last unaffected release); the StoredFieldDataInput case 10.2.0 [exec], the first release with that API",
   "affected_versions": "9.6.0 through 9.12.3, 10.0.0 through 10.5.2 and main ea57360912ed: executed on 9.6.0, 9.7.0 (StringField case only), 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.5.2 and main with -ea, and also with -da on 9.12.3, 10.5.2 and main [exec]; the releases in between have a byte-identical storeValues, no storedValue() call in MemoryIndex and the same binaryValue() overrides [read]; the StoredFieldDataInput case 10.2.0 and later only; 9.5.0 not affected (StringField(String) and the controls pass) [exec]; before 9.5.0 MemoryIndex returned no stored fields at all (9.4.2) [exec]; upstream main e1c4184cb983 and branch_10x unchanged on 2026-10-26 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-330.html",
   "repro": "repro/LFV-330/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-105",
   "priority": "medium",
   "priority_rank": 236,
   "novelty": "new",
   "withheld": false,
   "area": "index / indexing chain (single-term BINARY inversion, norms)",
   "title": "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",
   "summary": "You index one value in an untokenized field whose FieldType has DOCS_AND_FREQS and norms enabled, once through a plain Field (TokenStream inversion) and once through the single-term path (a Field subclass whose invertableType() returns BINARY, or an IndexWriter#addBatch BinaryColumn or DictionaryColumn). You expect the same field length and norm, 1 per value, because FieldInvertState#getLength is the 'total number of terms in this field' and a BINARY value is documented as a single value with term frequency one. Instead IndexingChain.invertTerm adds 2 to the length for every value, so the norm is 2 (2k for k values) and the BM25 score of the identical document drops (0.082873434 to 0.058813408 in the repro), while the postings still record freq 1 per value.",
   "impact_class": "silent wrong results",
   "introduced_commit": "cce33b07e4f5 (#12139 'Skip the TokenStream overhead when indexing simple keywords', main; 9.x backport 668246439ddf the same day), which created invertTerm with both 'invertState.length++;' and 'invertState.length = Math.addExact(invertState.length, 1);' [exec]; not a regression of older code: the doubled count came with the BINARY path itself. The addBatch trigger came later with #15990 (3d895681557, merged 2026-05-14; backport 3ec3bff01b1, first released in 10.5.0), whose BinaryColumnAdapter#invertableType returns BINARY for indexed untokenized columns [read]",
   "introduced_date": "2023-02-21 (#12139 merged into main and backported to branch_9x the same day); addBatch trigger from 2026-05-14 (#15990 merged)",
   "first_affected_version": "9.6.0 [exec] (addDocument with a field whose invertableType() is BINARY); 10.5.0 for the addBatch BinaryColumn trigger [exec]",
   "affected_versions": "every release from 9.6.0 on: 9.6.0-9.12.3, 10.0.0-10.5.2 and 10.6.0 (by reading), and main ea57360912ed [exec]; addBatch trigger: 10.5.0-10.5.2, 10.6.0 (by reading) and main [exec]; not affected: 9.5.0 and earlier, where InvertableType and the BINARY path do not exist (the repro does not compile; the TokenStream baseline is correct) [exec]; not fixed upstream: main, branch_10x, branch_10_6 (10.6.0, released 2026-10-29), branch_10_5 and branch_9_12 still have both increments [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-105.html",
   "repro": "repro/LFV-105/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-333",
   "priority": "medium",
   "priority_rank": 237,
   "novelty": "new",
   "withheld": false,
   "area": "memory / MemoryIndex term inversion (custom term frequencies: FeatureField, TermFrequencyAttribute streams, DOCS_AND_CUSTOM_FREQS); reached in-tree through monitor single-document batches",
   "title": "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)",
   "summary": "You add a document with FeatureField(\"features\", \"pagerank\", 10f), or a tokenized DOCS_AND_FREQS field whose TokenStream sets TermFrequencyAttribute (for example DelimitedTermFrequencyTokenFilter on 'a|7'), to a MemoryIndex and expect its postings, statistics and scores to equal those of the same document in a one-document IndexWriter index, as they do for ordinary fields. Instead MemoryIndex.storeTerms never reads the attribute and counts every token as frequency 1: FeatureField.newLinearQuery scores 4.5918E-41 instead of 10.0, newSaturationQuery with the pivot 10 scores exactly 0.0 (MemoryIndex.search's 'no match' value) for a document that matches, and a term with custom frequency 7 reports freq 1, sumTotalTermFreq 1 and a lower BM25 score. Lucene Monitor inherits it (since 8.6.0): the same FeatureField document scores 10.0 in a two-document batch (IndexWriter path) and 4.5918E-41 when matched alone (MemoryIndex path).",
   "impact_class": "silent wrong results",
   "introduced_commit": "d276acfbbcb8ea6124fe486e35cea9eb928e4702 (LUCENE-7854 'enable indexing custom term frequencies', by GitHub mikemccand; a JIRA patch with no GitHub PR, migrated as apache/lucene#8905) [read]. An omission since the feature was introduced, not a regression: MemoryIndex's one-per-token counting is older (current lines from LUCENE-7091 cf3eea264066, 2016-03-09; a per-token loop since 2005). Later commits widened the reach without touching it: 5844ed4ac953 (LUCENE-7854 follow-up, DelimitedTermFrequencyTokenFilter, 7.0.0), 70cc7b68783b / 710993435f36 (LUCENE-8197, FeatureField, 7.4.0), 29e5b8abcee8 (LUCENE-8031, edited storeTerms and the norm, still not reading the attribute, 8.0.0) and 3a55cc9ac5e9 / 5158a52a082b (#15584, DOCS_AND_CUSTOM_FREQS, one MemoryIndex line changed, 10.5.0)",
   "introduced_date": "2017-06-06 (d276acfbbcb8); reach widened 2017-06-09 (DelimitedTermFrequencyTokenFilter), 2018-03-20 (FeatureField) and 2026-04-24 (#15584 merged, DOCS_AND_CUSTOM_FREQS)",
   "first_affected_version": "7.0.0 [exec] (first release with TermFrequencyAttribute; 6.6.6 has no such API and the probe does not compile); the FeatureField path from 7.4.0 [exec]; the DOCS_AND_CUSTOM_FREQS sub-case from 10.5.0 [exec]",
   "affected_versions": "Every release checked from 7.0.0 to 10.6.0 (10.6.0 by reading), and main (ea57360912ed and a9779ef3c193). [exec] plain main() history probes (a DOCS_AND_FREQS custom-frequency stream; FeatureField with saturation and log queries; DelimitedTermFrequencyTokenFilter) fail on 7.0.0, 7.4.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main, each with a passing frequency-1 control, and pass on main with the fix sketch shadowed; the finder's JUnit fails on main (3 of 3, -ea and -da), 10.5.2 and 9.12.3 (2 of 2) and a main() variant on 8.11.4; the DOCS_AND_CUSTOM_FREQS JUnit fails on 10.5.0, 10.5.2 and main; the independent reproduction's JUnit fails on main (6 of 7, -ea and -da), 10.5.2 (5 of 6) and 9.12.3 (4 of 5) and its main() variant on 8.11.4; the Monitor batch-size test fails on main (-ea and -da) and 10.5.2. [exec] on main a9779ef3c193 the bug doc's JUnits fail 6 of 7 through gradle, assertions on and off. [read] the releases not executed (7.1-7.3, 8.1-8.8.1, 9.1-9.11, 10.1-10.4): MemoryIndex.java never mentions the attribute at any of the 65 local release tags 7.0.0 to 10.5.2; the local history clone has no tags for 8.8.2 to 8.11.3, which were neither read nor run; Lucene Monitor (from 8.2.0) matches a single document on MemoryIndex only since 8.6.0 (LUCENE-9314): in 8.2.0 to 8.5.2 Monitor.match(Document) called match(new Document[] {doc}) and DocumentBatch.of(Analyzer, Document...) always built the IndexWriter-based MultiDocumentBatch. branch_10_6 (2763db11b0a, 2026-10-24, before the 10.6.0 release of 2026-10-29): storeTerms unchanged, read only. Not checked: x86. Unfixed: no commit in lucene/memory or lucene/monitor adds custom-frequency support, and no open PR changes storeTerms",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-333.html",
   "repro": "repro/LFV-333/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-340",
   "priority": "medium",
   "priority_rank": 238,
   "novelty": "new",
   "withheld": false,
   "area": "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",
   "title": "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",
   "summary": "You add a document whose text field has two values, 'quick the' and 'fox', to a MemoryIndex with an analyzer that removes the stop word 'the', and expect the positions of a one-document IndexWriter index: IndexWriter keeps the hole the removed trailing 'the' leaves (TokenStream.end() reports it as a final position increment), so 'fox' is at position 2 and the phrase \"quick fox\" does not match. MemoryIndex.storeTerms never adds that final increment, puts 'fox' at position 1 and matches the phrase; the reverse also happens (the input of upstream's TestIndexWriter#testStopwordsPosIncHole matches a phrase on IndexWriter but not on MemoryIndex), and values that produce no tokens before the first token skip the position and offset gaps ([the | quick fox] with gap 100: IndexWriter quick at position 101, offsets 4-9; MemoryIndex position 0, offsets 0-5). Lucene Monitor inherits it: a stored phrase query matches the document when it is matched alone (MemoryIndex path) but not when the same document is in a two-document batch (IndexWriter path).",
   "impact_class": "silent wrong results",
   "introduced_commit": "59476c30cf39515cc14c26d70042632551a7138f (trunk) / 4ed3173891d176941a5a89706593f2f0a422b1c3 (branch_4x backport), LUCENE-4515 'Make MemoryIndex more memory efficient' (a JIRA patch with no GitHub PR, migrated as apache/lucene#5581; it also resolved LUCENE-3865 / #4938) [read]: it first let MemoryIndex accept a field more than once, starting the next value at info.lastPosition + positionIncrementGap (the end() increment ignored) and keeping the carry only if earlier values produced tokens. The headline symptom became a divergence with 2a5421ca685b7341bbead24975cd218cbcaf34f7 (trunk) / e005a580e9f856e1cdebc3bf3230768911c7105c (branch_4x), LUCENE-3849 / #4922 'position increments should be implemented by TokenStream.end()', which made IndexWriter add the increment end() reports and did not touch lucene/memory [read]. Later commits kept the behaviour: b4129d434c0 / 15f549a738f (LUCENE-5444, offset carry added under the same numTokens > 0 condition, 4.7.0), cf3eea26406 (LUCENE-7091, today's storeTerms shape), 8ed2b764ed4 (LUCENE-6819, line 996); 5d5b7e14d41 / 633ae90d7d9 (LUCENE-9314, 8.6.0) routed Monitor's single documents to MemoryIndex",
   "introduced_date": "2012-11-02 (LUCENE-4515, multi-value support with this carry logic); headline divergence from 2013-08-20 (LUCENE-3849 changed IndexWriter); Monitor reach from 2020-04-27 (LUCENE-9314)",
   "first_affected_version": "4.1.0 [exec] for the leading-tokenless-value gap (first release that accepts a second value; 4.0.0 rejects it [exec]); the headline (dropped end() position increment) from 4.5.0 [exec]; offsets in today's narrow form from 4.7.0 [exec] (4.1.0-4.6.1 had the broader offset bug LUCENE-5444 fixed); the Monitor single-vs-batch disagreement from 8.6.0 [exec]",
   "affected_versions": "Every release from 4.1.0 to 10.6.0 (the headline from 4.5.0; 10.6.0 by reading), branch_10_6, branch_10x and main ea57360912ed. [exec] the MemoryIndex history harness (main() programs, SHA-1-checked release jars, -ea, seed DEADBEEF) on 4.0.0 (API absent) and 28 affected releases (4.1.0, 4.2.1, 4.3.1, 4.4.0, 4.5.0, 4.5.1, 4.6.0, 4.6.1, 4.7.0, 4.8.1, 4.9.1, 4.10.4, 5.3.2, 5.4.1, 5.5.5, 6.0.0, 6.3.0, 6.6.6, 7.5.0, 7.7.3, 8.0.0, 8.8.2, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.3.2, 10.5.2) plus main, with identical results from 4.7.0 to main; the finder's JUnit fails 3 of 3 on main (-ea and -da), 10.5.2 and 9.12.3 and a main() variant fails on 8.11.4; the independent reproduction's JUnit fails 5 of 8 on main (-ea and -da), 10.5.2 and 9.12.3; a Monitor port gives the same result for a single document and a batch on 8.2.0 and 8.5.2 and differs on 8.6.0 and 8.11.4. [read] releases between executed points (5.0.0-5.2.x and 7.0.0-7.4.0 not executed; only refactors touched the carry code after 4.7.0); branch_10_6, branch_10x and upstream main have the same storeTerms (fetched 2026-10-24; upstream main e1c4184cb98 re-checked 2026-10-26). Not checked: x86. Unfixed",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-340.html",
   "repro": "repro/LFV-340/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-344",
   "priority": "medium",
   "priority_rank": 239,
   "novelty": "known",
   "withheld": false,
   "area": "memory / MemoryIndex lazy per-field read state (sorted terms, points and doc-values preparation, norms)",
   "title": "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",
   "summary": "You add a value to a field of a MemoryIndex that is not frozen, search it, add more values to the same field, and search again; you expect the second search to see everything, like a MemoryIndex built from the same adds, because freeze() is the only documented point after which no data may be added and adding the same field several times is supported. Instead the field keeps the read state that the first read built lazily and nothing ever resets (the sorted term ids, the point min/max and 1D order, the sorted doc values, the cached norm): a term or IntPoint added later is silently not found (for example IntPoint p=2, search, p=1: newExactQuery(p, 1) no longer matches), SORTED_NUMERIC values come back as 2, 1, the score uses the old norm, or the search throws ArrayIndexOutOfBoundsException from the corrupted term dictionary (an AssertionError under -ea for some inputs).",
   "impact_class": "silent wrong results",
   "introduced_commit": "bd0803fd41c68297c54201529c2c14ad50cda48e (branch_6_0; master cf3eea26406, branch_6x 559432fcdcd), LUCENE-7091 'Add doc values support to MemoryIndex' (GitHub mirror issue apache/lucene#8147; a JIRA patch, no PR), by GitHub martijnvg: addField stopped building a new per-field Info on every add and now mutates one Info in place, so the lazily built sortedTerms, the norm cache and the new doc-values prepare flag survive later adds [read]. Sub-symptoms with other origins: an existing term added again after a search is stored twice since LUCENE-4515 (4ed3173891d, 4.1.0, the first release that allowed adding a field more than once) [exec]; stale point min/max since LUCENE-7093 (fe58313de02, 6.0.0); IntPoint set queries miss since LUCENE-7869 (70305309471, 6.6.1); exact and range IntPoint queries miss since LUCENE-9820 (9adf7e27f97, 9.1.0) [exec]",
   "introduced_date": "2016-03-15 (commit date of bd0803fd41c and cf3eea26406; authored 2016-03-09); the narrow re-added-term sub-symptom dates from 2012-11-02 (LUCENE-4515)",
   "first_affected_version": "6.0.0 [exec] (the first release in which the candidate's repro scenarios fail; 5.5.0 and 5.5.5 pass); the narrow sub-symptom 'an existing term added again after a search is stored twice' from 4.1.0 [exec]; the exact IntPoint query miss from 9.1.0 [exec]",
   "affected_versions": "Every release from 6.0.0 to 10.6.0 (10.6.0 by reading) and main ea57360912ed. [exec] a version-portable main() port of the scenarios (fresh-MemoryIndex oracle, two controls that pass everywhere from 4.1.0) fails on 6.0.0, 6.6.0, 6.6.1, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4 and 9.0.0 (terms, norms, SORTED_NUMERIC, SORTED_SET, point min/max; the exact IntPoint query still passes there) and on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (every scenario), with -ea, and with -da on 9.12.3, 10.5.2 and main; the finder's JUnit fails 5 of 5 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) and 4 of 5 on 8.11.4 and 9.0.0 (pre-9.1 import variant; the point test passes); the independent reproduction's JUnit fails 8 of 10 on main (-ea and -da), 10.5.2 and 9.12.3. 4.1.0 to 5.5.5 [exec]: only the re-added-term sub-symptom (term dictionary [b ttf=1, b ttf=1] instead of [b ttf=2]). 4.0.0 not affected: a second addField on the same field throws IllegalArgumentException [exec]. Releases between the executed ones are affected by reading (no fix in the history). Not fixed on upstream main e1c4184cb983, branch_10x or branch_10_6, and no open PR changes the stale-state code [read].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/8447",
    "https://issues.apache.org/jira/browse/LUCENE-7394",
    "https://github.com/apache/lucene/issues/6973",
    "https://issues.apache.org/jira/browse/LUCENE-5911",
    "https://github.com/apache/lucene/issues/8444",
    "https://issues.apache.org/jira/browse/LUCENE-7391"
   ],
   "doc": "",
   "repro": "repro/LFV-344/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1112",
   "priority": "medium",
   "priority_rank": 240,
   "novelty": "known",
   "withheld": false,
   "area": "memory / MemoryIndex doc values (addField and fromDocument: BINARY and SORTED value storage)",
   "title": "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)",
   "summary": "You add new SortedDocValuesField(\"color\", new BytesRef(buf)) with buf holding \"red\" to a MemoryIndex, then re-use buf for \"tan\" after addField has returned, and expect the MemoryIndex to keep reporting \"red\", as IndexWriter does and as MemoryIndex did up to 9.0.0. It reports \"tan\", with no error: since 9.1.0 MemoryIndex stores BINARY and SORTED doc values as BytesRef.clone(), which BytesRef documents as a shallow copy that shares the caller's byte array. SORTED_SET values, indexed terms, points and vectors are still copied into the MemoryIndex's own storage.",
   "impact_class": "silent wrong results",
   "introduced_commit": "9174720b31f59c7efad4cc9a6b63219fa1eb1193 (branch_9x backport, the copy that shipped first, in 9.1.0) and main-line commit 4c578017af84672edc45f4ebf7a411774a85d9bf (merge of PR apache/lucene#647, first released in 10.0.0), both 'LUCENE-10405: binary and Sorted doc values are stored as BytesRef instead of BytesRefHash in memory index (#647)' (issue apache/lucene#11441, author Ignacio Vera, GitHub iverase; approved by romseygeek). It replaced the copy of BINARY and SORTED values into a BytesRefHash on the MemoryIndex's own ByteBlockPool with 'info.binaryProducer.dvBytesValuesSet = ((BytesRef) docValuesValue).clone();', unchanged since [read]",
   "introduced_date": "2022-02-07 (author date 07:33:07 +0100 for both commits; committer times 07:33:07 on main and 07:34:00 on branch_9x)",
   "first_affected_version": "9.1.0 [exec]; from 6.0.0 (LUCENE-7091, which added MemoryIndex doc values) through 9.0.0 the value was copied into a BytesRefHash [read], so this is a regression",
   "affected_versions": "every release from 9.1.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main e1faeba08bde (12.0.0-SNAPSHOT). Executed, all failing 'expected:<[red]> but was:<[tan]>': the repro on main (-ea and -da), 10.6.0 (-ea and -da), 10.5.2, 10.0.0, 9.12.3 and 9.1.0; the hunt unit XRel workload W3 shows the same on 10.4.0; 9.0.0 and 8.11.4 pass [exec]. The other releases by code identity: the clone line at all 33 release tags from 9.1.0 through 10.6.0, the BytesRefHash copy at 9.0.0 [read]. Not new in 10.6 (10.5.2 fails). Not fixed upstream: apache/lucene main (MemoryIndex.java:954), branch_11x, branch_10_6 and branch_9_12 still have the clone, the newest upstream commit on MemoryIndex.java is bfe5c847d3c (#16383, 2026-07-27, already in e1faeba08bde), and no open PR changes the store site [read]. Executed on Linux aarch64 with JDK 25.0.3 only.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/8147",
    "https://issues.apache.org/jira/browse/LUCENE-7091",
    "https://github.com/apache/lucene/issues/11441",
    "https://issues.apache.org/jira/browse/LUCENE-10405",
    "https://github.com/apache/lucene/issues/647",
    "https://github.com/apache/lucene/issues/14716"
   ],
   "doc": "",
   "repro": "repro/LFV-1112/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-342",
   "priority": "medium",
   "priority_rank": 241,
   "novelty": "known",
   "withheld": false,
   "area": "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",
   "title": "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",
   "summary": "You put a document into a MemoryIndex in which a SortedDocValuesField (or a NumericDocValuesField or a StoredField) named title comes before Field(\"title\", \"quick brown fox\") with a type that omits norms, and expect what IndexWriter gives for the same document: no norms for title and the score of a field without norms. Instead MemoryIndex builds the field's FieldInfo from the first instance, whose type reports omitNorms=false, so title gets norms and TermQuery title:fox scores 0.13076457 instead of IndexWriter's 0.1798013; with the text field first, MemoryIndex agrees with IndexWriter. The same happens for a multi-valued StringField with a SortedSetDocValuesField before each value, and in the mirror order (a non-indexed type with omitNorms=true before a text field with norms) MemoryIndex drops the norms instead.",
   "impact_class": "silent wrong results",
   "introduced_commit": "6696eafaae18948c2891ce758c7a2ec09873dab8 (LUCENE-7679 / apache/lucene#8730 'MemoryIndex should take into account omitNorms'; a JIRA patch by GitHub romseygeek with a +1 from martijnvg, no GitHub PR; branch_6x backport cecc44c731b1) [read]. The residue of an incomplete fix, not a regression: before it, MemoryIndex ignored omitNorms in every order; the fix takes omitNorms from the first instance of a name only. Later commits to createFieldInfo only added FieldInfo parameters",
   "introduced_date": "2017-02-09 (committed; authored 2017-02-07)",
   "first_affected_version": "6.5.0 [exec] (first release with the LUCENE-7679 fix; 6.0.0 to 6.4.2 have the broader LUCENE-7679 bug instead, omitNorms ignored in every order, executed on 6.4.2); first on the master line: 7.0.0 [exec]",
   "affected_versions": "Every release from 6.5.0 to 10.5.2 and main ea57360912ed. [exec] the version-portable main() history probe (text-first control, SortedDocValuesField first, StoredField first; IndexWriter vs MemoryIndex norms and BM25 score of title:fox) is order-dependent, with the control agreeing, on 6.5.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da); on 7.0.0 and 7.7.3 the norms state is wrong in every run but the score is equal at 3 and 60 tokens and differs only at 69 tokens (0.6015171 vs 0.6018415), because 7.x BM25 handles a missing norm differently; from 8.0.0 the score differs at any length of 2 tokens or more; 6.4.2 differs in every order (LUCENE-7679 itself, not this bug). The finder's JUnit fails on 9.1.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) and needs the 9.1+ test framework; the independent reproduction's JUnit fails on main, 10.5.2 (-ea and -da) and 9.12.3; the intended-behaviour check's on main and 10.5.2. [read] the releases not executed: by tag membership (8.8.2 to 8.11.3 inferred, their tags are not in the history clone) and the unchanged getInfo/createFieldInfo/getNormValues lines. Unfixed: no change to lucene/memory between ea57360912ed and upstream main e1c4184cb983 (2026-10-26) and no open PR mentions MemoryIndex. Not checked: branch_10_6 (10.6.0, released 2026-10-29), x86",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/8730",
    "https://issues.apache.org/jira/browse/LUCENE-7679",
    "https://github.com/apache/lucene/issues/4219",
    "https://github.com/apache/lucene/issues/11999",
    "https://github.com/apache/lucene/issues/12109",
    "https://github.com/apache/lucene/issues/8147"
   ],
   "doc": "",
   "repro": "repro/LFV-342/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-175",
   "priority": "medium",
   "priority_rank": 242,
   "novelty": "new",
   "withheld": false,
   "area": "index / stored fields (StoredFieldDataInput: DataInput-backed StoredField values, #14213)",
   "title": "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",
   "summary": "You add new StoredField(name, new StoredFieldDataInput(new ByteArrayDataInput(bytes, offset, len))) and expect the stored value to be exactly those len bytes, because the record's length is documented as 'the length of the data input'. The convenience constructor copies ByteArrayDataInput.length(), which is the end position offset + len, so for an 8-byte slice at offset 4 of a 16-byte array the document stores 12 bytes, the slice plus the next 4, with no error. If fewer bytes than the offset follow the slice, the stored fields writer reads past the array, addDocument throws ArrayIndexOutOfBoundsException and IndexWriter closes itself.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f12e44b6515a25933dc5e9316df72d8b093eae12 (main) and its branch_10x backport 2dedd1da89acec3d7440348a0d4fd8c1d75225d7, PR #14213 'Support DataInput as source for StoredField' (author Tim-Brooks, merged by iverase, milestone 10.2.0; CHANGES 10.2.0 'GITHUB#14213: Allowing indexing stored-only StoredField directly from DataInput'), which added the StoredFieldDataInput record together with the line 'this(byteArrayDataInput, byteArrayDataInput.length());' [read]. ByteArrayDataInput.length() has returned limit = offset + len since LUCENE-3030 (b7846ffaa1f) and LUCENE-3224 (6b41b73894d), 2011, by design [read]",
   "introduced_date": "2025-02-19 (merged 06:44:41 UTC; author date 2025-02-18 23:44:41 -07:00)",
   "first_affected_version": "10.2.0 [exec]; the API does not exist before it (10.1.0, 10.0.0 and 9.12.3 do not compile the repro) [exec]",
   "affected_versions": "10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main ea57360912ed. [exec] the finder's JUnit fails 3 of 3 on every one of these releases (follow-up history runs, SHA-1-checked release jars) and on main with -ea and -da; the independent reproduction's JUnit fails 3 of 5 on main (-ea, -da), 10.5.2 (-ea, -da) and 10.2.0; the security probe fails 3 of 4 on main (-ea, -da), 10.5.2 and 10.2.0. Not affected: 10.1.0 and older, including all 9.x (9.12.3 executed), because StoredFieldDataInput does not exist there [exec]. [read] branch_10_6 has the same constructor line, so the released 10.6.0 (4ae946e5a9b) has it too; 10.6.0 was not executed. Only the default stored fields format was executed; the default StoredFieldsWriter.writeField(FieldInfo, StoredFieldDataInput), which other codecs inherit, reads length() bytes the same way [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-175.html",
   "repro": "repro/LFV-175/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-766",
   "priority": "medium",
   "priority_rank": 243,
   "novelty": "new",
   "withheld": false,
   "area": "join / JoinUtil query-time join (single-valued term and numeric collectors)",
   "title": "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)",
   "summary": "You join orders to customers with JoinUtil.createJoinQuery(\"customer\", false, \"id\", fromQuery, searcher, scoreMode), or the numeric overload with Integer.class, where fromQuery matches two orders and only one of them has a customer key, and expect only that order's customer back, because the javadoc returns the to-documents that 'have the same terms' as the matching from-documents. Instead the order without a key is collected as if its key were the empty term (term join) or 0 (numeric join), so the customer whose id is \"\" or 0 is returned too, in every ScoreMode, and a real customer 0 also gets the key-less order's score (Max 5.0 instead of 1.0). The same call with multipleValuesPerDocument=true on the same single-valued field, and the global-ordinals join, return the correct answer.",
   "impact_class": "silent wrong results",
   "introduced_commit": "Term join: 7cdb8028c1067b24b0141fdbb8600053ac6e84c9 (LUCENE-3602 'Added query time joining', by martijnvg, trunk svn r1232223; issue apache/lucene#4676, no PR; first released in 4.0.0): its single-valued collector added FieldCache.DocTerms.getTerm(doc), which by the contract of the time returned an empty BytesRef for a document without the field, while the multi-valued collector of the same commit skipped such documents; the scoring collector TermsWithScoreCollector.SV (LUCENE-4043, 36acada7629 / 3b51274435e, 2012-05-29, 4.0.0) copied the default. Numeric join: LUCENE-5868 (issue #6930; branch_5x 3c7f3f4c435, trunk bc51c86b4bbf; committed by mkhludnev, CHANGES credits Alexey Zelin; first released in 5.5.0), where a missing numeric doc value read as 0; kept by the point-based rewrite LUCENE-7095 (5733f05c70d, 6.0.0). The iterator migrations LUCENE-7407 (f7aa200d406, 7.0.0), LUCENE-8152 (aa157f18335 / 6ae6ce2f42b, 7.3.0) and LUCENE-9796 (f3a284ad830, 9.0.0) wrote the defaults out as the explicit else-branches seen on main; they kept the behaviour, they did not introduce it [read]. Not a regression: the term join has it since 4.0.0 (on 3.6.x, the first release with JoinUtil, the same input throws NullPointerException instead) and the numeric join since its first release, 5.5.0.",
   "introduced_date": "2012-01-16 (term join, LUCENE-3602); 2015-12-07 (numeric join, LUCENE-5868)",
   "first_affected_version": "4.0.0 [exec] for the term join (the 4.0.0-alpha and -beta pre-releases contain the introducing commit by git ancestry [read]); 5.5.0 [exec] for the numeric join (5.4.1 has no numeric overload [exec]). Before that: 3.5.0 has no JoinUtil [exec]; on 3.6.0-3.6.2 (the 3.x port) the same input makes createJoinQuery throw NullPointerException instead [exec], the same root mistake with a different symptom, not part of this row",
   "affected_versions": "[exec] term join: 4.0.0, 4.2.0, 4.5.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.0.0, 7.2.1, 7.3.0, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main a9779ef3c193 (-ea and -da) with version-portable main() ports, each also running multipleValuesPerDocument=true as a control, which was correct on every version; numeric join: 5.5.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.2.1, 7.3.0, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main (-ea and -da); the candidate JUnit fails 3 of 3 on 9.5.0, 9.12.3, 10.5.2 (-ea and -da) and main (-ea and -da), the independent reproduction's JUnit 3 of 3 on main (-ea and -da), 10.5.2 and 9.12.3. [read] every other release from 4.0.0 (term) and 5.5.0 (numeric) to 10.5.2 has the same collect() bodies; so do branch_10_6, released as 10.6.0 on 2026-10-29, and the unreleased branch_10x (and 'long value = 0' on branch_10_5). Not fixed upstream: main f7bcc0abd816 (2026-10-27) has the same lines [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-766.html",
   "repro": "repro/LFV-766/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1111",
   "priority": "medium",
   "priority_rank": 244,
   "novelty": "new",
   "withheld": false,
   "area": "join / JoinUtil numeric (point-based) query-time join: multi-valued Float/Double decode of core DoubleField/FloatField doc values",
   "title": "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",
   "summary": "You index one from document with DoubleField(\"from\", -5.0) and one to document with DoubleField(\"to\", -5.0), and count JoinUtil.createJoinQuery(\"from\", true, \"to\", Double.class, new MatchAllDocsQuery(), fromSearcher, ScoreMode.None) on the to index; you expect 1, because the javadoc lists floats and doubles and allows SORTED_NUMERIC from fields, which is what DoubleField writes. You get 0 with no error: DoubleField stores NumericUtils.doubleToSortableLong(-5.0), but JoinUtil's multi-valued Float/Double path decodes the stored long as raw IEEE bits (Double.longBitsToDouble, Float.intBitsToFloat), so the join looks up -0.8749999999999999 instead of -5.0. Positive values are unaffected because their sortable and raw bits are the same, and FloatField fails the same way.",
   "impact_class": "silent wrong results",
   "introduced_commit": "827f762d137643c6f37fee22484b50ad7273bace (branch_9x copy that shipped, first released in 9.5.0) and main-line 57201aa967828a678a6c440b6a2e36fd8846ca37 (same author date, first in 10.0.0), apache/lucene#11997 'Add IntField, LongField, FloatField and DoubleField' (by fcofdez, merged by jpountz, approved by rmuir, milestone 9.5.0, closes #11199 / LUCENE-10162): it added core DoubleField/FloatField writing SORTED_NUMERIC doc values in the NumericUtils sortable encoding and did not touch JoinUtil. The raw-bit decode it collides with is older: 2babaf8c3d1710280ef53da3d7ba286615e7293e (LUCENE-7095, migrated as #8151, by martijnvg, +1 from mikemccand), shipped in 6.0.0 via the branch_6_0 backport 5733f05c70d. [exec]. An interaction bug, not a regression of the JoinUtil code",
   "introduced_date": "2022-12-20 (author date of 57201aa9678 and 827f762d137; #11997 merged 2022-12-20T17:19:46Z); decode site 2016-03-25 (2babaf8c3d1)",
   "first_affected_version": "9.5.0 [exec]",
   "affected_versions": "every release from 9.5.0 on: 9.5.0, 9.6.0, 9.7.0, 9.8.0, 9.9.0-9.9.2, 9.10.0, 9.11.0, 9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2, 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main e1faeba08bde (12.0.0-SNAPSHOT). Executed, all failing 'expected:<1> but was:<0>': main -ea and -da, 10.6.0 -ea and -da, 10.5.2, 10.0.0, 9.12.3, 9.6.0 and 9.5.0 [exec]; the other releases by code identity (all 34 tags 9.0.0-10.6.0 read: the raw decode is in JoinUtil at every tag, DoubleField/FloatField with sortable SORTED_NUMERIC at every tag from 9.5.0) [read]; upstream main head 5adff78bb16 (2026-11-02), branch_11x and branch_10_6 still have both raw decodes [read]. Not applicable before 9.5.0 (no DoubleField/FloatField; 9.4.2 compile error [exec]). Background, not a claimed range: since 6.0.0 the same mis-decode hits a from field hand-written with the SortedNumericDocValuesField javadoc's NumericUtils recipe (6.0.0 and 9.4.2 [exec], +5.0 control passes). Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1111.html",
   "repro": "repro/LFV-1111/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1106",
   "priority": "medium",
   "priority_rank": 245,
   "novelty": "known",
   "withheld": false,
   "area": "join / JoinUtil term join (TermsIncludingScoreQuery, TermsQuery)",
   "title": "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)",
   "summary": "You build one join query with JoinUtil.createJoinQuery(..., ScoreMode.Max) and, as the IndexSearcher thread-safety and Query-reuse javadoc allow, run searcher.search(join, n) in one thread while another thread runs searcher.count(join); every scoring search should return all 20,000 joined documents. Instead each count() builds a TermsQuery whose constructor sorts the join's BytesRefHash again in place, rewriting the ids array that the scoring search iterates as its ords, so the scoring search silently returns fewer documents (18,120 to 19,023 of 20,000 in the recorded runs).",
   "impact_class": "silent wrong results",
   "introduced_commit": "the repeated sort is old (TermsQuery sorts the shared hash in its constructor, TermsQuery.java:68; a second sequential sort was made safe by #13014); the silent missing hits start with #15772 (bd9d3bc230d, author date 2026-02-28, 'improve BytesRefHash.sort performance by rearranging ids'), whose compact() resets ids[i] = i before every sort [read]",
   "introduced_date": "2026-02-28 (#15772) [read]",
   "first_affected_version": "10.5.0 [exec]",
   "affected_versions": "10.5.0, 10.5.2 and 10.6.0 (released) [exec]; main 645d4fe14a20 and e1faeba08bde with -ea and -da [exec]; 10.4.0 and 9.12.3 pass this repro [exec]; before 10.5.0 an earlier, different test with several concurrent count() calls saw ArrayIndexOutOfBoundsException from the sort and wrong counts [exec]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/13018",
    "https://github.com/apache/lucene/pull/13019",
    "https://github.com/apache/lucene/issues/13019",
    "https://github.com/apache/lucene/issues/13014",
    "https://github.com/apache/lucene/issues/16847",
    "https://github.com/apache/lucene/issues/16801"
   ],
   "doc": "",
   "repro": "repro/LFV-1106/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-410",
   "priority": "medium",
   "priority_rank": 246,
   "novelty": "known",
   "withheld": false,
   "area": "join / JoinUtil numeric score join (PointInSetIncludingScoreQuery createWeight boost)",
   "title": "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",
   "summary": "You build a numeric query-time join with JoinUtil.createJoinQuery(\"fromId\", false, \"toId\", Integer.class, fromQuery, searcher, ScoreMode.Max) (or Min, Avg, Total), wrap it in BoostQuery(join, 10), and expect each to-document's score to be 10 times its join score, as BoostQuery documents ('the produced scores will be boosted by boost'), as the string-field join over the same documents does, and as GITHUB#12388 ('JoinUtil queries were ignoring boosts', 9.8.0) made every other JoinUtil join do. Instead the PointInSetIncludingScoreQuery that JoinUtil returns never reads the boost passed to createWeight and its scorer returns the raw join score, so BoostQuery(join, 10) scores 0.13076457 instead of 1.3076458, and BooleanQuery[SHOULD join, SHOULD join], which Lucene rewrites to one clause with boost 2, scores 1x instead of 2x. Only scores and ranking are wrong: the matching documents are correct.",
   "impact_class": "silent wrong results",
   "introduced_commit": "2babaf8c3d1710280ef53da3d7ba286615e7293e (LUCENE-7095 'Add point values support to the numeric field query time join', by martijnvg; JIRA patch era, migrated as apache/lucene#8151, no PR; branch_6_0 backport 5733f05c70d, the one released in 6.0.0, and branch_6x backport e26a4431942) created PointInSetIncludingScoreQuery, whose scorer has returned scores[docID()] ever since; in the 6.x API a parent's boost reached a weight through Weight.normalize(norm, boost), which this class forwarded only to the from query's weight, which plays no part in the precomputed to-side scores [read]. Later commits: 5def78ba101 (LUCENE-7368 'Remove queryNorm', jpountz, 2016-07-07, 7.0.0) made the boost a createWeight argument that the class never reads (no behaviour change: 6.6.6 and 7.0.0 identical [exec]); LUCENE-7925 (325263a9398 on branch_7x, ab793e7ab56 on master, jpountz, 2017-08-21, 7.1.0) folds duplicate SHOULD/MUST clauses into one boosted clause, which gives the boost-free trigger (7.0.0 2x, 7.1.0 1x [exec]); edd799824f9 (GITHUB#12388 'Enable boosts on JoinUtil queries', romseygeek, branch_9x 3ff2c9be154, 2023-06-26, 9.8.0) fixed TermsIncludingScoreQuery and the global-ordinal joins and did not touch this class (incomplete fix). Not a regression: the omission is original to the class",
   "introduced_date": "2016-03-25 (2babaf8c3d1, the omission); 2017-08-21 (LUCENE-7925, the boost-free BooleanQuery trigger); 2023-06-26 (GITHUB#12388, from which the numeric join is the only scoring JoinUtil join that drops the boost)",
   "first_affected_version": "6.0.0 [exec] (the first release with the point-based numeric JoinUtil overload; 5.5.5 has no such API [exec]). From 6.0.0 to 9.7.0 every scoring JoinUtil join ignored the boost [exec]; the numeric-only inconsistency, and the project's statement that ignoring boosts is a bug (CHANGES 9.8.0 Bug Fixes, GITHUB#12388), start in 9.8.0 [exec]. The boost-free duplicate-clause trigger starts in 7.1.0 [exec]",
   "affected_versions": "every release from 6.0.0 to 10.5.2 and main ea57360912ed; not fixed. [exec]: 6.0.0, 6.6.6, 7.0.0, 7.1.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.7.0, 9.8.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) all fail (numeric BoostQuery(join, 10) honoured 0 of 8 scoring cases on every one; numeric 'join OR join' 2x 8 of 8 on 6.0.0-7.0.0 and 0 of 8 from 7.1.0; the string join honours BoostQuery 0 of 8 up to 9.7.0 and 8 of 8 from 9.8.0); main with the fix shadowed passes 8 of 8. [exec]: the finder's fails on main (-ea, -da), 10.5.2, 9.12.3 and 9.8.0 (on 9.7.0 its string-join control fails first); the independent reproduction's fails 2 of 3 on main (-ea, -da), 10.5.2 and 9.12.3 (1 of 3 on 9.7.0, where the string join also ignores the boost); the intended-behaviour check's probe shows the same on main and 9.12.3; the cross-model review-stage test fails on main (-ea, -da). [read]: releases between the executed ones (blame shows score() unchanged since 2babaf8c3d1, and createWeight never reads boost from 7.0.0 on); upstream main cf398bfb142c (2026-10-26) still returns scores[docID()], branch_10x and branch_10_5 unchanged, no open PR touches the file. Every numeric type (Integer, Long, Float, Double), every scoring ScoreMode, single- and multi-valued [exec]. Old releases were run on JDK 25, newer than they supported; all runs on aarch64 Linux",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/12388",
    "https://github.com/apache/lucene/issues/14228",
    "https://github.com/apache/lucene/issues/16805",
    "https://github.com/apache/lucene/issues/13747",
    "https://github.com/apache/lucene/issues/6003",
    "https://issues.apache.org/jira/browse/LUCENE-4939"
   ],
   "doc": "",
   "repro": "repro/LFV-410/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-470",
   "priority": "medium",
   "priority_rank": 247,
   "novelty": "known",
   "withheld": false,
   "area": "queries / payloads (PayloadScoreQuery scoring with includeSpanScore=false)",
   "title": "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",
   "summary": "Build a PayloadScoreQuery with includeSpanScore=false and wrap it in BoostQuery(q, 3), or put it in a BooleanQuery as a clause with boost 10. You expect its scores to be multiplied by the boost, as BoostQuery promises for every query ('the produced scores will be boosted by boost'). Instead the score stays the bare payload value (4.0 instead of 12.0; 1.0 instead of 10.0), so the boosted payload hit ranks below a weaker clause; only a boost of 0 still works, because BoostQuery rewrites it into a ConstantScoreQuery.",
   "impact_class": "silent wrong results",
   "introduced_commit": "0b305f9279a5e7cdfa79a7b94dc50ba4c7e28866 (trunk, svn r1709386; branch_5x backport f04f42207ed885d757d105466ec07baefe2ce7c3, r1709391, the commit that shipped in 5.4.0), LUCENE-6844 'Add includeSpanScore option to PayloadScoreQuery' (now apache/lucene#7902; committed by romseygeek from JIRA, no pull request): it added the includeSpanScore argument with scoreCurrentDoc returning getPayloadScore() alone and explain returning the bare payload explanation; in 5.4 the boost reached the weight only through normalize(), which PayloadSpanWeight forwarded to the inner span weight, so it lived only in the dropped span score; blame on main still gives 0b305f9279a5 for PayloadScoreQuery.java:185 and :293 [read]. The flag and its semantics were ported from PayloadTermQuery, where LUCENE-1790 (e079d1cec34f, 2009-08-07, now #2865) added includeSpanScore with the same boost loss, first released in 2.9.0 [exec]",
   "introduced_date": "2015-10-19 (LUCENE-6844); the predecessor PayloadTermQuery behaviour dates from 2009-08-07 (LUCENE-1790)",
   "first_affected_version": "5.4.0 [exec] (first release whose PayloadScoreQuery has the includeSpanScore argument; 5.3.0-5.3.2 have only the 2-argument constructor, which always multiplies by the span score and keeps the boost [exec]); the predecessor PayloadTermQuery(term, function, false) drops the boost from 2.9.0 [exec]",
   "affected_versions": "every release from 5.4.0 to 10.5.2 and main ea57360912ed [exec]; all 91 release tags 5.4.0..10.5.2 in the history clone contain the payload-only return and no boost in getPayloadScore [read]; predecessor PayloadTermQuery(false) fails on 2.9.0, 2.9.4, 5.3.1, 5.3.2 and 5.4.0 [exec]; not fixed on upstream main 49483e82b357 [read]; aarch64 with JDK 25 only",
   "security": "none",
   "upstream_links": [
    "https://lists.apache.org/thread/ogrncgvq8jdchmvxvs0pr7kt6s5vlc2w",
    "https://github.com/apache/lucene/issues/9191",
    "https://issues.apache.org/jira/browse/LUCENE-8143",
    "https://github.com/apache/lucene/issues/7902",
    "https://issues.apache.org/jira/browse/LUCENE-6844",
    "https://github.com/apache/lucene/issues/2865"
   ],
   "doc": "",
   "repro": "repro/LFV-470/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-218",
   "priority": "medium",
   "priority_rank": 248,
   "novelty": "known",
   "withheld": false,
   "area": "join / block join (ParentsChildrenBlockJoinQuery#rewrite, custom scoreCombiner)",
   "title": "ParentsChildrenBlockJoinQuery.rewrite() drops a custom scoreCombiner, so hits are silently scored parent + child whenever the parent or child query rewrites",
   "summary": "You build a ParentsChildrenBlockJoinQuery with a custom scoreCombiner, for example (p, c) -> p * c, and expect every returned child hit to be scored with it, as the constructor documents ('Function to combine parent and child scores'). That is what happens when neither sub-query needs a rewrite, but when the parent or child query rewrites (a one-clause BooleanQuery, a PrefixQuery, BoostQuery(q, 1f), ...), rewrite() rebuilds the join query with the 4-argument constructor, which installs Float::sum, so the hit silently scores parent + child (5 instead of 6 for parent score 2 and child score 3). The same documents match; only their scores, their order and explain() change.",
   "impact_class": "silent wrong results",
   "introduced_commit": "1584c05b27ac31fbccb0ab328bf9f8eb6a7de414 (main, squash merge of PR #14728 '[BlockJoin] Add ParentsChildrenBlockJoinQuery', issue #14565, by Jinny-Wang, merged by msfroh) and its branch_10x backport 61b32ff6d3772906b12b9e7f855b8607e9261371; the class, the 5-argument constructor with scoreCombiner and the rewrite() that calls the 4-argument constructor landed together, and the omission is already in the PR's first commit 5132163203f0 [read]",
   "introduced_date": "2025-06-13 (main squash merge; PR first commit 2025-06-05); branch_10x backport committed 2025-09-04",
   "first_affected_version": "10.4.0 [exec] (the first release with the class; 10.3.2 and 9.12.3 do not have it and the repro does not compile there [exec])",
   "affected_versions": "10.4.0, 10.5.0, 10.5.1, 10.5.2 (the last release before 10.6.0), 10.6.0 (by reading, see the branch_10_6 check below) and main ea57360912ed [exec]; rewrite() is unchanged since the class was added (the only other commit on the file on main, bc601411a316 / #16519, changes a cost() signature; branch_10x 8f2f9f3f71e8 changes a setTopLevelScoringClause() signature) [read]; not fixed upstream: main, branch_10x, branch_10_4, branch_10_5 and branch_10_6 still call the 4-argument constructor in rewrite() [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/14728",
    "https://github.com/apache/lucene/issues/14565",
    "https://github.com/apache/lucene/issues/14975",
    "https://github.com/apache/lucene/issues/15041"
   ],
   "doc": "",
   "repro": "repro/LFV-218/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-279",
   "priority": "medium",
   "priority_rank": 249,
   "novelty": "new",
   "withheld": false,
   "area": "queries / span queries (SpanNotQuery: the exclusion filter in SpanNotWeight#getSpans)",
   "title": "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",
   "summary": "You index the text 'b a a c' and run new SpanNotQuery(a, b, 0, -1), whose javadoc says it keeps the 'a' spans that do not overlap a 'b' and that a negative post only allows some overlap; since 'b' at position 0 overlaps neither 'a', you expect both spans [1,2) and [2,3), exactly as with post = 0. Instead you get only [1,2): once the first 'a' has used up the document's exclude spans, the exclude iterator sits at NO_MORE_POSITIONS (Integer.MAX_VALUE) and SpanNotQuery.java:210 computes Integer.MAX_VALUE - post, which wraps to a negative int for any post < 0, so every later 'a' in the document is rejected. Nested as spanNear([spanNot(a, b, 0, -1), c], 0, true), the document no longer matches at all (count 0 instead of 1).",
   "impact_class": "silent wrong results",
   "introduced_commit": "726ee05240a65badf6c3499dd1e29daf490a3e48 (master) and its branch_7x backport 6b328dcd4f90f4b61961b1d3a16629b4ae0c3ece, 'LUCENE-8034: use subtraction instead of addition to sidestep int overflow in SpanNotQuery' (issue migrated as apache/lucene#9082; a patch attached to the JIRA issue by JIRA user hshankar, committed by mikemccand; no GitHub PR) [read]. It replaced 'candidate.endPosition() + post <= excludeSpans.startPosition()', which is correct for any post <= 0, with 'excludeSpans.startPosition() - post >= candidate.endPosition()', to avoid overflow for a huge positive post. Precondition, not the introducing commit: LUCENE-7431 (750da7c5f7af on master, 55ed23168f6 on branch_6x, 2016-11-08, first released in 6.4.0 and 7.0.0) removed the clamping of negative pre/post to 0 and documented negative values as allowed overlap, which made the trigger legal. A regression since 7.2.0",
   "introduced_date": "2017-11-22",
   "first_affected_version": "7.2.0 [exec] (7.1.0, 7.0.0, 6.6.6 and 6.4.0 pass [exec]; the 6.x line never received LUCENE-8034; before LUCENE-7431 the constructor clamped negative pre/post to 0, so the trigger did not exist: 6.3.0 passes vacuously [exec])",
   "affected_versions": "every release from 7.2.0 through 10.6.0 (7.2.0, 7.2.1, 7.3.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2, and 10.6.0 by reading), main ea57360912ed, the unreleased branch_10x, and branch_10_6 (head 2763db11b0a; 10.6.0 was released from this branch on 2026-10-29) [read]; not fixed upstream. [exec] the finder's JUnit fails on 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da on main); a version-neutral main() port with the same document and queries fails on 7.2.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main and passes on 6.4.0, 6.6.6, 7.0.0 and 7.1.0 (6.3.0 passes vacuously: negative post clamped); the independent reproduction's own JUnit fails on main (-ea, -da), 10.5.2 and 9.12.3, and its pre-9.0 variant fails on 7.2.0 and 8.11.4 and passes on 7.1.0. [read] a scan of every release tag 4.0.0-10.5.2 in the history clone finds the subtraction form in every tag from 7.2.0 to 10.5.2 (8.9.0-8.11.3 are not tagged there; 8.11.4 was executed). History runs used JDK 25, seed DEADBEEF, -ea",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-279.html",
   "repro": "repro/LFV-279/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-409",
   "priority": "medium",
   "priority_rank": 250,
   "novelty": "new",
   "withheld": false,
   "area": "queries / function queries (the ValueSource.fromDoubleValuesSource bridge: its FunctionValues inherits the float default FunctionValues.getRangeScorer that FunctionRangeQuery calls)",
   "title": "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",
   "summary": "You index DoubleDocValuesField(\"d\") values 0.9999999999999999, 1.0 and 1.0000000000000002 and search new FunctionRangeQuery(ValueSource.fromDoubleValuesSource(DoubleValuesSource.fromDoubleField(\"d\")), 1.0, 1.0, true, true), expecting only the document whose value is 1.0, as you get with new DoubleFieldSource(\"d\") or with FunctionMatchQuery over the same DoubleValuesSource. Instead all three match, because the bridged FunctionValues keeps the exact double in doubleVal but does not override getRangeScorer, so it inherits the FunctionValues default that parses both bounds with Float.parseFloat and compares the value cast to float. Likewise {1.0 TO *] misses 1.0000000000000002, [* TO 1e300] matches 1e301, [16777217 TO 16777217] on a long field also matches 16777216, and [* TO 1700000000000] over epoch milliseconds also matches 1700000060000, all without an error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "2f2e00ffe235ba590f43bf07dabd4201e6da53c6 (LUCENE-7737 'Remove spatial-extras dependency on queries module', a JIRA patch by romseygeek with reviewers dsmiley and jpountz, migrated as apache/lucene#8788; no pull request) [read]. Present in the code as first written, not a regression, so there is nothing earlier to bisect",
   "introduced_date": "2017-06-27 (committed to master; authored 2017-06-13)",
   "first_affected_version": "7.0.0 (tagged 2017-09-18) [exec]; 6.6.0 (the last release before the commit) and 6.6.6 (the last 6.x release) lack the API [exec]. the hunt's record executed back to 8.0.0 and put the origin at 7.0 by reading; the history stage executed 7.0.0",
   "affected_versions": "Every release from 7.0.0 to 10.5.2 and main ea57360912ed; not fixed upstream (the newest upstream change to ValueSource.java is ba277acb0f3, #15406, which does not touch range scoring; no open PR touches the fix sites; read 2026-10-26). [exec] The history probe FromDvsRangeHistoryProbe (public API, main(), bridged vs typed vs exact reference) fails on 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.3.2, 10.4.0, 10.5.2 and main with identical output and passes on main with the fix; the finder repro fails on 9.12.3, 10.5.2 and main (-ea and -da); the independent reproduction's test fails on 9.12.3, 10.5.2 (-ea and -da) and main (-ea and -da); the intended-behaviour check's cross-check fails on 10.5.2 and main; an expressions-module source fails on 7.0.0, 10.5.2 and main. [read] 7.0.0-8.8.1 and 9.0.0-10.5.2 by git tag --contains plus the same code shape at every tag; 8.8.2 and 8.9.0-8.11.3 (released from the separate 8.x branch, not tagged in the history clone) inferred between 8.8.1 and the executed 8.11.4. Trigger narrowed in 10.4.0 by #15406: fromDoubleValuesSource(vs.asDoubleValuesSource()) returns vs, so the typed-ValueSource round trip is exact on 10.4.0 and later [exec]; sources that did not start as a ValueSource stay affected [exec]. Old releases ran on JDK 25 with SHA-1-verified release jars",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-409.html",
   "repro": "repro/LFV-409/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-770",
   "priority": "medium",
   "priority_rank": 251,
   "novelty": "new",
   "withheld": false,
   "area": "core / search value sources (DoubleValuesSource, LongValuesSource adapters)",
   "title": "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",
   "summary": "You turn a double source into a long source with DoubleValuesSource#toSortableLongDoubleValuesSource(), documented as 'Convert to LongValuesSource by calling NumericUtils#doubleToSortableLong', and, as the LongValuesSource javadoc tells clients to, call rewrite(IndexSearcher) before getValues, or you sort on its getSortField(), which IndexSearcher rewrites for you. You expect the sortable-long encoding, which keeps the order of the doubles; instead rewrite() returns the plain toLongValuesSource() adapter (its toString changes from sortableLong(...) to long(...)), so 0.75, 0.25 and -0.5 all become 0, 2.5 becomes 2 and NaN becomes 0, and a sort over the values {0.75, 0.25, -0.5, 2.5} comes back in docID order with keys 0, 0, 0, 2. The source is correct when it is not rewritten, and the one-line fix is to return inner.rewrite(searcher).toSortableLongDoubleValuesSource().",
   "impact_class": "silent wrong results",
   "introduced_commit": "304d4e7855de (main, 'Sandbox: Compute facets while collecting (#13568)', PR by epotyom, merged by gsmiller; backported to branch_9x as f68e74034a7e the same day, which is the copy in 9.12.0); born buggy, not a regression: SortableLongDoubleValuesSource.rewrite is a verbatim copy of LongDoubleValuesSource.rewrite (from LUCENE-7736, 2a4dd499bbd, 2017, where it is correct) that kept the target adapter toLongValuesSource() [read]",
   "introduced_date": "2024-08-12 (merged to main as 304d4e7855de and backported to branch_9x as f68e74034a7e the same day)",
   "first_affected_version": "9.12.0 [exec] (9.10.0, 9.11.0 and 9.11.1 have no toSortableLongDoubleValuesSource(): compile error [exec]); 10.0.0 is the first affected 10.x release [exec]",
   "affected_versions": "every release from 9.12.0 to 10.5.2, 10.6.0 (by reading) and main a9779ef3c193. [exec] the finder's JUnit (seed 5EED257) fails 2 of 3 with the same two messages, the no-rewrite control passing, on all 16 releases 9.12.0, 9.12.1, 9.12.2, 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1 and 10.5.2 and on main with -ea, and with -da on 9.12.0, 9.12.3, 10.0.0, 10.5.2 and main; the independent reproduction's JUnit fails 3 of 4 on 9.12.0, 9.12.3, 10.5.2 and main; the intended-behaviour check's fails 4 of 5 on 10.5.2 and main; all runs on JDK 25, also for releases that predate it, Linux aarch64 only. [read] the class body is byte-identical in all 16 releases, in main a9779ef3c193 and in upstream main, branch_10x, branch_10_6 and branch_10_5. Not fixed upstream: main f7bcc0abd816, branch_10x, branch_10_6, branch_10_5 and branch_9_12 still return inner.rewrite(searcher).toLongValuesSource() (follow-up prior-report record, read 2026-10-27); branch_10_6 was not executed.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-770.html",
   "repro": "repro/LFV-770/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-641",
   "priority": "medium",
   "priority_rank": 252,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / hunspell (Stemmer affix stripping: Hunspell.spell, getRoots, analyzeSimpleWord, Stemmer.stem, HunspellStemFilter; WordFormGenerator.getAllWordForms)",
   "title": "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",
   "summary": "You load a Hunspell dictionary with a twofold suffix, where the first suffix's continuation class allows a second suffix (for example 'SFX S Y 1 / SFX S 0 st/E .', 'SFX E N 2 / SFX E 0 en . / SFX E 0 e .' and the entry raich/SE), and spell-check or stem raichsten. You expect it to be accepted and stemmed to raich: hunspell(5) defines the cross-product field only as the 'permission to combine prefixes and suffixes', no prefix is involved, and C Hunspell accepts the word with N as with Y. Instead Lucene rejects raichsten and raichste, returns no stems and leaves them out of getAllWordForms(\"raich\"), because Stemmer.applyAffix (Stemmer.java:621), Stemmer.isAffixCompatible (:564) and WordFormGenerator.expand (:251) follow a suffix+suffix chain only when the suffix classes are cross product Y; the real Luxembourgish dictionary shows the same for räichsten, räichste, räichstem and räichster.",
   "impact_class": "silent wrong results",
   "introduced_commit": "e3172b9239cda3c53769a9e1dd82ea122178b93b (svn r1167467, LUCENE-3414 'Added Hunspell for Lucene', migrated as apache/lucene#4487; svn era, no PR), 2011-09-10: the first Lucene Hunspell code, HunspellStemmer.applyAffix, recursed to a second affix only 'if (affix.isCrossProduct() && recursionDepth < RECURSION_CAP)'; it shipped through the branch_3x backport 1e084f1d08e (r1167505, same day) [read]. That gate is today's Stemmer.java:621. Contributing commits: 56babb83687 (branch_4x 040cf121458; LUCENE-5483 'hunspell inaccuracies', #6546; 2014-03-02; first released in 4.8.0) added the cross-product requirement on the inner suffix that is today's isAffixCompatible condition (Stemmer.java:564-570), so N on either class breaks the chain [exec]; d537013e708 (LUCENE-10626, PR #975, issue #11662; 2022-07-05; branch_9x 3b763af12f5; first released in 9.5.0) copied the gate into WordFormGenerator.expand (WordFormGenerator.java:251) [read]. Later refactors kept the gate unchanged (LUCENE-4542, LUCENE-5468, LUCENE-9671, LUCENE-9685, LUCENE-9748). Not a regression. Whether the external project that LUCENE-3414 ported already had the gate was not checked.",
   "introduced_date": "2011-09-10 (LUCENE-3414, outer recursion gate); 2014-03-02 (LUCENE-5483, inner-suffix check); 2022-07-05 (LUCENE-10626, generator copy)",
   "first_affected_version": "3.5.0 [exec] (the first release with Lucene's Hunspell code; 3.4.0 has none [exec]). The outer-N case fails in every release; the inner-N case fails from 4.8.0 (LUCENE-5483) [exec]. Entry points by release: stemming 3.5.0+, Hunspell.spell 8.9.0+, getAllWordForms 9.5.0+ [exec]",
   "affected_versions": "every release with Lucene's Hunspell code, 3.5.0 through 10.6.0 (10.6.0 by reading), and main a9779ef3c193; never fixed. [exec] the follow-up's version-portable probes fail on 18 releases (3.5.0, 3.6.2, 4.0.0, 4.7.2, 4.8.0, 4.10.4, 5.5.5, 6.0.0, 6.6.6, 7.7.3, 8.9.0, 8.11.4, 9.0.0, 9.4.2, 9.5.0, 9.12.3, 10.0.0, 10.5.2) and on main with -ea and -da; the finder's JUnit fails on main (-ea, -da), 10.5.2, 10.0.0, 9.12.3 and 9.5.0 (it does not compile before 9.5.0, its spell-only variant fails on 9.4.2); the independent reproduction's tests fail on main (-ea, -da), 10.5.2, 9.12.3, 9.4.2 and 8.11.2 (stem-only variant); the intended-behaviour check re-ran the finder's test on 10.5.2 (fail). In 3.5.0-4.7.2 the inner-N case is accepted only because those versions did not check continuation classes at all (they also accept drinkables when 'able' has no continuation class, which C Hunspell rejects). [read] Stemmer.java and WordFormGenerator.java on upstream main a95c754ee003 are byte-identical to a9779ef3c193; the gates are also on branch_10x and branch_10_6. All runs on aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-641.html",
   "repro": "repro/LFV-641/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-100",
   "priority": "medium",
   "priority_rank": 253,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / quantized vector formats merge (Lucene104 OSQ, Lucene102 BBQ) with index / SortingCodecReader",
   "title": "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",
   "summary": "You re-sort an index the way the SortingCodecReader javadoc describes: wrap every segment with SortingCodecReader.wrap(reader, sort) and pass them all to IndexWriter.addIndexes on a fresh index-sorted writer, with a codec that uses a quantized vector format (for example Lucene104HnswScalarQuantizedVectorsFormat), where one segment has vectors for field b but none for field a. You expect the re-sort to succeed, as it does with the default non-quantized HNSW format and as an ordinary merge of the same segments does. Instead the quantized writer's centroid code asks every source reader for field a without checking that reader's FieldInfos, SortingCodecReader wraps the missing (null) values, and addIndexes fails with a NullPointerException at SortingCodecReader.java:252 (an AssertionError at :318 with -ea), so nothing is added.",
   "impact_class": "crash",
   "introduced_commit": "8856a5f4eb7 (#14078 'Binary vector format for flat and hnsw vectors', main; branch_10x backport 39e7f0973ec, first released in 10.2.0), which added Lucene102BinaryQuantizedVectorsWriter.mergeAndRecalculateCentroids and calculateCentroid with null-only checks [read]; carried byte for byte into the current Lucene104ScalarQuantizedVectorsWriter by 594eeb7e637 (#15169, backport 07033dcd84c, first released in 10.4.0) and extended to FLOAT16 fields on main by 50c1e6acb7f (#16473) [read]; a reintroduction of the defect class that #13641 (74e3c44063a main / ab262f917d4 branch_9x, 9.12.0 and 10.0.0) fixed in the generic merge and the Lucene99 writers [exec]",
   "introduced_date": "2025-03-04 (#14078 merged); current Lucene104 code from 2025-09-17 (#15169 merged); fp16 variant from 2026-08-26 (#16473, main only)",
   "first_affected_version": "10.2.0 [exec] (Lucene102 BBQ formats); 10.4.0 for the Lucene104 OSQ formats [exec]",
   "affected_versions": "10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1 and 10.3.2 (Lucene102HnswBinaryQuantizedVectorsFormat, Lucene102BinaryQuantizedVectorsFormat) and 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main ea57360912ed (Lucene104HnswScalarQuantizedVectorsFormat, Lucene104ScalarQuantizedVectorsFormat) [exec]; the FLOAT16 (fp16) variant on main only [exec]; branch_10_6 (10.6.0, released 2026-10-29) and the unreleased branch_10x [read]; not affected: 9.12.0, 9.12.3, 10.0.0 and 10.1.0, where only the guarded int8 and the non-quantized writers exist [exec]; 9.11.1 and earlier fail for every vector format, including the non-quantized control, through the older generic merge defect GITHUB#13626 that #13641 fixed, which is not this bug [exec]; not fixed upstream as of main ea57360912ed and branch_10_6 2763db11b0a [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-100.html",
   "repro": "repro/LFV-100/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-269",
   "priority": "medium",
   "priority_rank": 254,
   "novelty": "new",
   "withheld": false,
   "area": "index / merged CodecReader view (SlowCompositeCodecReaderWrapper vector values); misc / BP merge-time reordering",
   "title": "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",
   "summary": "You use BPReorderingMergePolicy with a BpVectorReorderer on a float vector field, and one segment holds only documents without that optional field, for example a batch of documents without embeddings that was flushed on its own. You expect merges to combine it with the other segments, as they do when every segment has vectors. Instead the merged view's FloatVectorValues.copy() throws NullPointerException ('Cannot invoke KnnVectorValues.copy() because this.sub is null'), IndexWriter treats the failed merge as a tragic event, closes itself and drops every change since the last commit, and the same merge fails again after each reopen.",
   "impact_class": "index unusable",
   "introduced_commit": "68051f1b9f5a052b9a2b4274ad7197eafb4a8caf, 'SlowCompositeCodecReaderWrapper must copy its sub-vector values to maintain thread-safety (#14092)' by msokolov (merged 2024-12-31, milestone 10.2.0, no review comments, no CHANGES entry); branch_10x backport 0bfa27513dce, same day, the commit the 10.2.0 release contains [exec]. It replaced the shallow copy of the sub list (#13779, 10.0.0) with DocValuesSub.copy(), which calls sub.copy() with no null check, to fix a real thread-safety problem; the null subs themselves date from #12622 (f7cab164501, 2023) and are handled everywhere else. The end-to-end in-tree trigger came with #14097 (02a09f6ab12, 2025-01-07, main only), whose BpVectorReorderer copies the merged view once per thread; #16383 (bfe5c847d3c, 2026-07-27, main only) added the float16 variant with the same pattern",
   "introduced_date": "2024-12-31",
   "first_affected_version": "10.2.0 [exec] for the core copy() NullPointerException (same-package test and a public-API custom OneMerge#reorder that copies the merged view, -ea and -da; 10.1.0 passes); the stock end-to-end failure (BPReorderingMergePolicy + BpVectorReorderer) is unreleased, main only (11.0.0-SNAPSHOT), because BpVectorReorderer is in no release",
   "affected_versions": "core copy() defect: 10.2.0, 10.3.0, 10.3.2, 10.4.0, 10.5.2 and main ea57360912ed [exec]; 10.2.1, 10.2.2, 10.3.1, 10.5.0, 10.5.1, 10.6.0 and the branch_10x, branch_10_6 and branch_10_5 tips of 2026-10-24 [read]; not affected: 10.0.0 and 10.1.0 [exec]; 9.12.3 and older: API absent (no KnnVectorValues, no copy()) [exec]. End-to-end BPReorderingMergePolicy + BpVectorReorderer failure (forceMerge, natural merges, addIndexes(CodecReader...)): main only [exec]; BpVectorReorderer is absent from the 10.2.0, 10.3.0 and 10.5.2 misc jars [checked by the intended-behaviour check on the cached jars]. float32, byte and (main only) float16 merged values all fail [exec], but only the float32 path has an in-tree caller. Not fixed upstream as of main ea57360912ed [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-269.html",
   "repro": "repro/LFV-269/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-128",
   "priority": "medium",
   "priority_rank": 255,
   "novelty": "known",
   "withheld": false,
   "area": "store / MMapDirectory (MemorySegmentIndexInput clone, slice and close)",
   "title": "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",
   "summary": "You open a file with MMapDirectory that is larger than one mmap chunk, make a clone (or a slice that covers the whole file), close that clone and keep reading the original; you expect the original and the other clones to be unaffected, as they are for single-chunk files, for partial slices, for other directories and on 10.0.0. Instead the clone shares the original's array of memory segments and close() fills that array with nulls, so the original's next access to another chunk throws NullPointerException, from then on the never-closed original reports AlreadyClosedException, and closing it afterwards leaves its arena and the file mapping open. Separately, reading a clone after the original was closed throws NullPointerException where the IndexInput#clone javadoc promises AlreadyClosedException.",
   "impact_class": "crash",
   "introduced_commit": "331323f1b96e (apache/lucene#13906 'Avoid slicing memory segments unnecessarily', author original-brownbear, merged 2024-10-15, approved by jpountz and uschindler; one file changed, no test, no CHANGES entry; branch_10x backport cebf1e7259c1, first released in 10.1.0) made clone() pass this.segments to the new MultiSegmentImpl and buildSlice(0, length) reuse it, instead of copying the array as before; the in-place Arrays.fill(segments, null) in close() is older (#912, 2022-09-26, first released in 9.4.0) and was harmless while every instance owned its array [read]",
   "introduced_date": "2024-10-15 (#13906 merged on main; the branch_10x backport the same day)",
   "first_affected_version": "10.1.0 [exec]",
   "affected_versions": "every release from 10.1.0 through 10.5.2 (11 releases: 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2), each executed and failing 3 of 3 with seed DEADBEEF (also with -da on 10.1.0 and 10.5.2), and main ea57360912ed (4 of 4 with -ea and -da) [exec]; the leaked arena also on 10.1.0 (-ea) and 10.5.2 (-ea and -da) [exec]; unaffected: 10.0.0 and 9.12.3 (pass with -ea and -da; a probe shows MultiSegmentImpl in use with each clone holding its own array) [exec], 9.4.0 through 9.12.2 by source identity [read], and releases before 9.4.0, which have no MemorySegmentIndexInput [read]; branch_10x and branch_10_6 carry the same lines [read], so 10.6.0 (released 2026-10-29) is affected [not executed]; not fixed upstream [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/13906",
    "https://github.com/apache/lucene/issues/12705",
    "https://github.com/apache/lucene/issues/14271",
    "https://github.com/apache/lucene/issues/7287",
    "https://issues.apache.org/jira/browse/LUCENE-6225",
    "https://github.com/apache/lucene/issues/15054"
   ],
   "doc": "",
   "repro": "repro/LFV-128/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-492",
   "priority": "medium",
   "priority_rank": 256,
   "novelty": "known",
   "withheld": false,
   "area": "store / BufferedIndexInput (NIOFSDirectory, misc RAFDirectory, BufferedIndexInput.wrap; surfaces through CodecUtil.checkFooter and stored-fields reads)",
   "title": "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)",
   "summary": "You read an index through NIOFSDirectory (or any BufferedIndexInput), one read fails with an IOException, for example a transient storage error, and the same input is read again, by your retry or by Lucene's own CodecUtil.checkFooter(in, priorException). You expect the next read to re-read the failed region or to throw again. Instead, since 8.6.0 refill() has already marked the buffer as holding the new region before readInternal failed, so the next reads silently return up to one buffer of bytes from the previous region (or zeros), and one transient failure while opening a healthy index makes DirectoryReader.open report it as corrupt.",
   "impact_class": "silent wrong results",
   "introduced_commit": "82692e76e054d3e6938034e96a4e9632bd9f7a70 (master, released first in 9.0.0) and its branch_8x commit 4ccbf19eb785705b80f3ecb10fc8643dbee53783 (first released in 8.6.0), LUCENE-9271 'Move BufferedIndexInput to the ByteBuffer API' (apache/lucene#10311, PR apache/lucene-solr#1338, committed directly by jpountz) [read] [exec]. It re-opens LUCENE-1262 (#2339), fixed by a6ff3c93df77 (trunk) and 3349b10e4fa (2.3 branch) on 2008-04-13",
   "introduced_date": "2020-04-07 (both commits; PR opened 2020-03-11)",
   "first_affected_version": "8.6.0 [exec]; last unaffected release 8.5.2 [exec] (tagged 2020-05-26 from branch_8_5, which does not contain 4ccbf19eb78)",
   "affected_versions": "every release from 8.6.0 on: 8.6.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2, and main ea57360912ed. [exec] fail: 8.6.0, 8.6.3, 8.8.2, 8.9.0, 8.11.2, 8.11.4, 9.0.0, 10.0.0 (version-neutral main() probes), 9.12.3, 10.5.2 and main (JUnit, -ea and -da, plus main() probes); [exec] pass: 5.5.5, 6.6.6, 7.7.3, 8.5.0, 8.5.2. [read] git tag --contains: 8.6.0-8.8.1 contain the branch_8x commit (the history clone has no later 8.x tags) and all 33 tags 9.0.0-10.5.2 contain the master commit; 2.3.2-8.5.2 keep the LUCENE-1262 ordering (the original bug existed before 2.3.2). 10.6.0 not checked (not on Maven Central on 2026-10-26). Not fixed upstream: no commit touches BufferedIndexInput.java after ebfd863ac72 (2025-08-25), and no open PR changes refill() [read]. The false-corruption manifestation at DirectoryReader.open also needs LUCENE-7822 (8.6.0); on 8.5.2 with only the reordering shadowed in, the stale bytes show only as suppressed exceptions [exec]. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/2339",
    "https://github.com/apache/lucene/issues/10311",
    "https://issues.apache.org/jira/browse/LUCENE-1262",
    "https://github.com/apache/lucene/issues/1828",
    "https://issues.apache.org/jira/browse/LUCENE-753",
    "https://github.com/apache/lucene/issues/8873"
   ],
   "doc": "",
   "repro": "repro/LFV-492/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-346",
   "priority": "medium",
   "priority_rank": 257,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / kuromoji (JapaneseCompletionFilter and JapaneseCompletionAnalyzer romanization, KatakanaRomanizer)",
   "title": "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",
   "summary": "You analyze a short Japanese string with JapaneseCompletionAnalyzer or JapaneseCompletionFilter, for example 32 x \"ン\" when indexing or 32 x \"し\" as an auto-complete query, and expect the surface token plus a bounded set of romanized spellings. Instead KatakanaRomanizer.romanize builds every combination of the alternative spellings of each ambiguous kana (2^n for シ ジ チ ツ ヅ フ ヲ ン, 3^n for ヂ; for ン most are duplicates: 2^n tokens but only n+1 distinct strings), eagerly and with no limit, and the filter buffers all of them before it returns the first token. So 20 x \"ン\" already gives 1,048,577 tokens at one position, 24-32 kana throw OutOfMemoryError, a LimitTokenCountFilter placed after the filter cannot help, and an IndexWriter that analyzes such a field closes.",
   "impact_class": "crash",
   "introduced_commit": "4e86df96c0385a7b552434d7e2a9bee69f18bd77 (apache/lucene#297, LUCENE-10102 / GitHub issue #11140 'Add JapaneseCompletionFilter for Input Method-aware auto-completion', by GitHub mocobeta, co-authored by rmuir) [read] [exec]. Present since the feature was written, so not a regression; no later commit changes what romanize generates (#16416 changed only the output buffer)",
   "introduced_date": "2021-09-17 (merged 2021-09-17T13:37:13Z)",
   "first_affected_version": "9.0.0 [exec] (the first release with JapaneseCompletionFilter; CHANGES.txt lists LUCENE-10102 under 9.0.0 New Features; no 8.x release has the classes: 8.11.4 executed, the repro does not compile; the 8.10.0-8.11.3 kuromoji jars, SHA-1 checked, contain no completion classes)",
   "affected_versions": "every release that has the filter, 9.0.0 to 10.6.0 (10.6.0 by reading): all 33 from 9.0.0 to 10.5.2 [exec], also -ea on 9.0.0, 9.12.3 and 10.5.2, the introducing commit 4e86df96 (-ea and -da) and main ea57360912ed (-ea and -da) [exec]; the independent reproduction's independent JUnit also fails on 10.5.2 and 9.12.3 [exec]; not applicable to 8.x and older, where the API does not exist [exec]; still unfixed on upstream main e1c4184cb98 (read 2026-10-26). On 10.5.2 and 9.12.3 draining the buffer is also quadratic; #16416 (CHANGES 10.6.0, released 2026-10-29) fixed only that, and the exponential count is identical on every version. All runs: OpenJDK 25.0.3, Linux aarch64, 2 GB heap (the heap moves only the threshold, not the failure at 32 kana)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-346.html",
   "repro": "repro/LFV-346/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-111",
   "priority": "medium",
   "priority_rank": "",
   "novelty": "new",
   "withheld": true,
   "area": "store",
   "title": "Details withheld pending security review",
   "summary": "",
   "impact_class": "withheld",
   "introduced_commit": "withheld",
   "introduced_date": "withheld",
   "first_affected_version": "withheld",
   "affected_versions": "withheld",
   "security": "withheld",
   "upstream_links": [],
   "doc": "",
   "repro": "",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-171",
   "priority": "medium",
   "priority_rank": "",
   "novelty": "new",
   "withheld": true,
   "area": "queryparser",
   "title": "Details withheld pending security review",
   "summary": "",
   "impact_class": "withheld",
   "introduced_commit": "withheld",
   "introduced_date": "withheld",
   "first_affected_version": "withheld",
   "affected_versions": "withheld",
   "security": "withheld",
   "upstream_links": [],
   "doc": "",
   "repro": "",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-644",
   "priority": "low",
   "priority_rank": 258,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter deletes (deleteDocuments, DocumentsWriterDeleteQueue array nodes, per-thread delete slices)",
   "title": "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)",
   "summary": "You pass a Term[] or Query[] to IndexWriter.deleteDocuments, the call returns its sequence number, and you then reuse the array, for example refill it with the next batch of ids; the delete should mean the terms or queries the array held at the call, as it already does for documents in flushed segments. IndexWriter hands the array itself to its delete queue, and each per-thread writer reads it only later, at its next addDocument or flush, so documents still buffered in RAM are deleted by the array's new contents. In the repro, deleting {flushed1, buffered1} and then refilling the same array with {flushed2, buffered2} and deleting again leaves buffered1 alive after commit, and reassigning the slot of a one-element Query[] after the call keeps 'delete-me' and deletes 'keep', which no delete call named; no exception is thrown.",
   "impact_class": "data corruption",
   "introduced_commit": "e95097a7c8dfc042c09288717822768c6011f5e8 (LUCENE-2956 'Support updateDocument() with DWPTs', apache/lucene#4030, patch by s1monw, realtime_search branch; JIRA/SVN patch era, no pull request): added DocumentsWriterDeleteQueue, whose TermArrayNode/QueryArrayNode store the caller's Term[]/Query[] (one node per call so the call's deletes become visible atomically, as the reviewer mikemccand asked), and replaced DocumentsWriter's loop that copied the elements into every per-thread writer during the call. It reached trunk, the line every release since 4.0 comes from, in merge 2a969f828c1b65d81f0e630188dd8244694765b9 (LUCENE-3023 'Land DWPT on trunk', apache/lucene#4097). Later edits (e555950a3e6 generics, ec4720f4c29 BufferedUpdates rename, 058970e72bd6 sequence numbers 2016) kept passing the array through [read]. [exec]",
   "introduced_date": "2011-04-13 (e95097a7c8d, realtime_search branch); 2011-05-01 (2a969f828c1, trunk)",
   "first_affected_version": "4.0.0-ALPHA [exec]; 3.6.2 and 3.1.0, the last releases before, copy the elements during the call and pass with -ea and -da [exec]",
   "affected_versions": "every release from 4.0.0-ALPHA through 10.5.2 (the last release before 10.6.0) and main a9779ef3c193, never fixed. [exec] the follow-up history step fails on 4.0.0-ALPHA, 4.0.0-BETA, 4.0.0 (-ea/-da), 4.10.4, 5.0.0, 7.7.3, 8.11.4 (-da), 9.12.3, 10.5.2 and main (-ea/-da); the finder's records add 5.5.5, 6.6.6 and 7.0.0; the independent reproduction re-ran 10.5.2 (-ea/-da) and 9.12.3 (-ea), and the security probe 10.5.2 (-da). Releases before 9.12.3 ran a main() port of the same scenario adapted to their API; all runs on JDK 25, single-threaded. [read] git tag --contains 2a969f828c1 lists all 123 release tags 4.0.0-alpha..10.5.2 in the history clone (the 8.8.2-8.11.x tags are not in that clone; 8.11.4 was executed), and every tag builds new TermArrayNode(terms)/new QueryArrayNode(queries) with no clone, copyOf or arraycopy on the path. Not affected: 3.6.2 and earlier (executed 3.1.0 and 3.6.2; read 2.1.0-3.0.0, where Term[] deletes exist since 2.1.0, Query[] since 2.4.0, varargs since 3.0.0).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-644.html",
   "repro": "repro/LFV-644/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-010",
   "priority": "low",
   "priority_rank": 259,
   "novelty": "new",
   "withheld": false,
   "area": "index / soft deletes",
   "title": "A try* un-delete or pending soft-delete change is ignored or lost by later term-based operations",
   "summary": "With a soft-deletes field, you revive a document with tryUpdateDocValue (or change its soft field by term) and then issue term-based deletes or updates. You expect the later operations to see the revived or newly soft-deleted state. Instead term-based ops resolve against live docs that are only materialized when doc-values updates are written, so the revived document is skipped (duplicate live keys) or lost when its segment looks 100% deleted.",
   "impact_class": "data corruption",
   "introduced_commit": "LUCENE-8298 (#9345; 0c65af048b3 on branch_7x, a3c86373e47 on master) [exec]; the C2 form dates from LUCENE-8233 (soft deletes, 2018-04-04)",
   "introduced_date": "2018-05-09",
   "first_affected_version": "7.4.0 [exec]",
   "affected_versions": "7.4.0 to 10.5.2 (all 67 releases) and main [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-010.html",
   "repro": "repro/LFV-010/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-014",
   "priority": "low",
   "priority_rank": 260,
   "novelty": "new",
   "withheld": false,
   "area": "index / addIndexes",
   "title": "addIndexes publishes segments outside the full-flush boundary, breaking sequence-number ordering",
   "summary": "You call addIndexes while other threads delete or update documents, and you rely on sequence numbers to order those operations. You expect operations with a smaller seqNo not to touch the added documents, and a commit to contain only operations up to its seqNo. Instead deletes or updates with a smaller seqNo hit the added documents, and a commit can include later operations.",
   "impact_class": "silent wrong results",
   "introduced_commit": "LUCENE-7302 (#8356; 7ee1f422458 on branch_6x, reaching master through the merge b1fb142af00) [exec]",
   "introduced_date": "2016-05-24",
   "first_affected_version": "6.2.0 [exec]",
   "affected_versions": "6.2.0 to 10.5.2 (all 89 releases) and main [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-014.html",
   "repro": "repro/LFV-014/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-359",
   "priority": "low",
   "priority_rank": 261,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / SimpleQueryParser (near operator: consumePhrase phrase slop)",
   "title": "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",
   "summary": "You parse \"a b\"~2+c with SimpleQueryParser and expect what its javadoc defines, the near query AND c, just as \"a b\"~2 +c and \"a b\"+c parse. Instead the parser skips the character right after the slop digits, so the '+' is lost and you get phrase OR c (on an index with the documents 'a b' and 'c' it matches 2 documents instead of 0); the same happens to '|' (\"a b\"~2|c becomes AND under default MUST), to a quote (\"a b\"~2\"c d\" becomes the phrase OR c OR d) and to '(' (\"a b\"~2(c+d) loses its group). The cause is an off-by-one in consumePhrase: parseFuzziness already stops on the delimiter that ends the slop, and the unconditional '++state.index' that was written to step over the closing quote then skips that delimiter.",
   "impact_class": "silent wrong results",
   "introduced_commit": "584fda3bdf0a5b044046feb63c322ae8dee997a4 (trunk, LUCENE-5410 'add fuzzy and near to SimpleQueryParser', svn r1563558) and its branch_4x backport b18fdadedecad444583eaa0eb343c35d6aa84707 (svn r1563562, the commit that shipped first, in 4.7.0); an SVN-era commit of a JIRA patch, no pull request; issue LUCENE-5410 = apache/lucene#6473 (CHANGES credit 'Lee Hinman via Robert Muir'). The skipping '++state.index' itself is older (LUCENE-5336, 3c9e753df64 / 64e591e1b7a, 2013-11-12), when it only stepped over the closing quote; LUCENE-5410 put the slop branch, whose parseFuzziness leaves the index on the next delimiter, in front of it. [read]",
   "introduced_date": "2014-02-02",
   "first_affected_version": "4.7.0 [exec] (the first release with SimpleQueryParser and its '~' operator; 4.6.1 has no SimpleQueryParser, the probe does not compile)",
   "affected_versions": "every release from 4.7.0 to 10.5.2 (the last before 10.6.0) and main ea57360912ed; never fixed. [exec] the follow-up's version-portable main() probe (4 bug cases against their spaced forms, 2 controls) fails on 4.7.0, 4.10.4, 5.0.0, 6.4.2, 6.5.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main and passes on main with the fix; the finder's JUnit fails 4 of 4 on main (-ea, -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 5 of 6 on main (-ea, -da), 10.5.2 (-ea, -da) and 9.12.3; the intended-behaviour check's main() probe fails on 10.5.2, 9.12.3, 8.11.4, 6.6.6 and 5.0.0. [read] consumePhrase is whitespace-normalized identical in all 110 release tags of the history clone (4.7.0 to 10.5.2) and on main (the clone lacks 8.9.0 to 8.11.3; 8.11.4 was executed); parseFuzziness changed in 6.5.0 (LUCENE-7712: an empty slop means 2), 9.0.0 and 9.10.0, none of which moves where the index stops; the newest upstream commits to the file on main (df6f71a3729, in the tested tree) and branch_10x (ef740ebd967) change only javadoc formatting. All runs on JDK 25, aarch64 Linux.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-359.html",
   "repro": "repro/LFV-359/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-560",
   "priority": "low",
   "priority_rank": 262,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / flexible StandardQueryParser (processor pipeline order: WildcardQueryNodeProcessor runs before MultiFieldQueryNodeProcessor)",
   "title": "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)",
   "summary": "You give StandardQueryParser a PerFieldAnalyzerWrapper (WhitespaceAnalyzer by default, StandardAnalyzer for 'title'), call setMultiFields({title}) and parse 'Luc*' with no field, expecting what the javadoc promises: the clause expanded over the multi fields, i.e. the same query as 'title:Luc*', which becomes title:luc* and finds the document titled 'Lucene'. Instead the pipeline normalizes the prefix in WildcardQueryNodeProcessor before MultiFieldQueryNodeProcessor has set the field, so Analyzer#normalize is called with field null (the wrapper's default analyzer), the query becomes title:Luc* and finds nothing, while plain, fuzzy, regexp and range clauses in the same setup are normalized with the expanded field. If the per-field map is a Map.of, the null lookup makes parse() throw NullPointerException for every field-less prefix or wildcard clause.",
   "impact_class": "silent wrong results",
   "introduced_commit": "e92a38af90d12e51390b4307ccbe0c24ac7b6b4e (master): LUCENE-7355 'Add Analyzer#normalize() and use it in query parsers' by @jpountz (now apache/lucene#8409; a JIRA patch, no PR) [read]. It removed LowercaseExpandedTermsQueryNodeProcessor, which ran after MultiFieldQueryNodeProcessor and lower-cased field-independently, and added Analyzer#normalize(fqn.getFieldAsString(), ...) to WildcardQueryNodeProcessor, the first processor of the pipeline; the calls it added to the fuzzy, regexp and range processors run after the expansion. The pipeline order itself dates from 6f66858572c (2010) and was harmless until then. The 6.x backport 7c2e7a0fb80 (6.2.0) did not touch the flexible parser. Not commit-bisected (2016 sources not built)",
   "introduced_date": "2016-07-12 (committed to master; authored 2016-06-28)",
   "first_affected_version": "7.0.0 [exec]; not affected up to 6.6.6 [exec]. The 'present since 6.2.0 [read]' in the hunt's record and the intended-behaviour check is wrong: the 6.x backport of LUCENE-7355 did not change the flexible parser",
   "affected_versions": "every release 7.0.0 to 10.5.2 and main ea57360912ed. [exec] the follow-up's version-portable probe (MultiFieldWildcardHistoryMain, 7 mismatches each) on 7.0.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the finder's JUnit (2 of 2 fail) on 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the independent reproduction's JUnit (3 of 3 fail) on main (-ea and -da), 10.5.2 and 9.12.3, and its parse-only main() on 8.11.4 and 7.0.0. [read] git tag --contains e92a38af90d lists every 7.x to 10.x release tag (8.8.2 to 8.11.4 are not tagged in the history clone; 8.11.4 was executed). Not affected: every release up to 6.6.6 [exec]. Upstream main a95c754ee003, branch_10x and branch_10_5 have the same three processor files [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-560.html",
   "repro": "repro/LFV-560/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-828",
   "priority": "low",
   "priority_rank": 263,
   "novelty": "new",
   "withheld": false,
   "area": "queries / intervals (overlap filters Intervals.overlapping / nonOverlapping / notWithin vs the LUCENE-8477 disjunction rewrite that containedBy and within apply to their reference)",
   "title": "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",
   "summary": "You index 'visit new york' and run within(visit, 1, R) and notWithin(visit, 1, R) with R = or(york, \"new york\"), and you expect exactly one of them to return 'visit', because the javadoc defines notWithin as the intervals that do not appear within n positions of the reference. Instead both return the same interval [0,0]: within is built on containedBy, which pulls the or() apart (LUCENE-8477) and sees 'new york' right next to 'visit', while notWithin, overlapping and nonOverlapping read the default or() as one minimized source, which drops 'new york' because that interval contains 'york'. In the same way containedBy(new, R) matches 'new york' but overlapping(new, R) does not, and maxgaps(0, overlapping(new, R)) does match, because the nested form does pull the reference apart.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f1782d0dd1195c823c79aab87529ebd7e8217b95 (master, released from 9.0.0) and its branch_8x backport 2571bf355f82e193d50ec2509f83ba698b262562 (the first released form, in 8.1.0), both 2019-03-27: 'LUCENE-8477: Automatically rewrite disjunctions when internal gaps matter' (apache/lucene-solr#620 by romseygeek; the JIRA issue is now apache/lucene#9523). It gave containedBy (ContainedByIntervalsSource.build) the reference pull-up and extend() a pullUpDisjunctions(), so within = containedBy(source, extend(reference)) tests every alternative, but rewrote overlapping and nonOverlapping as plain new OverlappingIntervalsSource / NonOverlappingIntervalsSource constructors (and notWithin as NonOverlapping over extend) without a top-level pull-up; OverlappingIntervalsSource.pullUpDisjunctions runs only when the filter is nested [exec] [read]. A regression of the relations' mutual consistency: 8.0.0 is consistent because every relation read the same minimized or()",
   "introduced_date": "2019-03-27 (author date of f1782d0dd11 and of the branch_8x backport 2571bf355f8)",
   "first_affected_version": "8.1.0 [exec] (8.1.0 and 8.1.1 shipped the intervals package in lucene-sandbox as org.apache.lucene.search.intervals; LUCENE-8856 moved it to lucene-queries in 8.2.0). Last unaffected release 8.0.0 [exec]: there within, containedBy and the overlap filters all read the minimized or() and agree (all miss the 'new york' alternative). API age: nonOverlapping, notWithin and containedBy since 7.4.0 (LUCENE-8196), within and overlapping since 8.0.0 (LUCENE-8629), the fn: query-text functions since 9.1.0 (LUCENE-10223) [read]",
   "affected_versions": "every release from 8.1.0 through 10.5.2 and 10.6.0 (its intervals sources at branch_10_6 RC1 4ae946e5a9b [exec], below) [exec]; branch_10_6 head 4ae946e5a9b [exec], so the released 10.6.0 has it; main a9779ef3c193 [exec]; upstream main 20ced71c1e6 [read]. Not affected: 8.0.0 [exec]; 7.4.0 and 7.7.3 for the only pair that existed then, containedBy / nonOverlapping [exec]. All release runs on JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-828.html",
   "repro": "repro/LFV-828/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-909",
   "priority": "low",
   "priority_rank": 264,
   "novelty": "new",
   "withheld": false,
   "area": "queries / span queries (per-document lockstep of the ContainSpans subclasses in SpanContainingQuery and SpanWithinQuery)",
   "title": "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",
   "summary": "You index 'a b a' and search with SpanContainingQuery(big = SpanNear([a, b], slop 0), little = SpanOr(SpanNear([a, a], slop 5), b)): the big span 'a b' at [0,2) contains the little span 'b' at [1,2), so you expect a hit, and SpanWithinQuery with the same pair should match too. Instead both return nothing, because the little spans arrive sorted by start as [0,3) and then [1,2) (their ends go down, which the Spans contract allows), and each query's single forward pass gives up after testing only the longer little span [0,3): containing moves on to the next big span, within moves the big iterator past [0,2) and never comes back. The same happens in a sentence-scoped search for '(apple NEAR/5 pie) OR cake' on 'bos apple cake eos bos pie eos' (the 'cake' sentence is missed only because 'apple ... pie' crosses into the next sentence), so adding a word to a document or an OR alternative to the query can remove a hit; nothing extra is ever returned.",
   "impact_class": "silent wrong results",
   "introduced_commit": "4483ff208956f74eeef32cfd6ee724ec0ea5d549 (trunk, svn r1676716, 2015-04-29, committed by Robert Muir) and its branch_5x backport 2e2ae5435e7 (svn r1676723, the commit 5.2.0 contains): LUCENE-6083 'Span containing/contained queries' (GitHub #7145 after the JIRA migration), patch by Paul Elschot with renames and tests by Robert Muir; no pull request (svn era); CHANGES 5.2.0 New Features [read]. Not a regression: the lockstep has been incomplete since the queries were added; no commit-level bisection is possible because the introducing commit creates the classes",
   "introduced_date": "2015-04-29",
   "first_affected_version": "5.2.0 [exec] (the first release of SpanContainingQuery and SpanWithinQuery; 5.1.0 and earlier lack the classes [exec])",
   "affected_versions": "every release from 5.2.0 through 10.5.2, 10.6.0 (released 2026-10-29; branch_10_6 head 4ae946e5a9b) and main a9779ef3c193; not fixed upstream (the last commits on the four files are #13957 (2024-10-26), #11840 (2022-10-19) and #152 (2021-05-26), none of which touches the lockstep; main head c5ab3e57b9ba and branch_10_6 head 4ae946e5a9b9 checked 2026-10-28). [exec] the finder's JUnit fails 3 of 4 (its Intervals control passes) on main (-ea, -da), the branch_10_6 head, 10.5.2, 10.0.0 and 9.12.3 (-ea); its main() variants fail 3 of 5 (controls pass) on 5.2.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0 and main (-da); the independent reproduction's JUnit fails 4 of 6 on main (-ea, -da), the branch_10_6 head, 10.5.2 (-ea, -da) and 9.12.3; the intended-behaviour check's fails 2 of 3 on main (-ea, -da) and 10.5.2. [read] identical lockstep digests at 5.2.0, 5.5.5, 6.6.6, 7.7.3, 8.8.1, 9.0.0, 9.12.3, 10.0.0, 10.5.2, 4ae946e5a9b and main; 8.8.2 to 8.11.3 are not tagged in the history clone and are listed because 8.8.1 [read] and 8.11.4 [exec] are. Not a 10.6.0 regression. Caveats: all runs used JDK 25 on aarch64 Linux, and the releases before 9.12.3 ran with -da only",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-909.html",
   "repro": "repro/LFV-909/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1171",
   "priority": "low",
   "priority_rank": 265,
   "novelty": "new",
   "withheld": false,
   "area": "core / search: FuzzyQuery and FuzzyTermsEnum (Levenshtein pattern built from Term.text())",
   "title": "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",
   "summary": "You index a binary term, for example the bytes ff 61 62 63 in a StringField, and search it with new FuzzyQuery(new Term(field, sameBytes), 1); you expect the document to match, because the identical term is at edit distance 0 and FuzzyQuery(term, 0) does match it. Instead the query matches nothing, or only a document holding the text term \"[ff 61 62 63]\": FuzzyTermsEnum builds its Levenshtein automaton from Term.text(), and for bytes that are not valid UTF-8 Term.text() returns the human-readable hex rendering of the bytes, not the term.",
   "impact_class": "minor",
   "introduced_commit": "0c333c60dd03aedde4fc75aca29713ca9b87b6ff (LUCENE-2514 'Term is no longer character based', apache/lucene#3588, trunk r960484; no PR, Subversion era) [read]. The hex-display-string form of the symptom comes from LUCENE-4934 (apache/lucene#5998): trunk e8279926a2d7e08920c45cd657f71122fc45975c and branch_4x 74fc96bd3d68757d20508aceb9ffb7530374652c, which made Term.text() decode strictly and fall back to BytesRef.toString() [read]",
   "introduced_date": "2010-07-05 (LUCENE-2514, author and commit date 2010-07-05T08:33:25Z); hex form 2013-04-15 (LUCENE-4934)",
   "first_affected_version": "4.0.0 [exec]",
   "affected_versions": "4.0.0 to 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT); not fixed anywhere. Executed, fail [exec]: main with -ea and -da (the finder, the independent reproduction, the intended-behaviour check, the adjudication and a separate re-run), 10.6.0 (the finder, the independent reproduction, the history step and a separate re-run), 10.5.2 and 9.12.3 (the independent reproduction; 9.12.3 also finder and history step), 8.11.4 (finder, history step), 4.3.0 (-ea and -da: hex-string neighbour matched), 4.2.1 and 4.0.0 (-da: no hit; -ea: AssertionError in UnicodeUtil). Not affected: 3.x and earlier (API absent). Other releases by reading every release tag (0c333c60dd0 is in all release tags from 4.0.0-alpha on). Not new in 10.6. Upstream main 1c2072f0284 (2026-11-02) still builds the pattern from term.text() (FuzzyTermsEnum.java:101 and :132). All runs on Linux aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1171.html",
   "repro": "repro/LFV-1171/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-248",
   "priority": "low",
   "priority_rank": 266,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / analyzing suggester (AnalyzingSuggester.build, inherited by FuzzySuggester)",
   "title": "AnalyzingSuggester and FuzzySuggester count skipped duplicate copies of a surface form toward maxSurfaceFormsPerAnalyzedForm, so distinct lower-weighted surface forms are silently dropped",
   "summary": "You build an AnalyzingSuggester or FuzzySuggester from entries in which one text repeats, for example 256 documents with 'Apple iPhone' and one with 'apple iphone', which a lowercasing analyzer maps to the same analyzed form, and you expect both surface forms back, because maxSurfaceFormsPerAnalyzedForm (default 256) is documented as the 'maximum number of surface forms to keep for a single analyzed form' and repeated copies are documented as removed. build() increments its per-analyzed-form counter and applies the limit before it checks whether the surface form was already seen, so every skipped copy still uses up a slot: lookup('apple ip') returns only [Apple iPhone], and with a limit of 2 the entries a/10, a/5, A/3 give [a/10] instead of [a/10, A/3]. With 255 copies, or without the repeated copy, both forms are returned.",
   "impact_class": "silent wrong results",
   "introduced_commit": "37cdda05f50b1c544efc5aaac4135dbcd7a28cba (mikemccand, trunk svn r1405977, 2012-11-05; branch_4x backport d9a88eb0e12ea157c2092e51ab39b878788c0dfd, r1405978; no pull request, Subversion era). Its message says 'LUCENE-4534: dedup same surface form in Analyzing/FuzzySuggester', but it is the fix for LUCENE-4533 / #5599 (LUCENE-4534 is the 0-byte-key fix 2537836d4ab committed just before). It added the seenSurfaceForms check below the existing counter and cut [read]. The counter (dedup++) and the cut come from f2f91bae46cbc4a883324521767e4701fbbbc14a (LUCENE-3842 'add AnalyzingSuggester', 2012-09-28), when there was no surface-form dedup and every counted entry was indexed. Isolation is partial [exec]: the 4.1.0 source with only the dedup lines removed also loses the distinct form on these inputs (with -da; with -ea a TopNSearcher assertion fires, the LUCENE-4533 symptom), but there the copy that took the slot was itself indexed as a duplicate result; 37cdda05f50 removed the copy from the FST and left it counted. Both commits predate the first release of the API",
   "introduced_date": "2012-11-05 (the dedup check placed below the cut; the counter and cut date from 2012-09-28)",
   "first_affected_version": "4.1.0 [exec] (the first release that has AnalyzingSuggester and FuzzySuggester at all; the repro fails 2 of 3 there and passes 3 of 3 with the fix shadowed); 4.0.0 has no analyzing package, so the repro does not compile [exec]",
   "affected_versions": "every release from 4.1.0 through 10.5.2 and main ea57360912ed; not fixed on upstream main as of 2026-10-26 [exec]. Caveats: releases before 10.x were run on JDK 25 with API ports of the same test (TermFreqIterator in 4.1-4.5, no temp Directory before 6.0, pre-9.1 test-framework packages); FuzzySuggester was executed on main, 10.5.2 and 9.12.3 only (it does not override build() in 4.1.0 or main); unreleased maintenance branches were not checked",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-248.html",
   "repro": "repro/LFV-248/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1052",
   "priority": "low",
   "priority_rank": 267,
   "novelty": "new",
   "withheld": false,
   "area": "util / FST (Util.TopNSearcher.search, 'Empty string!' branch) and suggest / FreeTextSuggester (lookup's per-level seen-token filter)",
   "title": "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",
   "summary": "You build a FreeTextSuggester (default bigram model) from text in which 'foo' occurs 9 times (once followed by 'bar'), 'barn' 8 times and 'bar' 10 times, and call lookup(\"foo bar\", 1). With stupid backoff 'foo bar' scores 1/9 = 0.111 and 'barn' 0.4 x 8/27 = 0.119, and 'bar' does not count at the unigram level because the bigram model already predicted it, so you expect [barn], which is also what upstream TestFreeTextSuggester's own reference model gives. You get [foo bar]: 'bar' is itself a word, so Util.TopNSearcher returns it from its 'Empty string!' branch without calling the acceptResult filter that rejects already-predicted words; it takes the unigram level's only slot, is then thrown away as a duplicate, and 'barn' is never considered.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f2f91bae46cbc4a883324521767e4701fbbbc14a (trunk, LUCENE-3842 'Analyzing Suggester', JIRA, migrated as apache/lucene#4915; svn era, no pull request; first authored on the lucene3842 feature branch as bc0d717c8f6, 2012-09-23) and its branch_4x backport 0c89e05d765 (svn r1391686, the commit in 4.1.0): it added the protected acceptResult hook to Util.TopNSearcher but called it only on the zero-output completion path, and left the older 'Empty string!' branch (a519b630eea, LUCENE-3714 / apache/lucene#4788, 2012-02-19, written when TopNSearcher was private and had no filter) unfiltered [read]. The user-visible FreeTextSuggester symptom exists since that class was added: b50a2edbb23 (trunk) / 9494be7ec2a (branch_4x), LUCENE-5214 (apache/lucene#6278), 2013-10-02, first released in 4.6.0. Later changes to TopNSearcher (LUCENE-4481 dc49949558d, LUCENE-5519 803a9907d39, LUCENE-6459 be4d58c7740, LUCENE-7686 4e2cf61ac76, LUCENE-8920 760f2dbdcb2) never added the call to the branch. Not a regression.",
   "introduced_date": "2012-09-28 (f2f91bae46c, acceptResult added on the zero-output path only; first authored 2012-09-23); 2013-10-02 (FreeTextSuggester, b50a2edbb23); the branch itself 2012-02-19 (a519b630eea)",
   "first_affected_version": "4.1.0 for the root [exec]; 4.6.0 for the FreeTextSuggester symptom [exec]",
   "affected_versions": "[exec] main 645d4fe14a20 (-ea and -da: finder, the independent reproduction, the intended-behaviour check, adjudication, the cross-model refute review and the re-run); 10.6.0, released (the tag releases/lucene/10.6.0 exists and peels to 4ae946e5a9b; the independent reproduction and the history step on the published jars, the intended-behaviour check on jars built from 4ae946e5a9b, -da); 10.5.2 and 9.12.3 (JUnit, -da); 9.1.0 (finder); 8.11.4, 7.7.3, 6.6.6, 5.5.5, 4.10.4 and 4.6.0 (FreeTextSuggester ports, -da); the Util-level port fails on 4.1.0, 10.5.2, 10.6.0 and main. [read] every release in between, the branch being unchanged. Not fixed upstream: upstream main, branch_11x and branch_10_6 have no commit on Util.java or FreeTextSuggester.java after 645d4fe14a20 (checked 2026-10-29), and no open PR touches TopNSearcher. Not new in 10.6. Executed on Linux aarch64 with JDK 25 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1052.html",
   "repro": "repro/LFV-1052/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-523",
   "priority": "low",
   "priority_rank": 268,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / TokenStreamToAutomaton (core), reached through ConcatenateGraphFilter (analysis-common) and the completion suggesters (suggest: NRT document suggester, AnalyzingSuggester, FuzzySuggester)",
   "title": "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)",
   "summary": "You index the suggestion 'foo ـ bar' (a standalone Arabic tatweel between two words) with ArabicAnalyzer into a SuggestField, or build an AnalyzingSuggester or FuzzySuggester from it, and expect a lookup for 'foo' to return it next to 'foo bar', because ArabicAnalyzer turns the tatweel into an ordinary empty token and ConcatenateGraphFilter promises one output token for every path through the token graph. Instead TokenStreamToAutomaton adds a token's transitions only inside its per-byte loop, which never runs for a zero-length token, so the token's end state is unreachable: ConcatenateGraphFilter emits nothing, the document suggester indexes no entry for the value and the analyzing suggesters skip the input, so the suggestion never comes back. A stacked empty token loses only its own alternative path; nothing throws, with assertions on or off.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f2f91bae46cbc4a883324521767e4701fbbbc14a (LUCENE-3842 'add AnalyzingSuggester', mikemccand, svn r1391683 on trunk; the class was first written on the feature branch lucene3842 in 9d7873ff5a6 (r1385125, 2012-09-15) and reached branch_4x as the merge 0c89e05d765 (r1391686); JIRA patch workflow, no PR; issue #4915) [read]. Not a regression",
   "introduced_date": "2012-09-28 (trunk and branch_4x commits; the feature-branch commit is from 2012-09-15)",
   "first_affected_version": "4.1.0 [exec] (the first release with TokenStreamToAutomaton, AnalyzingSuggester and FuzzySuggester; 4.0.0 does not have them [exec]). Later consumers are affected from their own first release: the NRT document suggester from 5.1.0 and ConcatenateGraphFilter from 7.4.0 [exec]",
   "affected_versions": "4.1.0 through 10.5.2 (the last release before 10.6.0; the latest 9.x is 9.12.3) and main ea57360912ed. [exec] per-era main() probes fail on 4.1.0, 4.5.1, 4.9.1, 4.10.0, 4.10.4, 5.0.0, 5.1.0, 5.2.1, 5.3.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.4.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (4.1.0, 4.10.4, 10.5.2 and main also with -da), with every control (a non-empty middle token) passing; on 4.1.0 one added arc for the empty token (shadowed) makes the probe pass; the ConcatenateGraphFilter probe fails on 7.4.0, 8.11.4, 9.12.3, 10.5.2 and main; the finder's JUnit fails 3 of 3 on 9.12.3, 10.5.2 and main (-ea, -da); the independent reproduction's JUnit fails 7 of 10 on 9.12.3, 10.5.2 and main (-ea, -da). The visible symptom differs in two windows for reasons unrelated to this bug: on 4.10.0-4.10.4 AnalyzingSuggester/FuzzySuggester.build() throws IllegalStateException 'from state (0) already had transitions added', and on 5.1.0-5.2.1 consuming the document suggester's analysis chain throws the same exception [exec]; every other release loses the suggestion silently. [read] all 120 release tags from 4.1.0 to 10.5.2 in the history clone have the per-term loop with no zero-length case (8.8.2-8.11.4 are not tagged there; 8.11.4 was executed). Not fixed upstream: upstream main ffa9d816eeb4 has a byte-identical TokenStreamToAutomaton.java, its last change on main and the 10.x branches is the 2020 reformat, and no open PR touches it [read]. Executed only on aarch64 Linux with JDK 25 (plain Java logic)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-523.html",
   "repro": "repro/LFV-523/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1118",
   "priority": "low",
   "priority_rank": 269,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / ConcatenateGraphFilter no-separator mode, and core / util.automaton (Automaton.addEpsilon); reached from suggest (CompletionAnalyzer preserveSep=false, document suggester)",
   "title": "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)",
   "summary": "You concatenate the token graph play | thewho (spanning two positions) | who, which a multi-word synonym ('the who' => 'thewho') followed by a stop filter produces for 'play the who', with ConcatenateGraphFilter and no separator (a null tokenSeparator, or CompletionAnalyzer with preserveSep=false), and expect one token per path, 'playthewho' and 'playwho', as the class javadoc promises. With assertions disabled you get only 'playwho', so a suggestion reached through the synonym (prefix 'playth') is silently missing; with -ea the filter throws an AssertionError in Automaton.getNextTransition. The cause is Automaton.addEpsilon: it copies the transitions of a state that is still being built, and its own first addTransition to the other state sorts and shrinks that state in place mid-copy, so some transitions are copied twice and others never.",
   "impact_class": "silent wrong results",
   "introduced_commit": "46132142cc2 (branch_4x, first released in 4.10.0) and trunk merge ec2eaaafad8, 'LUCENE-5752: switch to simpler, immutable Automaton implementation' (migrated as apache/lucene#6814; a JIRA-era change, no pull request; author Michael McCandless). The code was written on the lucene5752 branch: 7339f52d921 added addEpsilon, whose body is unchanged since apart from the 2020 reformat, and c98b9a8d525 ('cutover suggesters') rebuilt AnalyzingSuggester.replaceSep as a plain Automaton filled in reverse topological order, with addEpsilon for SEP and HOLE arcs [read]. The calling pattern was carried into the document suggester by LUCENE-6339 (40e94c39ad3, first released in 5.1.0; trunk b7adb6ac770) and into ConcatenateGraphFilter by LUCENE-8332 (9b61121ffb6, 7.4.0; master f9f5e837450); LUCENE-5963 (1c2918f66d7, 5.0.0, #7025) moved only AnalyzingSuggester's copy to Automaton.Builder, for allocation reasons, which removed the defect there as a side effect [read]",
   "introduced_date": "2014-06-11 (author date of 7339f52d921 and c98b9a8d525 on the lucene5752 branch); landed 2014-06-19 on trunk (ec2eaaafad8) and 2014-06-20 on branch_4x (46132142cc2)",
   "first_affected_version": "4.10.0 for the defective Automaton.addEpsilon [exec]. By public analysis path on stock jars: CompletionAnalyzer(preserveSep=false) loses the path from 5.3.0 [exec], and ConcatenateGraphFilter without a separator from 7.4.0, its first release [exec]",
   "affected_versions": "Root-cause code in every release from 4.10.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT) [exec]. With the repro's token graph on stock jars: ConcatenateGraphFilter without a separator 7.4.0 through 10.6.0 and main [exec]; CompletionAnalyzer(preserveSep=false) 5.3.0 through 10.6.0 and main [exec], where 5.3.0-6.3.x also emit an extra wrong string from the older TokenStreamToAutomaton hole bug (fixed in 6.4.0 by 2336152fb4a) and, with -ea, fail on that bug's assertion first. Latent (code present, masked for this input on stock jars): 4.10.x AnalyzingSuggester/FuzzySuggester without PRESERVE_SEP and the 5.1.0-5.2.x document suggester [exec]. With -ea the failure is an AssertionError from 5.2.0 on (the sortedness assert came with LUCENE-5879, 7b94751e141); before that it is silent under -ea too. Releases between the executed ones were not run; their addEpsilon, finishCurrentState and replaceSep code is the same by reading. Not new in 10.6 (10.5.2 fails). Not fixed upstream: the newest commits are 86593e51b28 on Automaton.java (author date 2026-04-19, unrelated) and 36ddc378eac on ConcatenateGraphFilter.java (author date 2025-05-30, typo fixes); the only open PR touching Automaton.java (#14360) adds toMermaid() and leaves addEpsilon alone [read]. Executed on Linux aarch64 with JDK 25.0.3 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1118.html",
   "repro": "repro/LFV-1118/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-798",
   "priority": "low",
   "priority_rank": 270,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / document (NRT) suggester (SuggestField's raw-value reserved-character check vs. the analyzed form that CompletionTokenStream passes to NRTSuggesterBuilder's FST encoding)",
   "title": "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 '&#0;') hides another document's suggestion or its own and adds FST inputs out of order at flush (with assertions enabled the IndexWriter closes)",
   "summary": "You index suggestions with SuggestField through an analyzer that decodes HTML character references (HTMLStripCharFilter + KeywordTokenizer), for example 'a' (weight 1) and 'a&#0;' (weight 2), and expect a PrefixCompletionQuery 'a' with n=100 to return both documents, as it does with '&#1;'. Instead only the second document comes back; and with 'a&#0;&#0;', 'a', 'a', 'b' the commit fails with an 'inputs are added out of order' AssertionError that closes the IndexWriter when assertions are enabled, while without assertions 'a&#0;&#0;' is never found for its own value. SuggestField rejects U+0000, the byte that ends every entry in the suggester's FST, only in the raw value, so the analyzed form can still carry it and collide with that terminator.",
   "impact_class": "silent wrong results",
   "introduced_commit": "b7adb6ac7704a7e6364ee0d831bf77cf849f2090 (trunk, 'LUCENE-6339: Added Near-real time Document Suggester via custom postings format', by Areek Zillur; JIRA LUCENE-6339 = apache/lucene#7400; svn era, no pull request) and its branch_5x backport 40e94c39ad3b0f018ae9647b7d30bd0cfe341d86 (the commit in the 5.1.0 release): the commit that created the document suggester already built each FST input as analyzed bytes + END_BYTE 0x00 + dedup byte(s) (NRTSuggesterBuilder.startTerm/finishTerm) and passed the analyzed form on unchecked; the only in-band escaping it added was for the separator label U+001F [read]. The raw-value reservation of U+0000 came later with LUCENE-6459 (be4d58c7740 trunk / 380bb29f395 branch_5x, 2015-05-28, first in 5.3.0, apache/lucene#7518): it states the contract the bug breaks and narrowed it (a raw U+0000 is rejected from 5.3.0 on), but did not introduce the defect [exec]. Not a regression.",
   "introduced_date": "2015-03-27 (trunk b7adb6ac770); 2015-03-28 (branch_5x 40e94c39ad3)",
   "first_affected_version": "5.1.0 [exec]; 5.0.0 is not affected because it has no document suggester [exec]",
   "affected_versions": "every release that has the document suggester: 5.1.0 to 10.5.2, 10.6.0 (by reading) and main a9779ef3c193 (unreleased 11.0) [exec]; the releases in between by inference, the fix-site code being unchanged in substance [read]. 5.1.0-5.2.1 are wider: a raw U+0000 value is accepted too [exec]. branch_10_6 (head 2763db11b0a): CompletionTokenStream.java and NRTSuggesterBuilder.java byte-identical to main, SuggestField.java differs only in javadoc markup [read]. Not fixed upstream: main 20ced71c1e6e, branch_10x 657014b3c579 and branch_10_6 4ae946e5a9b9 have no commit on the fix-site files after a9779ef3c193, and no open PR changes the check [read]. Executed on Linux aarch64 with JDK 25 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-798.html",
   "repro": "repro/LFV-798/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-699",
   "priority": "low",
   "priority_rank": 271,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / ternary search tree suggester persistence (TSTLookup.store and load, writeRecursively and readRecursively)",
   "title": "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)",
   "summary": "You build a TSTLookup from ordinary text that contains an emoji or a CJK Extension B character (for example the key 𠮷野家 with weight 5), store() it, load() it back, and expect the reloaded copy to answer like the original, as Lookup.load promises ('load it from a previously saved copy'). Instead lookup('𠮷', true, 5) returns [] instead of [𠮷野家/5] and get('𠮷野家') returns null after the reload, because TSTLookup keeps one tree node per UTF-16 code unit, writeRecursively writes each node's split char with DataOutput.writeString of a one-char String, and a lone surrogate has no UTF-8 form, so it is written and reloaded as U+FFFD and the tree's char comparisons then take the wrong branches. ASCII keys and getCount() survive, while some BMP keys next to a surrogate node are lost too (in the finder's test lookup('Ａ') returns [] instead of [Ａb/4]).",
   "impact_class": "silent wrong results",
   "introduced_commit": "b5926da2d67820f5fdf8c8ec9b2e642b74d12070 (trunk, svn r1565810; the line released in 6.0.0 and later) and its branch_4x twin fdf4595051ada90409a47f8259a6d6e17d4711be (svn r1565811; the line released in 4.7.0-5.5.5), both 'LUCENE-5404: Add .getCount method to all suggesters (Lookup), persist count metadata on .store(), ...' by Areek Zillur (now apache/lucene#6467; an svn-era JIRA patch, no GitHub PR) [read]. It moved Lookup.store/load from java.io streams to Lucene DataOutput/DataInput and replaced the lossless DataOutputStream.writeChar(node.splitchar) / readChar() with writeString(new String(new char[] {node.splitchar}, 0, 1)) / readString().charAt(0); the issue discussion never mentions characters, so the loss is a side effect of that move, not a design choice. No later commit changed the two lines.",
   "introduced_date": "2014-02-07",
   "first_affected_version": "4.7.0 [exec] (release tag dated 2014-02-25); the last unaffected release is 4.6.1 [exec]; TSTLookup store/load existed before (since Lucene 3.3, stream API since 3.6.0) and was lossless there [exec]",
   "affected_versions": "every release from 4.7.0 through 10.5.2 and main a9779ef3c193; not fixed upstream. [exec] the follow-up's main() probe on 133 releases: 3.6.0-4.6.1 (14 releases) round-trip correctly, and all 119 cached releases from 4.7.0 to 10.5.2 lose the same 7 of 10 answers with 0 control changes (also -da on 4.6.1, 4.7.0, 9.12.3 and 10.5.2), main with -ea and -da, and main with the fix shadowed passes; the finder's JUnit fails on main (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's history probe on 4.6.1 (OK), 4.7.0, 4.10.4, 5.5.5, 8.11.4, 10.5.2 and main (CHANGED). [read] both lines are present unchanged in all 110 release tags of the history clone that contain the introducing commit and absent (writeChar/readChar) in every earlier tag; upstream main head a95c754ee003 and branch_10x still have them. All runs on JDK 25.0.3 (aarch64); the defect is pure-Java string encoding, so the platform does not matter.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-699.html",
   "repro": "repro/LFV-699/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-744",
   "priority": "low",
   "priority_rank": 272,
   "novelty": "new",
   "withheld": false,
   "area": "search / similarities (IndriDirichletSimilarity constructors and the LMSimilarity collection model)",
   "title": "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",
   "summary": "You install new IndriDirichletSimilarity(2000f) and expect the same similarity as new IndriDirichletSimilarity(), which is documented as using 'the default mu value of 2000', and Indri's Dirichlet smoothing log((tf + mu*cf/|C|)/(|D| + mu)) for any mu. Instead the mu-only constructor passes no collection model, so its implicit super() installs LMSimilarity's DefaultCollectionModel, (cf+1)/(|C|+1), while only the no-argument constructor installs the class's own IndriCollectionModel, cf/|C|. On a 25-token index the term 'president' (cf 3) scores -1.871553 instead of -2.119101 in the same document, although both instances print 'LM IndriDirichlet(2000.000000)'.",
   "impact_class": "silent wrong results",
   "introduced_commit": "9cc5c9b7983cf181280e18819f8516dc16ccf1ef (main, 2021-01-29) and a6125fb938553fe2cd8cd035b8ffb329a7a1a288 (branch_8x backport, same day, same IndriDirichletSimilarity.java blob e494bc9800d5): LUCENE-9537 'Add Indri Search Engine Functionality to Lucene' (GitHub issue apache/lucene#10577, PR apache/lucene-solr#2097 by cammiemw, merged by mikemccand). The class was added with the mu-only constructor { this.mu = mu; } (implicit super() = LMSimilarity(), DefaultCollectionModel) and the no-argument constructor this(new IndriCollectionModel(), 2000); the same constructor set is already in the PR's first commit 087d9d2a07c (2020-11-24). [read]. DefaultCollectionModel's (cf+1)/(|C|+1) dates from LUCENE-3430 (156a5c89ee8, 2011-09-12) and is unchanged since.",
   "introduced_date": "2021-01-29 (main and branch_8x)",
   "first_affected_version": "8.9.0 [exec] (the first release with IndriDirichletSimilarity; 8.8.2 has no such class, so the repro does not compile there [exec])",
   "affected_versions": "every release from 8.9.0 through 10.5.2 (the last release before 10.6.0), 10.6.0 (by reading) and main a9779ef3c193 (unreleased 11.0); never fixed. [exec] the finder's JUnit fails 2 of 2 with bit-identical values on 8.9.0, 8.11.4, 9.0.0, 9.12.1, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da); the independent reproduction's and the intended-behaviour check's tests also fail on 10.5.2 and 9.12.3. [read] the mu-only constructor is the same in every release in between (file blobs e494bc9800d5, 9f708362bb5 for 9.0.0 to 9.12.0, b3994c5dc46 for 9.12.1 to 10.5.2, 91fb1395cb1 on main; in the 8.9.0 and 9.0.0 jars IndriDirichletSimilarity(float) calls LMSimilarity.<init>()V); branch_10x and branch_10_6 have the 10.5.2 blob (not executed); upstream main f7bcc0abd816 (2026-10-27) has the main blob. Not affected: releases before 8.9.0 (no class). All runs with JDK 25 on aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-744.html",
   "repro": "repro/LFV-744/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-332",
   "priority": "low",
   "priority_rank": 273,
   "novelty": "new",
   "withheld": false,
   "area": "monitor / query index updates (WritableQueryIndex.commitWithoutNotify and populateQueryCache, reached through both Monitor.register overloads and ConcurrentQueryLoader)",
   "title": "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",
   "summary": "You register query id q twice in one call, monitor.register(List.of(new MonitorQuery(\"q\", apple OR banana), new MonitorQuery(\"q\", cherry))), as an application might when it applies a batch of query edits, and expect q to behave like one version, as it does when the two entries are registered in separate calls (the newer replaces the older). Instead the query index keeps both versions: q is reported for documents containing banana or cherry, a set that neither version matches, and getDisjunctCount is 3 for a one-clause query. With a persistent Monitor (q = apple, then q = cherry, in one call) the newer version runs until the Monitor is reopened, and from then on the older version apple runs instead while getQuery(\"q\") still returns cherry.",
   "impact_class": "silent wrong results",
   "introduced_commit": "251dbe7cea8126cb7ecadc921ba444c63d06c618 (main, 2019-06-13, 'LUCENE-8766: Add monitor subproject', by GitHub romseygeek; JIRA LUCENE-8766, migrated as GitHub issue #9811; no PR, pre-GitHub-PR era), shipped through the branch_8x commit b8773d13ad8e249a045862249bf476c30a444461 (same day). The 'delete each distinct id, then add every update' loop came with the code donated from the predecessor project Luwak (QueryIndex.commit, read, not executed). LUCENE-10422 / PR #679 (be991789564, 2022-03-21, first released in 9.2.0) moved it unchanged into WritableQueryIndex.commitWithoutNotify. [read]. Not a regression.",
   "introduced_date": "2019-06-13 (251dbe7cea8 on main and b8773d13ad8 on branch_8x)",
   "first_affected_version": "8.2.0 [exec] (first release with the monitor module); there is no unaffected earlier release: 8.1.1 has no monitor module (lucene-monitor-8.1.1 does not exist on Maven Central)",
   "affected_versions": "Every release that ships lucene-monitor from 8.2.0 to 10.5.2 (the last release before 10.6.0), and main ea57360912ed. [exec] the finder's JUnit fails 3 of 3 on 8.2.0, 8.11.4, 9.0.0, 9.1.0, 9.2.0, 9.12.3, 10.0.0, 10.2.2, 10.3.0, 10.5.2 and main (seed DEADBEEF, -ea; main also -da; 8.x and 9.0.0 ran a copy that differs only in the test-framework import); the independent reproduction's JUnit fails 4 of 6 on main (-ea and -da), 10.5.2 and 9.12.3; the follow-up's security probe fails 3 of 4 as expected on main (-ea and -da) and 10.5.2 (-da). [read] the other releases by code identity, and 8.8.2 to 8.11.3 by inference between the executed 8.2.0 and 8.11.4 (not in the history clone). From 10.3.0 on, #14885 (stable decomposition order, fixing #14886) changes which stale branch of the older version survives in the repro (banana instead of apple), not the bug. Not fixed upstream: upstream main has the same loop (checked 2026-10-26) and no open PR changes commitWithoutNotify or buildIndexables [read]. Not executed: x86, the JDK of each release's era (all runs used JDK 25.0.3; the code is plain collections and IndexWriter calls).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-332.html",
   "repro": "repro/LFV-332/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-499",
   "priority": "low",
   "priority_rank": 274,
   "novelty": "new",
   "withheld": false,
   "area": "monitor / query index updates (WritableQueryIndex.commitWithoutNotify failure atomicity, reached through both Monitor.register overloads)",
   "title": "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",
   "summary": "You update stored queries with Monitor.register and IndexWriter rejects one of the new query documents, for example register(q2 = f:y) where q2 carries a 40,000-byte value in a TermFilteredPresearcher filter field, so register() throws IllegalArgumentException. You expect the queries of the call to keep their old versions, as they do when the Monitor rejects a query before writing and as IndexWriter.updateDocuments would guarantee for each id. Instead the Monitor has already queued the deletion of the old version of every query id in the call and switched its in-memory cache to the new versions: right away q2 matches nothing although getQuery(\"q2\") still returns f:b, and the next unrelated register or deleteById, or close() of a persistent Monitor, deletes the old versions for good (register(q2 rejected, q1 valid), then close and reopen, leaves neither q1 nor q2).",
   "impact_class": "data corruption",
   "introduced_commit": "251dbe7cea8126cb7ecadc921ba444c63d06c618 (main, 2019-06-13, 'LUCENE-8766: Add monitor subproject', by GitHub romseygeek), with the branch_8x twin b8773d13ad8e249a045862249bf476c30a444461 (same message and time); submitted as apache/lucene-solr#648, which GitHub shows closed unmerged with 'This has been merged.' because the code was committed directly; JIRA LUCENE-8766 (migrated as #9811). It added QueryIndex.commit with the delete-every-id-first, cache-put-before-addDocument, no-rollback sequence. LUCENE-10422 / #679 (be991789564, first released in 9.2.0) moved the body verbatim into WritableQueryIndex.commitWithoutNotify. [read]. Not a regression. The loop came with the code donated from the predecessor project Luwak, where the fix of flaxsearch/luwak#68 (luwak 18fc644, 2015) moved the deletes into commit() and so created it [read].",
   "introduced_date": "2019-06-13 (251dbe7cea8 on main and b8773d13ad8 on branch_8x)",
   "first_affected_version": "8.2.0 [exec] (the first lucene-monitor release, tagged 2019-07-25); there is no unaffected earlier release: 8.1.1 has no monitor module (lucene-monitor 8.1.1 is not on Maven Central, HTTP 404, and the portable repro does not compile against 8.1.1)",
   "affected_versions": "Every release that ships lucene-monitor, 8.2.0 to 10.6.0 (10.6.0 by reading), plus main ea57360912ed, branch_10x and branch_10_6. [exec] the follow-up's portable public-API repro (3 filter-field checks, 1 I/O check, 2 controls) fails 4 of 6 with both controls passing on 8.2.0 (-ea and -da), 8.11.4, 9.0.0, 9.1.0, 9.2.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the finder's JUnit fails 3 of 3 and its I/O test 1 of 1 on main (-ea and -da), 10.5.2, 10.0.0, 9.12.3 and 9.2.0 (9.1.0: the filter-field test only, 3 of 3); the independent reproduction's JUnit fails 5 of 6 on main (-ea and -da), 10.5.2 and 9.12.3, and 4 of 5 on 8.11.4 (import-adapted, I/O test not run; two checks fail there through the pre-9.9.0 NullPointerException of getQuery() on a deleted id, GITHUB#12736). [read] the whitespace-stripped method body is identical in 54 refs: both introducing commits, every release tag 8.2.0-8.8.1, every 9.x and 10.x release tag, origin/branch_10_6 2763db11b0a, origin/branch_10x 1309534296e, origin/main a9779ef3c19 (2026-10-26) and a Lucene main checkout; 8.8.2 to 8.11.3 by bytecode (the same call sequence as 8.2.0). Not fixed upstream (2026-10-26): no open PR changes commitWithoutNotify. Not executed: x86, and the JDK of each release's era (all runs used JDK 25.0.3; the code is plain collections and IndexWriter calls).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-499.html",
   "repro": "repro/LFV-499/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-501",
   "priority": "low",
   "priority_rank": 275,
   "novelty": "new",
   "withheld": false,
   "area": "monitor / query index updates (WritableQueryIndex.deleteQueries and clear versus commitWithoutNotify, reached through Monitor.deleteById, Monitor.clear and Monitor.register)",
   "title": "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",
   "summary": "One thread registers query q = a OR b OR c, which the Monitor indexes as three parts, one per clause, while another thread calls monitor.deleteById(\"q\") or monitor.clear(); you expect the two calls to take effect in some order, so that afterwards q is either fully registered or gone. Instead the delete goes to the IndexWriter without the commit lock that register holds, lands between register's per-part addDocument calls and removes only the parts already added. q is still reported as registered with its full query, getDisjunctCount is 2, and a document that contains only 'a' no longer matches, also after the Monitor is closed and reopened.",
   "impact_class": "silent wrong results",
   "introduced_commit": "251dbe7cea8126cb7ecadc921ba444c63d06c618 (master, 'LUCENE-8766: Add monitor subproject', by GitHub romseygeek; JIRA LUCENE-8766, no GitHub PR, pre-GitHub-PR era; first released in 9.0.0), shipped first through the same-day branch_8x backport b8773d13ad8e249a045862249bf476c30a444461 (8.2.0) [read]. The unlocked deletes came with the code donated from the predecessor project Luwak, whose commit 18fc644 (2015, luwak#68) had moved only update()'s delete into the synchronized commit. Not a regression",
   "introduced_date": "2019-06-13 (both commits)",
   "first_affected_version": "8.2.0 [exec] (first release with the monitor module; 9.0.0 is the first 9.x release); there is no unaffected earlier release: 8.1.1 has no monitor module (no lucene-monitor-8.1.1 artifact on Maven Central)",
   "affected_versions": "Every release that ships lucene-monitor, 8.2.0 to 10.6.0 (10.6.0 by reading), and main ea57360912ed. [exec] the finder's pinned JUnit (deleteById, seed DEADBEEF, -ea) fails on 8.2.0 (10 of 10 iterations), 8.11.4, 9.0.0, 9.1.0, 9.2.0, 9.8.0, 9.9.0, 9.12.3, 10.0.0, 10.5.2 and main (8.x and 9.0.0 ran a copy that differs only in the LuceneTestCase import), main also with -da (20 of 20 iterations) and with the registration check's fresh seeds; the independent reproduction's hook-free stress JUnit (64-part disjunction, -da, 400 races per method) leaves partial queries for both deleteById and clear on 8.2.0 (20 and 28 of 400), 9.12.3 (16 and 28), 10.5.2 (18 and 29; the independent reproduction's own run 15 and 24) and main (the independent reproduction 25 and 23, adjudication 19 and 31, registration check 15 and 27). [read] the other releases by code identity, and 8.8.2-8.11.3 by inference between 8.8.1 (same source) and the executed 8.11.4 (the 8.x branch is not in the history clone). Before 10.3.0 the decomposition order depends on the hash seed (#14885 made it stable), which changes which parts survive in the pinned repro (b only instead of b and c) and could let the pinned repro pass on those releases with another seed; the order-independent stress test fails there. clear() was executed only through the stress tests. Not fixed upstream: upstream main and branch_10_4 still issue the deletes before taking commitLock, and no open PR changes deleteQueries or clear (2026-10-26) [read]. Not executed: x86, and each release's own JDK (all runs used JDK 25.0.3)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-501.html",
   "repro": "repro/LFV-501/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-779",
   "priority": "low",
   "priority_rank": 276,
   "novelty": "new",
   "withheld": false,
   "area": "index / index sorting at merge time (IndexSorter.IntSorter merge keys, MultiSorter) -> search / TopFieldCollector index-sort early termination",
   "title": "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)",
   "summary": "You configure an index sort on SortField(\"s\", SortField.Type.INT), index documents with NumericDocValuesField(\"s\", value), one of them with a value that does not fit in an int (for example 2^32, whose int value is 0), and let segments merge, expecting the merged segment to be sorted the way a flushed segment of the same documents is. Flush (IntSorter#getDocComparator), the search-time IntComparator and CheckIndex all compare (int) of the value, but the merge key (IntSorter#getComparableProviders) is the full long, so forceMerge(1) of the segments [a = 2^32] and [b = 1, c = 2] writes the order b, c, a instead of a, b, c. CheckIndex (level 2 or higher) then reports 'segment has indexSort=<int: \"s\"> but docID=1 sorts after docID=2' and a top-1 search sorted by the index sort returns b instead of a, while before the merge the same index is clean and returns a.",
   "impact_class": "data corruption",
   "introduced_commit": "17f2f96a5cf8e0001a81b9327c2ddced053e6934 on master and its branch_8x backport aad4b411cdd2d517328a2444147b407d4a38343d, 'LUCENE-8900: Simplify MultiSorter.' (JIRA LUCENE-8900, migrated as apache/lucene#9943; a patch on the JIRA issue, no pull request; by jpountz, +1 from danmuzi). It moved 'case INT:' under 'case LONG:' in MultiSorter#getComparableProviders and deleted the INT branch that returned (int) values.longValue(). LUCENE-9330 (8.6.0, apache/lucene-solr#1440) then moved the code unchanged into IndexSorter.IntSorter#getComparableProviders, and LUCENE-9570 (2d6ad2fee6d, formatting only) is what git blame shows for IndexSorter.java:228 on main. The merge-time (int) narrowing dates from the first index-sort merge code (LUCENE-6766, 6.2.0) and was kept by LUCENE-8592 (7.6.0). [read] [exec]",
   "introduced_date": "2019-07-09",
   "first_affected_version": "8.2.0 [exec] (the first release with LUCENE-8900). 8.1.1, the last release before it, passes [exec], as do 6.2.0 (the first release with IndexWriterConfig#setIndexSort), 6.6.6, 7.0.0, 7.7.3, 8.0.0 and 8.1.0 [exec]",
   "affected_versions": "every release from 8.2.0 through 10.6.0 (8.2.x to 8.11.x, all of 9.x and 10.x; 10.6.0 by reading) and main a9779ef3c193 and 645d4fe14a2 [exec]; branch_10x and branch_10_6 (10.6.0, released 2026-10-29) carry the same line [read]. Executed (JDK 25, -ea unless stated): the follow-up's runs fail on 8.2.0, 8.6.0, 8.9.0, 8.10.1, 8.11.4, 9.0.0, 9.5.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) and pass on 6.2.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.1.0 and 8.1.1; the finder's JUnit also fails on 8.5.2; the independent reproduction's JUnit fails on main (-ea, -da), 10.5.2 and 9.12.3; the intended-behaviour check reproduced on main (-ea, -da) and 10.5.2 (-da). On 8.2.0 and 8.10.1 CheckIndex records the index-sort error but still reports clean=true (probe), while 8.11.4 and 9.x report clean=false; the wrong order and the wrong top hit are there in all of them. Inferred only (not tagged in the local clone, between failing releases on the same branch): 8.8.2, 8.10.0, 8.11.0 to 8.11.3. Not fixed upstream: upstream main 645d4fe14a2 (2026-10-29), branch_10x 657014b3c57 and branch_10_6 4ae946e5a9b still return values.longValue() at IndexSorter.java:228, and no open PR touches IndexSorter.java [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-779.html",
   "repro": "repro/LFV-779/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1037",
   "priority": "low",
   "priority_rank": 277,
   "novelty": "new",
   "withheld": false,
   "area": "search / sorting (SortField STRING_VAL, SortedSetSortField and KeywordField.newSortField missing values; index sorting)",
   "title": "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')",
   "summary": "You build a string sort with a missing value that is not STRING_FIRST or STRING_LAST, for example new SortedSetSortField(\"tag\", false, SortedSetSelector.Type.MIN, \"zzz\") or the same through KeywordField.newSortField, much as you would give a numeric sort field a substitute value. You expect an IllegalArgumentException when the sort field is built, as new SortField(f, Type.STRING, false, \"zzz\") throws and as the removed setMissingValue threw for these sorts too. Instead the value is accepted (getMissingValue() and toString() report it) but every comparator treats it as STRING_FIRST, so documents without a value silently sort first; and if the sort is the index sort, the segment is written without the value, so the next new IndexWriter with the very same config refuses the index with 'cannot change previous indexSort'.",
   "impact_class": "wrong error",
   "introduced_commit": "75108f430664 (apache/lucene#15483 'Deprecate SortField.setMissingValue()', by romseygeek, author date 2025-12-08, approved by benwtrent; branch_10x backport 202f206c2f97 of the same PR, first release 10.4.0) [read]; on main f4f6d70c0c4c (#15486, 2025-12-09) then removed the rejecting setters, so nothing rejects such values there; the lost index-sort value comes from SortedSetSortField.serialize (de2bad903905, LUCENE-9330, 9.0.0), which writes 'no missing value' for anything but the sentinels and was latent until 10.4.0",
   "introduced_date": "2025-12-08",
   "first_affected_version": "10.4.0 [exec]",
   "affected_versions": "10.4.0 [exec], 10.5.0 and 10.5.1 [read], 10.5.2 [exec], 10.6.0 RC1 4ae946e5a9b (released as 10.6.0 on 2026-10-29, the latest release) [exec], branch_10x 657014b3c579 [exec], main from 75108f430664 (2025-12-08) through 645d4fe14a20 [exec]; on 10.4.0-10.6.0 the deprecated setMissingValue still rejects the value [exec], so only code that moved to the constructors is affected; on main the constructors are the only way to set a missing value; not affected: every release up to 10.3.2 [exec]; upstream main HEAD 2a32d42e5e85 (2026-10-29) has no later commit on SortField.java, SortedSetSortField.java or KeywordField.java [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1037.html",
   "repro": "repro/LFV-1037/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1141",
   "priority": "low",
   "priority_rank": 278,
   "novelty": "known",
   "withheld": false,
   "area": "core / kNN vector queries (COSINE)",
   "title": "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",
   "summary": "You index COSINE vectors and search with an all-zero query vector, which KnnFloatVectorField would reject ('zero vector not allowed with cosine similarity function'). You expect the query to be rejected too, or to return valid COSINE scores in [0, 1]. Instead it is accepted and scores NaN against every document: similarity queries and exact-search segments return no hits, an unfiltered kNN search returns the HNSW entry document of each graph-searched segment with score NaN, and with assertions enabled VectorUtil.cosine's isFinite assertion fails.",
   "impact_class": "silent wrong results",
   "introduced_commit": "#366 (f4861159c3c, COSINE kNN): latent since then [read]; the field/query asymmetry since #15751 (c592f384aa5, 2026-02-23; 10.5.x as 4e00bd9127d), which validates only indexed vectors [read]",
   "introduced_date": "2021-10-11 (COSINE); 2026-02-23 (#15751, field side only)",
   "first_affected_version": "9.0.0 [read]; executed from 9.6.0, the oldest release run (KnnFloatVectorQuery exists from 9.5.0, KnnVectorQuery before it)",
   "affected_versions": "main 5adff78bb168 (-ea, and -da with three seeds), 10.6.0 (4ae946e5a9b, -ea and -da), 9.12.3 and 9.6.0 (-da) [exec]; 9.0.0-9.5.0 [read]. On 10.4.0+ the default HNSW format builds no graph for segments under about 648 vectors (HNSW_GRAPH_THRESHOLD, [read]), so such segments take exact search and return no hits; 9.x tiny segments return the NaN hit [exec].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15540",
    "https://github.com/apache/lucene/issues/15751",
    "https://github.com/apache/lucene/issues/16098",
    "https://github.com/apache/lucene/issues/16099",
    "https://github.com/apache/lucene/issues/12281",
    "https://github.com/apache/lucene/issues/16965"
   ],
   "doc": "",
   "repro": "repro/LFV-1141/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-467",
   "priority": "low",
   "priority_rank": 279,
   "novelty": "new",
   "withheld": false,
   "area": "search / vector similarity-threshold queries (ExplicitVectorSimilarityCollector with the exhaustive scan and the HNSW graph search)",
   "title": "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",
   "summary": "You index vectors with the default codec and run FloatVectorSimilarityQuery.Explicit(field, target, 1.0f) on main or 10.5.2 (the plain FloatVectorSimilarityQuery(field, target, 1.0f) on 9.10.0-10.4.0), which sets traversalSimilarity = resultSimilarity, to find every exact copy of target under EUCLIDEAN, and you expect every document with similarity >= 1.0, as collect() ('similarity >= resultSimilarity'), explain() ('Score above threshold') and the query's own exact fallback all count them. Instead only the first copy comes back: a 65-vector segment with copies at doc 0 and doc 64 returns [0] and count() 1, the same query with a MatchAllDocsQuery filter returns [0, 64], a 4,000-vector HNSW segment returns 1 of its 12 copies, and a traversalSimilarity one ulp lower returns all of them (byte vectors at an exact 0.5 behave the same). Once a hit at the threshold is collected, ExplicitVectorSimilarityCollector.minCompetitiveSimilarity() = min(traversalSimilarity, maxSimilarity) equals the inclusive result threshold, and both the exhaustive scan (a 64-vector batch is collected only if its best score > minCompetitiveSimilarity()) and the graph search (score >= nextUp(minCompetitiveSimilarity())) treat an equal score as not competitive; the one-line fix returns min(nextDown(traversalSimilarity), maxSimilarity).",
   "impact_class": "silent wrong results",
   "introduced_commit": "cd195980ecbcb45e19ce9465854fed0b6be79ea7 on main (GITHUB#12679 'Add support for similarity-based vector searches' by kaivalnp, merged 2023-12-11) and its branch_9x backport 8089b8c9d3374dc4d451a4280daae85e0b139b84, first released in 9.10.0 [read]: the new collector kept similarity >= resultSimilarity but reported min(traversalSimilarity, maxSimilarity) as minCompetitiveSimilarity, and the 3/4-argument constructors passed resultSimilarity as traversalSimilarity (a default the author proposed in the PR on 2023-11-30), while #12770 (e1ce1d692ca4, merged 2023-11-07 during that review, released in 9.9.0) had already made HnswGraphSearcher's level-0 neighbour test strict ('>'), so the code was defective the day it merged. Not adapted when #15021 (0421a8de771e, 10.4.0) added the exhaustive-scan batch gate 'max > minCompetitiveSimilarity()', and #14963 (4a7c9c2780b, 10.4.0) stopped building graphs for small segments, so that gate became the normal path for them. Gone in 10.5.0 (#15784, be2af1e7b43: the plain constructors use the adaptive collector) and restored verbatim in 10.5.2 by #16654 (bc9adc96cc58 on main, 2026-09-13; backport #16671 5caef2a1fda9) as the deprecated ExplicitVectorSimilarityCollector behind [Byte|Float]VectorSimilarityQuery.Explicit [read]",
   "introduced_date": "2023-12-11 (main cd195980ecbc, #12679); reintroduced 2026-09-13 (main bc9adc96cc58, #16654; backport #16671, released in 10.5.2)",
   "first_affected_version": "9.10.0 [exec] (the release that added the query; 9.9.0 and 9.9.2 have no FloatVectorSimilarityQuery [exec]); 10.5.0 and 10.5.1 are not affected [exec] and 10.5.2 is affected again [exec]",
   "affected_versions": "9.10.0, 9.11.0, 9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2 and 10.4.0 through the plain 3/4-argument constructors, and 10.5.2 and main ea57360912ed through the deprecated Explicit 3/4-argument constructors (and the 5-argument form with equal values) [exec]; not affected: 10.5.0 and 10.5.1 (adaptive collector, no Explicit class) [exec], before 9.10.0 the API does not exist [exec]. Path by era [exec]: 9.10.0-10.3.2 drop the tie in the HNSW graph search (the 65-vector repro segment has a graph there); from 10.4.0 a segment below the graph threshold has no graph and the exhaustive scan's batch gate drops it, while larger segments still drop ties in the graph search [exec]. Float16VectorSimilarityQuery has no Explicit variant and the Adaptive queries are not affected [read]. Upstream main 49483e82b357 (unreleased) and branch_10_6 still have the code, so the released 10.6.0 (2026-10-29) has it [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-467.html",
   "repro": "repro/LFV-467/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-429",
   "priority": "low",
   "priority_rank": 280,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter merge-time reordering (OneMerge#reorder guard; misc BPReorderingMergePolicy)",
   "title": "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'",
   "summary": "You have an index with document blocks (children followed by their parent, added with IndexWriter#addDocuments) that was written by Lucene 9.8 or earlier, open it with a current Lucene, and force-merge it through BPReorderingMergePolicy. You expect the merge to leave the blocks alone, because since 9.11 IndexWriter lets a merge reorder documents only when there are no blocks or a parent field identifies them, and such an old index cannot have a parent field. Instead the guard trusts LeafMetaData#hasBlocks, which was never recorded before 9.9 and reads false for those segments, so the reorderer renumbers the documents one by one and interleaves the blocks, with no exception and a clean CheckIndex, while the same documents written by 9.9.2 are left intact.",
   "impact_class": "data corruption",
   "introduced_commit": "4a3f4cfe9745 on main and 2e503b657549 on branch_9x (#13128 'Make OneMerge#reorder preserve blocks', by jpountz), which added today's guard hasBlocksButNoParentField = anyMatch(LeafMetaData::hasBlocks) && (some leaf has no parent field) [read]. The reorder hook itself came earlier with #12622 ('Add a merge policy wrapper that performs recursive graph bisection on merge', jpountz; 6b1538b33136 on branch_9x, f7cab1645017 on main), which called OneMerge#reorder with no block check at all, so the pre-9.9 damage starts there [exec]. The 'not recorded before 9.9.0' caveat of hasBlocks comes from #12685 (s1monw; 26043819a5b1 on branch_9x, 6677109ee608 on main), four months before the guard. No commit-level bisect: release-level runs plus git ancestry pin both boundaries",
   "introduced_date": "2023-11-23 (#12622 merged; first released in 9.9.0, 2023-12-04); 2024-03-29 (#13128 merged, the incomplete guard; first released in 9.11.0, 2024-06-06); both first reached main-line releases in 10.0.0 (2024-10-14)",
   "first_affected_version": "9.9.0 [exec]; read as a gap in the #13128 guard, 9.11.0 [exec]",
   "affected_versions": "all 22 releases from 9.9.0 to 10.5.2 and main ea57360912ed [exec]; forceMerge and addIndexes(CodecReader...) both break blocks written by 9.0.0 and by 9.8.0 on 9.9.0-10.5.2 and main, and forceMerge breaks blocks written by 8.11.4 on 9.10.0, 9.11.0 and 9.12.3 [exec]; 10.0.0 and later cannot open 8.x indexes, so 8.x-written segments matter only on 9.9.0-9.12.3; not affected: 9.8.0 and earlier, which have no reordering-merge API (the JUnit does not compile on 9.8.0) [exec]; main 645d4fe14a2 [exec]; branch_10x 657014b3c57 and branch_10_6 4ae946e5a9b (10.6.0, released 2026-10-29) have the same guard files [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-429.html",
   "repro": "repro/LFV-429/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-471",
   "priority": "low",
   "priority_rank": 281,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter sequence numbers (tryDeleteDocument, tryUpdateDocValue vs commit)",
   "title": "tryDeleteDocument / tryUpdateDocValue running while commit() flushes returns a sequence number above the commit's, yet its change is in that commit",
   "summary": "You call tryDeleteDocument or tryUpdateDocValue with an NRT reader while another thread is inside commit(), after the commit has fixed its sequence number and before it snapshots its segments. You expect what the commit javadoc promises ('All sequence numbers <= this value will be reflected in the commit, and all others will not'): a change whose returned number is above the commit's is not in that commit. Instead the call returns the commit's number plus one (8 against 7), yet the delete or doc-values update is already in the commit point, while deleteDocuments(Term), deleteDocuments(Query) and updateNumericDocValue(Term) in the same window get 8 too and correctly stay out.",
   "impact_class": "silent wrong results",
   "introduced_commit": "7ee1f422458 (branch_6x; the same change is e4a21330a20 on the sequence_numbers branch, identical patch-id, merged to master in b1fb142af00): LUCENE-7302 = apache/lucene#8356 (mikemccand), 'cutover all IW APIs that change the index to return seq no', changed tryDeleteDocument from boolean to long and returned the current delete queue's next number with no coordination with the full flush that fixes commit()'s number [exec]. The violated javadoc (commit/prepareCommit @return) was added three days later in the same series (5361d67996a), before any release. tryUpdateDocValue: LUCENE-8297 = apache/lucene#9344 (s1monw), 48a2138e899 (branch_7x) / b0b32931b28 (master), which added the method with the same behaviour and moved both bodies into the shared tryModifyDocument, the fix site on main [exec]",
   "introduced_date": "2016-05-24 (author date of 7ee1f422458 / e4a21330a20; on master 2016-06-05 via b1fb142af00; on branch_6x 2016-06-11); tryUpdateDocValue: 2018-05-05 (committed 2018-05-07)",
   "first_affected_version": "6.2.0 [exec] for tryDeleteDocument (6.0.0, 6.0.1 and 6.1.0 cannot express the scenario: no sequence numbers, the probe does not compile); 7.4.0 [exec] for tryUpdateDocValue, the release that added it",
   "affected_versions": "tryDeleteDocument: all 89 releases from 6.2.0 through 10.5.2 [exec] and main ea57360912ed [exec]; tryUpdateDocValue: all 67 releases from 7.4.0 through 10.5.2 [exec] and main; also with -da on 6.2.0, 7.4.0, 9.12.3 and 10.5.2 [exec]; 199 executed history runs, controls pass in every one. Not fixed upstream: upstream main 49483e82b357 (2026-10-26) has IndexWriter.java byte-identical to the tested tree [read]. The NRT-reopen variant was not tested and is not claimed",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-471.html",
   "repro": "repro/LFV-471/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-590",
   "priority": "low",
   "priority_rank": 282,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter forced merge (forceMerge wait loop, mergeExceptions and mergeGen, tragic events)",
   "title": "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",
   "summary": "You call forceMerge(1) while a background merge started by an earlier commit or flush (or by forceMerge's own flush) is still pending or running, and that merge fails, for example because the disk is full. You expect forceMerge to throw, as it does ('background merge hit exception') when the failing merge is one it registered itself. Instead it can return normally with the index still unmerged (2 segments, or 9 with the default TieredMergePolicy): the adopted merge keeps its old mergeGen, so its failure is dropped, and the tragic event that closes the writer is published only after mergeFinish has woken the waiting call.",
   "impact_class": "wrong error",
   "introduced_commit": "299d6357dd296f87a099fadd0764292b28dbde47 'LUCENE-845, LUCENE-847, LUCENE-870: factor MergePolicy & MergeScheduler out of IndexWriter, improve overall concurrency of IndexWriter, and add ConcurrentMergeScheduler' (Subversion r576798, by mikemccand; pre-GitHub, no PR), which added mergeGen, the addMergeException generation filter, resetMergeExceptions and the optimize() loop that marks pending and running merges as its own without updating their mergeGen [read]. LUCENE-6579 (branch_5x aaf1c49b6097, trunk 926397824e9f; released in 5.3.0) made merge failures tragic and calls tragicEvent after mergeFinish; that turned the deterministic false success into a race (it narrowed the defect, it did not introduce it).",
   "introduced_date": "2007-09-18",
   "first_affected_version": "2.3.0 [exec]; 2.2.0 has no background merges [exec]",
   "affected_versions": "every release from 2.3.0 through 10.6.0 (10.6.0 by reading), including 9.12.3 (the latest 9.x), and main a9779ef3c193; the previous hunt main ea57360912ed too [exec]; never fixed. [exec] 2.3.0 and 5.2.1: deterministic false success with the writer left open (5.2.1: 5/5 without any hold); 5.3.0, 6.6.6, 7.7.3, 8.5.2, 9.12.3, 10.5.2 and main: forceMerge returns normally and the tragedy closes the writer right after (deterministic with an InfoStream hold; without it 6/10 on 5.3.0 and 3/10 on main); the own-merge control passes on 2.3.0, 5.2.1, 5.3.0, 9.12.3, 10.5.2 and main. [exec] 8.6.0, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main (-ea and -da) each 4 run / 3 fail with the control passing; the independent reproduction and the intended-behaviour check repeated this on main, 10.5.2 and 9.12.3, the cross-model review on main and 10.5.2. [read] 2.4.0, 2.9.2, 3.0.1, 3.6.2, 4.0.0 and 4.10.4 have the same lines. IndexWriter.java is unchanged on upstream main (a95c754ee003), branch_10x and branch_10_6 since #16581 (2026-09-21), which does not touch these lines.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-590.html",
   "repro": "repro/LFV-590/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-838",
   "priority": "low",
   "priority_rank": 283,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter doc-values updates (BinaryDocValuesFieldUpdates value buffer, FrozenBufferedUpdates apply, applyUpdatesPacket tragic close)",
   "title": "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)",
   "summary": "You commit 2,100 documents that share the term group:g, add one more document, call updateBinaryDocValue(group:g, field, a 1 MiB value) once and commit; the javadoc sets no size limit and says the value replaces the value of all affected documents, and the resulting 2.1 GB of binary doc values is an index Lucene can hold (a build with the fix sketch commits it). Instead, applying the update appends a full copy of the value for every matched document to one int-addressed BytesRefBuilder, which overflows at 2^31 bytes: commit throws ArrayIndexOutOfBoundsException (with -ea, AssertionError 'size must be positive (got -2147483648): likely integer overflow?'), IndexWriter treats it as a tragic event and closes itself, and both the update and the extra uncommitted document are gone. On 7.7.0 and later a lone update fails at half that size (1,100 documents x 1 MiB) because of the linked bug that applies the first update of a field twice, and ordinary value sizes suffice too (530,000 documents x 4 KiB).",
   "impact_class": "crash",
   "introduced_commit": "c5263086b4da47ae0331678f1ec64dc1e7e3577b (trunk, svn r1578784) and its branch_4x backport 019b0c879cb (svn r1578790, the commit that shipped in 4.8.0), 'LUCENE-5513: add IndexWriter.updateBinaryDocValue' (committed from a JIRA patch, no GitHub PR; issue now apache/lucene#6576; author shaie, reviewed in the issue by mikemccand) [read] [exec]. Two later changes altered the consequence, not the defect: 58105a203a1 (LUCENE-7868, #8919, 2017-06-21, 7.0.0) made an apply failure a tragic event, so the writer closes instead of staying open but stuck [exec]; b0e6a92ede3 / eaf840867fa (LUCENE-8590, #9636, 2018-12-04, 7.7.0) applies the first update of a field in a packet twice, halving the threshold [exec]",
   "introduced_date": "2014-03-18 (author and commit date of c5263086b4d, 08:56 UTC, and 019b0c879cb, 09:25 UTC)",
   "first_affected_version": "4.8.0 [exec] (the release that introduced updateBinaryDocValue; 4.7.2 has no such API [exec]); 4.8.0-6.6.6 leave the writer open but stuck (every later commit and close() throw, close() rolls back) [exec]; the writer closes itself from 7.0.0 [exec]",
   "affected_versions": "every release with binary doc-values updates, 4.8.0 through 10.6.0 (10.6.0 by reading), and main a9779ef3c193 [exec]; the other releases by tag ancestry and an identical class blob across 7.4.0-8.8.1 and across 9.12.3, 10.0.0-10.5.2 and main [read]; 8.8.2-8.11.3 are not in the history clone and are inferred; not fixed upstream: upstream main 20ced71c1e6e, branch_10x and branch_10_6 have the same BinaryDocValuesFieldUpdates.java blob, last changed 2022-11-15 [read], so the released 10.6.0 has it too. All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-838.html",
   "repro": "repro/LFV-838/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1077",
   "priority": "low",
   "priority_rank": 284,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter delete queue (DeleteSlice of an idle DocumentsWriterPerThread, flush-by-RAM on pure deletes)",
   "title": "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)",
   "summary": "You add a document to an IndexWriter with the default config and then, without a commit, NRT reopen or flush(), send a long stream of deleteDocuments(Term) or doc-values update calls, and expect the heap held by those buffered deletes to stay around the RAM buffer, because the writer applies and drops them each time they reach it, as it does when nothing is buffered. Instead the in-memory segment that holds the one document keeps a pointer into the shared delete queue that moves only when that segment indexes again or is flushed, so every later delete stays reachable after it was applied. IndexWriter.ramBytesUsed() does not count it, nothing flushes that segment, and the heap grows with every call until OutOfMemoryError. The same happens without any delete-only run when two threads indexed at once and then one thread keeps calling updateDocument: the second in-memory segment stays idle and pins every later delete term until the active segment fills the RAM buffer and is flushed.",
   "impact_class": "crash",
   "introduced_commit": "2a969f828c1b65d81f0e630188dd8244694765b9 (trunk landing of per-thread writers, LUCENE-3023 'Land DWPT on trunk', Subversion trunk r1098427, a merge commit by Uwe Schindler; LUCENE-3023 = apache/lucene#4097; svn era, no pull request) [exec]. The mechanism (DocumentsWriterDeleteQueue with a per-DWPT DeleteSlice whose head an idle writer never advances, and the class javadoc that relies on the GC to prune the list) came from e95097a7c8dfc042c09288717822768c6011f5e8, LUCENE-2956 'Support updateDocument() with DWPTs' (apache/lucene#4030) by Simon Willnauer on the realtime_search branch [read]. A 4.0 regression relative to 3.x, not a recent one.",
   "introduced_date": "2011-05-01 (2a969f828c1, author and commit date 2011-05-01T22:38:33Z, landing on trunk); mechanism e95097a7c8d authored 2011-04-13T09:20:39Z",
   "first_affected_version": "4.0.0-ALPHA [exec]; first GA release 4.0.0 [exec]; not affected: 3.6.2 and every earlier release, which have no per-thread writers [exec]",
   "affected_versions": "every release from 4.0.0-ALPHA through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 645d4fe14a20 (unreleased 11.0) [exec]; the releases in between by git tag --contains 2a969f828c1 (124 release tags, plus the 8.8.2-8.11.4 releases of the separate lucene-solr branch_8x) and a log of every later commit that touches the slice code (refactors only, each followed by an executed failing release) [read]. Not new in 10.6 (10.5.2 fails the same test). Not fixed upstream: upstream main e1faeba08bde (2026-11-02) changes the fix-site files only by #16867 (2813efa40a3, author date 2026-10-30), which caps the global delete buffer at 1945 MB and stalls indexing during a full flush; it does not touch DeleteSlice, the idle per-thread writer or ramBytesUsed() [read]. Executed on Linux aarch64 with JDK 25 only. The updateDocument trigger (2026-11-02, -da, 1.5M calls, -Xmx256m, default 16 MB buffer): main e1faeba08bd 163 MiB vs control 14 MiB, 10.6.0 157 vs 8, 9.12.3 157 vs 8, 8.11.4 157 vs 7 [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1077.html",
   "repro": "repro/LFV-1077/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-981",
   "priority": "low",
   "priority_rank": 285,
   "novelty": "new",
   "withheld": false,
   "area": "core / index (ParallelLeafReader and ParallelCompositeReader index-sort metadata, LeafMetaData.sort; consumers: TopFieldCollector early termination, Sort.getPrimarySortField range shortcuts, IndexWriter.addIndexes(CodecReader...))",
   "title": "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",
   "summary": "You keep a main index sorted on a long field s and a sidecar index with the same documents in the same order that re-indexes s with new values (docs 0-3 get 100-103), open them as new ParallelLeafReader(sidecar, main), and expect the reader either to stop claiming the sort or to reject the combination, as it already does for two different sorts, because the first reader that has a field serves it and the sidecar is not sorted. Instead it reports main's sort <long: \"s\"> in getMetaData() while it serves s = 100, 101, 102, 103, 4, 5, ...: a top-3 search sorted by s returns docs 0, 1, 2 (s = 100-102) instead of 4, 5, 6, IndexSortSortedNumericDocValuesRangeQuery s:[0 TO 9] counts 10 instead of 6, a range query on a skip-indexed s finds 0 instead of 6, and ParallelCompositeReader behaves the same. IndexWriter.addIndexes(SlowCodecReaderWrapper.wrap(reader)) into an index sorted on s accepts the reader and writes the documents in that order under indexSort=<long: \"s\">, a segment that CheckIndex level 2 rejects ('docID=3 sorts after docID=4') and that survives forceMerge.",
   "impact_class": "data corruption",
   "introduced_commit": "54fa7dfd271f7fe3bc8da2cfcd165e21e76e1804 ('LUCENE-6766: initial patch', Mike McCandless; JIRA LUCENE-6766 'Make index sorting a first-class citizen', migrated as GitHub #7824; patch workflow, no PR) [read]: it gave ParallelLeafReader an index sort, the first non-null sub-reader sort, without asking which sub-reader serves the sort field (the 'first reader having a given field wins' rule dates from ParallelReader, b68ae2ef265, 2005, and was carried into today's class by 6188bc66d7d, LUCENE-3736, 2012). Follow-up 8361de87becd ('fix parallel reader's detection of conflicting index sort', 2016-05-10) set today's rule (null sorts allowed anywhere, two different non-null sorts rejected); master merge d715210467a (2016-05-13); branch_6x backports fdc220eeb42 and 4740056f098 (committed 2016-06-11). LUCENE-7756 (23b002a0fdf, 7.0) only moved the sort into LeafMetaData. Not a regression: the logic is unchanged since 2016.",
   "introduced_date": "2016-05-04 (initial patch, author date); 2016-05-10 (current combining rule)",
   "first_affected_version": "6.2.0 [exec] (6.1.0 has neither LUCENE-6766 commit and 6.2.0 has both; 6.1.0 and 5.5.5 lack the index-sort API, compile error [exec])",
   "affected_versions": "Every release from 6.2.0 through 10.5.2, 10.6.0 (released 2026-10-29; run as its RC 4ae946e5a9b) and main a9779ef3c193; never fixed. [exec] follow-up history runs (follow-up): 6.2.0 (-ea and -da), 6.6.6, 7.0.0, 7.1.0, 7.2.0, 7.3.0, 7.4.0, 7.5.0, 7.6.0, 7.7.3, 8.11.4, 9.12.3, 10.5.2, the 10.6 RC and main (API-adapted ports for 6.x and 7.x, a version-portable main() from 8.11.4 on); the finder also ran 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2, the RC and main; the independent reproduction ran its own JUnit on main, 10.5.2 and 9.12.3 (-ea and -da); the intended-behaviour check ran 10.5.2. The false metadata, the addIndexes segment and EarlyTerminatingSortingCollector's wrong top-N exist from 6.2.0; plain IndexSearcher.search(q, n, sort) gives wrong top hits only from 7.5.0 (LUCENE-8432 made TopFieldCollector trust the sort; 7.4.0 passes that check, 7.5.0 fails it) [exec]. [read] upstream main 645d4fe14a20 (2026-10-28): no commit after a9779ef3c193 touches ParallelLeafReader, ParallelCompositeReader or LeafMetaData (last ParallelLeafReader change bfe5c847d3c, authored 2026-07-27, fp16 vectors); #16893 (merged 2026-10-26) adds guards only for segments with blocks or multi-valued fields and does not change this trigger. JDK 25.0.3, aarch64; pure Java logic.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-981.html",
   "repro": "repro/LFV-981/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1114",
   "priority": "low",
   "priority_rank": 286,
   "novelty": "new",
   "withheld": false,
   "area": "core / index (ParallelCompositeReader.prepareLeafReaders: per-leaf field ownership through ParallelLeafReader's 'first reader having a given field wins' rule)",
   "title": "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",
   "summary": "You open a ParallelCompositeReader over two indexes that hold the same 3 documents in the same two segments ([0, 1] and [2]); the first index has field t only on doc 0 (t=new), the second has t=old on every document, and you search t:old. You expect no hits, because the javadoc says matches come from the first index added that has the field (and docs 1 and 2 are identical in both indexes, so they must at least be treated alike). You get doc 2 but not doc 1, with no error: the reader chooses each field's owner separately in every segment, and segment [2] of the first index has no document with t, so the second index's t shows through there; after forceMerge(1) of both indexes the same search returns nothing.",
   "impact_class": "silent wrong results",
   "introduced_commit": "6188bc66d7d00511cb5fc9a0ee76c25d76aec73a ('LUCENE-3736: ParallelReader was split into ParallelAtomicReader and ParallelCompositeReader', issue LUCENE-3736, migrated as apache/lucene#4810; Subversion r1242924, no PR): the new composite reader builds one ParallelAtomicReader (today ParallelLeafReader) per aligned leaf from that leaf's own FieldInfos, so the first-reader-wins owner rule became per segment while the class javadoc kept the 3.x per-index sentence [read]. Later changes kept the per-leaf construction (LUCENE-4953 60151ce379a, LUCENE-5569 85bf3181737, LUCENE-6501 4c6300f105a / 376c8fc7d9c, reformat 2d6ad2fee6d). Not a regression: wrong since the class was added",
   "introduced_date": "2012-02-10 (author date = commit date of 6188bc66d7d)",
   "first_affected_version": "4.0.0-ALPHA (first GA release 4.0.0) [exec]",
   "affected_versions": "every release from 4.0.0-ALPHA through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main e1faeba08bde (12.0.0-SNAPSHOT). Executed, all failing the same way (t:old -> [2] instead of []): the JUnit repro on main (-ea and -da), 10.6.0, 10.5.2 and 9.12.3; API-adapted ports on 4.0.0-ALPHA, 4.0.0, 4.10.4, 5.0.0, 5.1.0, 5.2.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 10.6.0 and main [exec]; the releases in between by code identity (the per-leaf construction never changed) [read]. Not affected: the 3.x line (no ParallelCompositeReader; 3.6.2 ParallelReader gives []) [exec]. Not new in 10.6 (10.5.2 fails). Not fixed upstream: no commit touches ParallelCompositeReader.java after 48715fe898b (author date 2021-03-26), the last ParallelLeafReader.java commit is bfe5c847d3c (author date 2026-07-27, already in e1faeba08bde), and upstream main head 5adff78bb168 (2026-11-02) has no later change to either file [read]. Executed on Linux aarch64 with JDK 25.0.3 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1114.html",
   "repro": "repro/LFV-1114/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-445",
   "priority": "low",
   "priority_rank": 287,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / ICU (ICUTokenizer chunked buffer refill; ICUTokenizerFactory 'icu')",
   "title": "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",
   "summary": "You index a long Chinese paragraph with no spaces or line breaks through the stock ICUTokenizer, and it contains an emoji or a rare ideograph such as U+20000; you expect that character to be a token wherever it falls, as it is one position earlier or later. Instead, when its first UTF-16 half is the last char of the tokenizer's 4096-char read chunk, refill() gives the word breaker a chunk that ends in a lone high surrogate and starts the next chunk with the lone low surrogate; both halves get rule status 0 and are skipped, so the character is in no token. A TermQuery for it finds 0 documents instead of 1, with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "5abbf3429cfa2288f5bf1ff8b19945f67e0d459d (trunk, svn r940447; LUCENE-2414 / GitHub #3489 'Add ICUTokenizer, tailorable impl of Unicode Text Segmentation', rmuir; pre-GitHub, no PR; parent issue #2562 / LUCENE-1488) and its branch_3x backport a1602caf91e2688df47ea1f30de568f92000561a (svn r941706), which shipped in 3.1.0. The commit added refill() with the no-whitespace fallback 'usableLength = length', IOBUFFER = 4096 and the rule-status-0 skip in incrementTokenBuffer(), so the defect is original to the class [read]",
   "introduced_date": "2010-05-03 (trunk commit); 2010-05-06 (branch_3x backport)",
   "first_affected_version": "3.1.0 [exec] (3.0.3, the last release before, has no ICUTokenizer [exec]; the emoji form shows from 7.4.0 on, when LUCENE-8125 made emoji tokens; before that the loss shows on supplementary letters and ideographs such as U+20000 [exec])",
   "affected_versions": "every release from 3.1.0 to 10.5.2 (the latest release before 10.6.0) and main ea57360912ed (unreleased 11.0): a public-API main() probe is affected on 3.1.0 (-ea and -da), 3.6.2, 4.0.0, 4.10.4, 5.0.0, 6.6.6, 7.2.1, 7.3.0, 7.4.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) [exec]; the finder's JUnit fails 3 of 4 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) [exec]; all 131 release tags in the history clone that contain ICUTokenizer.java (3.1 to 10.5.2) have one of two normalized refill()/findSafeEnd() variants, both with the same fallback and no surrogate check [read] (8.8.2 to 8.11.3 are untagged in the clone; 8.11.4 was executed). Not affected: 3.0.3 and earlier (no ICUTokenizer). Not fixed upstream: main, branch_10x, branch_10_6 and branch_9_12 unchanged as of 2026-10-26 [read], so the released 10.6.0 (2026-10-29) is affected too [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-445.html",
   "repro": "repro/LFV-445/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-659",
   "priority": "low",
   "priority_rank": 288,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / ICU (ICUTokenizer rule status: Default.rbbi WB3c chain, BreakIteratorWrapper emoji status, status-0 skip)",
   "title": "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",
   "summary": "You index text through the stock ICUTokenizer in which a word runs straight into an invisible ZERO WIDTH JOINER (U+200D) and then an emoji, for example 'abc' + U+200D + U+1F44D, or a Malayalam word written in the older ZWJ chillu form followed by an emoji, and expect the word and the emoji to be tokens, as they are with a space before the emoji, without the ZWJ, or with StandardTokenizer. Instead neither appears: Unicode rule WB3c (ZWJ x Extended_Pictographic) keeps 'word ZWJ emoji' in one segment, the break rules give that segment rule status 0 ('not a word'), BreakIteratorWrapper's emoji check looks only at the segment's first code point (a letter), and ICUTokenizer skips every status-0 segment, so 'hello world' + U+200D + U+1F44D + ' again' gives only [hello, again]. A TermQuery for the lost word finds nothing, with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "2dcf263b5207243f6854c0e48d2496036f678eee (branch_7x, the commit that shipped in 7.4.0; same change on master 4522e45bdadd4268a9270135130fc28a7f46c627), by rmuir, 2018-03-26, 'LUCENE-8175: un-revert \"LUCENE-8122: Upgrade analysis/icu to ICU 60.2\"' (JIRA patch era, no PR; issues LUCENE-8122 / #9170 and LUCENE-8175 / #9223, neither discussing word + ZWJ + emoji input or rule statuses). Its Default.rbbi added $ZWJ, let the word macros absorb a trailing ZWJ, and added the UAX #29 WB3c rule '$ZWJ ($Extended_Pict | $EmojiNRK);' with no status tag, so under !!chain a word ending in ZWJ chains into a status-less rule [read]. It re-lands 07407a5b53bf (master) / 96be7b432ebd (branch_7x) of 2018-01-08, reverted 2018-02-20 for an unrelated ICU4J concurrency bug before any release. Older ingredients that are not regressions by themselves: the status-0 skip in ICUTokenizer (LUCENE-2414, 5abbf3429cf, 2010) and the first-code-point isEmoji of LUCENE-8125 (c0b92e27942 / 23bff7dbc20, same day, also 7.4.0). Later rule rewrites kept the behaviour [exec]: LUCENE-8366 (2ea416ee3d2, ICU 62.1, 7.5.0, current form of Default.rbbi:107), #13239 (54a2e11434d, ICU 74.2, current form of :122) and #14386 (ICU 77.1, 10.2.0), so git blame on today's lines does not point at the introduction.",
   "introduced_date": "2018-03-26 (shipped re-land 2dcf263b5207 / 4522e45bdadd); first landed 2018-01-08 (07407a5b53bf / 96be7b432ebd), reverted 2018-02-20 before any release",
   "first_affected_version": "7.4.0 [exec] (7.3.1, the last release before, keeps the word [exec], as do all of 7.0.0-7.3.1; before 7.4.0 ICUTokenizer emitted no emoji tokens at all, so only the lost word is a regression, the lost emoji only relative to the same version's 'abc U+1F44D' output)",
   "affected_versions": "Every release from 7.4.0 to 10.5.2 (the last release before 10.6.0) and main a9779ef3c193; never fixed. [exec] the follow-up's public-API main() probe ZwjHistoryMain drops 5 of 5 bug-case words and 0 of 4 controls on all 67 releases 7.4.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3 and 10.0.0-10.5.2 and on main (-ea; -da also on 9.12.3, 10.5.2 and main), and 0 of 5 on all 7 releases 7.0.0-7.3.1; the finder's JUnit fails 3 of 4 on main (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 6 of 10 on main (-ea and -da), 10.5.2 and 9.12.3, and its main() variant on 8.11.4 and 7.4.0 (7.3.0 keeps the words); the intended-behaviour check re-ran the finder's JUnit on 10.5.2. 8.8.2-8.11.4 are untagged in the history clone and were run from checksum-verified release jars. [read] upstream main and branch_10x: BreakIteratorWrapper.java and ICUTokenizer.java have only formatting commits since 2018, Default.rbbi only the ICU upgrades #13239 and #14386 (both executed on either side), and no open PR fixes it, so the unreleased 10.x and 11.0 lines are affected. JDK 25.0.3, aarch64; pure Java and ICU4J logic.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-659.html",
   "repro": "repro/LFV-659/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-653",
   "priority": "low",
   "priority_rank": 289,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / ICU (DefaultICUTokenizerConfig break rules Default.rbbi / Default.brk, used for CJK text when cjkAsWords=false; ICUTokenizerFactory 'icu' with cjkAsWords=\"false\")",
   "title": "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",
   "summary": "You build ICUTokenizer with cjkAsWords=false, whose javadoc promises that text 'will be segmented according to UAX#29 defaults', and index Japanese text such as 人々 ('people'), 時々 ('sometimes') or 様々な人々; you expect 々, a Word_Break=ALetter letter under UAX #29, to end up in a token, as it does with StandardTokenizer, with the default cjkAsWords=true mode and with Lucene 4.6.1. Instead Default.rbbi takes every Han-script character out of its letter rule and gives a status only to Ideographic characters, and 々 is Han but not Ideographic, so its segment gets rule status 0 and ICUTokenizer skips it like punctuation: 人々 -> [人], 様々な人々 -> [様, な, 人], and with CJKBigramFilter 人々 becomes the unigram 人. Nothing throws; the character is simply missing from the index.",
   "impact_class": "silent wrong results",
   "introduced_commit": "b5dbac5e3582a1cfd59af34c1a41f88aed203da1 (trunk, svn r1547502) and its branch_4x copy 2924e528633022f2c68bbdd1db25b49bb13af4cb (svn r1547561, the copy that shipped in 4.7.0), both 'LUCENE-4381: upgrade ICU to icu4j 52.1' by GitHub rmuir (JIRA LUCENE-4381, migrated as apache/lucene#5447; direct SVN commit with the patch on the JIRA issue, no PR). The commit added DefaultICUTokenizerConfig(boolean cjkAsWords) and changed Default.rbbi from '$ALetterPlus = [$ALetter [$dictionary-$Extend-$Control]]' to '$ALetterPlus = [$ALetter-$dictionaryCJK [$ComplexContext-$Extend-$Control]]' with all of [:Han:] in $dictionaryCJK [read]. Later rule regenerations (LUCENE-8122/8175 in 7.4.0, LUCENE-8366 in 7.5.0, LUCENE-9773 in 9.0.0, #13239 in 9.11.0/10.0.0, #14386 in 10.2.0) kept the line",
   "introduced_date": "2013-12-03",
   "first_affected_version": "4.7.0 [exec] (4.6.1, the last release before it, keeps U+3005 as <ALPHANUM> [exec]; 4.6.1 has no cjkAsWords option, and its only config, DefaultICUTokenizerConfig(), is the UAX #29 behaviour that cjkAsWords=false replaced: the introducing commit moved the module's existing tests to DefaultICUTokenizerConfig(false))",
   "affected_versions": "every release from 4.7.0 to 10.5.2 (the last release before 10.6.0; the latest 9.x is 9.12.3) and main a9779ef3c193; never fixed. [exec] the follow-up's version-independent main() probe drops U+3005 on 4.7.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.2.1, 7.3.0, 7.4.0, 7.5.0, 7.7.3, 8.11.4, 9.0.0, 9.10.0, 9.11.0, 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.5.2 and main (-ea and -da) and keeps it on 4.6.1; the finder's JUnit fails 3 of 4 on main (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 4 of 7 on main (-ea and -da), 10.5.2 and 9.12.3. [read] every release tag from 4.7.0 to 10.5.2 in the history clones contains one of the two introducing commits, and the line is unchanged in each line's latest release. Not affected: 4.6.1 and earlier. Not fixed upstream: no commit after a9779ef3c193 touches lucene/analysis/icu (upstream main a95c754ee003, 2026-10-26), Default.rbbi last changed with #14386 (2025-03, an unrelated sync), and no open PR touches Default.rbbi, Default.brk, DefaultICUTokenizerConfig or ICUTokenizer, so the unreleased 10.x and 11.0 lines are affected (main executed).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-653.html",
   "repro": "repro/LFV-653/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-665",
   "priority": "low",
   "priority_rank": 290,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / Arabic light stemmer (ArabicStemmer.stemPrefix; ArabicStemFilter, ArabicAnalyzer and the 'arabicStem' factory)",
   "title": "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",
   "summary": "You index Arabic text with the stock ArabicAnalyzer, whose javadoc says it implements light stemming 'as specified by' the light10 paper; that paper removes a leading waw ('and') first and then a definite article, so 'وبالكتاب' ('and with the book') should stem to 'كتاب' ('book'), like 'الكتاب' and 'بالكتاب'. Instead ArabicStemmer.stemPrefix scans one list (the six articles, then waw) and returns after the first match, so once it has removed the waw it never tries the articles: 'وبالكتاب' becomes 'بالكتاب' and 'وللطلاب' becomes 'للطلاب'. A TermQuery for the analyzed form of 'الكتاب' then finds 0 of 1 documents that contain only 'وبالكتاب', with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "8dfe073760c5f97a980390ae5daad3a881fd7730 (LUCENE-1406 'new Arabic Analyzer (Apache license)', GitHub #2480; patch by rmuir, committed by gsingers as svn r706342, 2008-10-20) [read]: stem() calls stemPrefix() once and stemPrefix() returns after the first match in one list {al, wal, bal, kal, fal, waw}, so wa+bal-, wa+kal- and wa+fal- keep their article from this commit on. 820620f3a7224c6416d001984570897682112676 (LUCENE-1758 'improve arabic analyzer: light8 -> light10', GitHub #2832, rmuir, 2009-08-05) added the lil- entry just before waw, the light10 javadoc citation and the CHANGES line 'ArabicAnalyzer now uses the light10 algorithm', without changing the loop, so wa+lil- is affected from then on. Not a regression: later commits on these lines (3241eb9291c LUCENE-2503 rename, 6faa4f98e04 LUCENE-9570 reformat, 8ac26737913 LUCENE-10003 array syntax, 694d797526a LUCENE-10561 visibility) preserve behaviour.",
   "introduced_date": "2008-10-20 (light10 contract and the lil- entry 2009-08-05; first released 2009-09-24 in 2.9.0)",
   "first_affected_version": "2.9.0 [exec] (tag releases/lucene/2.9.0, 2009-09-24, the first release with the org.apache.lucene.analysis.ar package; it contains both commits). The last release before it, 2.4.1, has no Arabic package [exec], so no release ever shipped a different variant.",
   "affected_versions": "Every release that ships the Arabic analysis API, 2.9.0 through 10.5.2, and main a9779ef3c193; not fixed. [exec] a same-package stemmer probe, a public ArabicStemFilter/ArabicAnalyzer probe, or both (4 of 4 waw+article words keep the article, 4 controls stemmed) fail on 2.9.0, 2.9.4, 3.0.3, 3.1.0, 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main, and the stemmer probe passes on main with the fix shadowed; the finder's JUnit fails 2 of 3 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da). [read] all 136 release tags in the history clone that contain 820620f3a72 have the same prefix list, stem() and stemPrefix() bodies and length rules (the 8.9-8.11.x tags are missing from the clone; 8.11.4 was executed); upstream main a95c754ee003 still has the single-return stemPrefix (read 2026-10-27).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-665.html",
   "repro": "repro/LFV-665/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-667",
   "priority": "low",
   "priority_rank": 291,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / Bengali normalizer (BengaliNormalizer.normalize; BengaliNormalizationFilter, BengaliAnalyzer and the 'bengaliNormalization' factory)",
   "title": "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",
   "summary": "You analyze Bengali text with the stock BengaliAnalyzer or BengaliNormalizationFilter. Its normalizer has a rule labelled 'Khio (Ka + Hoshonto + Murdorno Sh)' and says it implements a cited paper, which folds the conjunct ক্ষ (KA+HASANTA+SSA) to খ (KHA) at the start of a word and to কখ (KA+KHA) elsewhere, so ক্ষমা should normalize to খমা. Instead the rule's condition compares the third character with U+09BF (BENGALI VOWEL SIGN I) instead of U+09B7 (BENGALI LETTER SSA), one hex digit off, so the rule never fires on real text: ক্ষমা becomes ক্সমা and পরীক্ষা becomes পরিক্সা (only the separate 'All sh' rule applies, SSA to SA), while the malformed sequence KA+HASANTA+VOWEL SIGN I is folded instead (ক্িমা becomes খমা), with no error.",
   "impact_class": "minor",
   "introduced_commit": "1bca06b8a938bfe89b288877399942d217c8453d (the contributor's first commit of apache/lucene-solr PR #238, LUCENE-7940 'Bengali Analyzer for Lucene', now apache/lucene#8989; its message says 'LUCENE-7490', a typo for LUCENE-7940) [read]: the rule comment '// Khio (Ka + Hoshonto + Murdorno Sh)' and the condition s[i+2] == '\\u09BF' arrive together. It landed on master (8.0 line) through the merge 08128f712fc and on branch_7x through the squashed backport e18532cb687 (both by rmuir, 2017-09-05). Not a regression: the only later commits on these lines (8ef6a0da568 LUCENE-9570 reformat, f99deb58b74 #13661 spotless) are formatting.",
   "introduced_date": "2017-08-24 (authored; landed on master and branch_7x 2017-09-05; first released in 7.1.0)",
   "first_affected_version": "7.1.0 [exec] (the first release with the org.apache.lucene.analysis.bn package; the history probe fails 3 of 3 there and passes with the one-character fix shadowed). 7.0.1, the last release before it, has no Bengali analysis API [exec], so no release ever shipped a working khio rule.",
   "affected_versions": "Every release that ships the Bengali analysis API, 7.1.0 through 10.5.2, and main a9779ef3c193; not fixed. [exec] a version-independent public-API probe (BengaliNormalizationFilter over KeywordTokenizer and BengaliAnalyzer.normalize, 3 khio checks) fails on 7.1.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da), and passes on 7.1.0 and main with the fix shadowed; the finder's JUnit fails 3 of 3 on 9.12.3, 10.5.2 and main (-ea and -da) (it needs org.apache.lucene.tests.analysis, so it does not compile on 9.0.0). [read] all 63 release tags in the history clone that have the file (7.1.0-7.7.3, 8.0.0-8.8.1, 9.0.0-10.5.2) contain the same condition; upstream main a95c754ee00 (2026-10-26), branch_10x and branch_10_5 still test '\\u09BF' (read 2026-10-27).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-667.html",
   "repro": "repro/LFV-667/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-676",
   "priority": "low",
   "priority_rank": 292,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / Bengali normalizer (BengaliNormalizer.normalize; BengaliNormalizationFilter, BengaliAnalyzer and the 'bengaliNormalization' factory)",
   "title": "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",
   "summary": "You index or query Bengali text with the stock BengaliAnalyzer or BengaliNormalizationFilter. Its normalizer folds SHA (শ) and SSA (ষ) to SA (স) everywhere and turns a medial visarga (ঃ) into a copy of the next letter (gemination), so নিঃশব্দ ('silent'), নিঃষব্দ and নিঃসব্দ should all become নিসসব্দ (SA SA), just as the class's other gemination rule turns বিশ্ব into বিসস in an upstream test. Instead the visarga branch copies the next character before the loop has folded it and never revisits the copy, so নিঃশব্দ becomes নিশসব্দ (SHA SA) and নিঃষব্দ becomes নিষসব্দ (SSA SA): the three spellings give three different terms, and a document written with one of them is not found by a query written with another, with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "1bca06b8a938bfe89b288877399942d217c8453d (author sunkuet02; the first commit of apache/lucene-solr PR #238, LUCENE-7940 'Bengali Analyzer for Lucene', now apache/lucene#8989; its message says 'LUCENE-7490', a typo for LUCENE-7940) [read]: the visarga copy s[i] = s[i+1] and the fold cases ('All sh', 'check na', II, UU, NGA, khanda-ta) arrived together in one left-to-right switch. It landed on branch_7x as the squash e18532cb687c (7.1.0) and on master through the merge 08128f712fc8 (8.0.0 and later), both by rmuir on 2017-09-05. Not a regression: the later commits on the file are formatting or visibility only (8ef6a0da568 LUCENE-9570, 8ac26737913 LUCENE-10003, 694d797526a LUCENE-10561, f99deb58b74 #13661), and the Ja/Ba-phala boundary fixes 3197d5af71d and 40dddf9324e inside PR #238 leave the visarga case unchanged.",
   "introduced_date": "2017-08-24 (authored; landed on branch_7x and master 2017-09-05; first released in 7.1.0)",
   "first_affected_version": "7.1.0 [exec] (the first release with the org.apache.lucene.analysis.bn package; the history probe reports BUG_PRESENT there with -da and with -ea, all 5 controls OK). 7.0.1, 7.0.0 and 6.6.6 have no Bengali analysis API [exec], so no release ever folded the visarga copy.",
   "affected_versions": "Every release that ships the Bengali analysis API, 7.1.0 through 10.5.2 (72 releases: 7.1.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2), and main a9779ef3c193; not fixed. [exec] the follow-up's public-API main() probe (WhitespaceTokenizer + BengaliNormalizationFilter, and BengaliAnalyzer) reports BUG_PRESENT (4 mismatches, 5 of 5 controls OK) on each of the 72 releases with -da (7.1.0 also with -ea) and on main, and BUG_ABSENT on main with the fix sketch shadowed; the finder's JUnit fails 3 of 3 on main (-ea and -da), 10.5.2, 10.0.0, 9.12.3 and 9.1.0; the independent reproduction's JUnit fails 5 of 9 on main (-ea and -da), 10.5.2 and 9.12.3, and the independent reproduction's portable main() fails on 8.11.4 and 7.7.3. [read] the file has three blobs across all release tags in the history clone (7.1.0-8.8.1, 9.0.0-9.12.3, 10.0.0-10.5.2 and main), all with the same raw copy; upstream main a95c754ee00 (2026-10-26), branch_10x and branch_10_5 still have s[i] = s[i + 1] at line 121 (read 2026-10-27).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-676.html",
   "repro": "repro/LFV-676/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-734",
   "priority": "low",
   "priority_rank": 293,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / StandardTokenizer JFlex word rule (the <ALPHANUM> rule of core StandardTokenizerImpl.jflex; the same rule in analysis-common UAX29URLEmailTokenizerImpl.jflex)",
   "title": "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)",
   "summary": "You index Hebrew text with the stock StandardAnalyzer, whose StandardTokenizer says it implements the UAX #29 word-break rules, among them WB7a-WB7c, which keep an ASCII apostrophe after a Hebrew letter (BET') and an ASCII quotation mark between two Hebrew letters (TAV\"ALEF) inside a word, and you expect them to combine with the other rules as the annex and ICU do: BET'2 gives [BET', 2], HE.SHIN' gives [HE.SHIN'], and TAV\"ALEF.BET and ALEF.TSADI\"LAMED are single words. Instead the grammar writes 'Hebrew letter + quote' as a separate piece that may be glued to any following piece but cannot continue a letter chain, so BET'2 becomes one term (a search for 2 misses the document), HE.SHIN' loses the apostrophe, and the quoted words are split into [TAV\"ALEF, BET] and [ALEF.TSADI, LAMED]. StandardTokenizer and UAX29URLEmailTokenizer behave the same, with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "d516948bbde8774d668c79432f33f5384d4075f9 (LUCENE-5357 'Upgrade StandardTokenizer and UAX29URLEmailTokenizer to Unicode 6.3', apache/lucene#6421; trunk svn r1548595 by sarowe, an svn-era JIRA patch, no pull request): it added the Hebrew_Letter, Single_Quote and Double_Quote classes and wrote WB7a-WB7c as the stand-alone piece '( {HebrewLetterEx} ( {SingleQuoteEx} | {DoubleQuoteEx} {HebrewLetterEx} ) )' of the '+'-repeated piece list in the <ALPHANUM> rule of both grammars; the branch_4x merge d53a21ef180ea4369f148b7541ae05fe71ae9bb6 (svn r1548762, 2013-12-07) is the commit that shipped first, in 4.7.0 [read]. Not a regression: no later commit changed the Hebrew piece or how the pieces are joined (git log -L238,251: LUCENE-5447, LUCENE-8527 and #14820 touched other parts, names or whitespace only)",
   "introduced_date": "2013-12-06 (trunk; branch_4x merge 2013-12-07; first release 4.7.0)",
   "first_affected_version": "4.7.0 [exec] (the follow-up's version-portable probe: 4.6.1, the last release before, implements the Unicode 6.1 rules, which have no Hebrew rules, and conforms to them on all 5 inputs; 4.7.0 deviates on 5 of 5 inputs in both tokenizers; 4.7.0 with matchVersion LUCENE_46 selects the old 6.1 scanners and is not affected)",
   "affected_versions": "Every release from 4.7.0 to 10.5.2, 10.6.0 (by reading) and main a9779ef3c193; not fixed. [exec] the follow-up's version-portable probe (public API, one source for 4.0.0 to main) reports the bug present, 5 of 5 inputs deviating in StandardTokenizer and in UAX29URLEmailTokenizer with output identical to main's, on all 119 releases 4.7.0-4.10.4, 5.0.0-5.5.5, 6.0.0-6.6.6, 7.0.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3 and 10.0.0-10.5.2 (-ea) and on main (-ea and -da), and absent on the 11 releases 4.0.0-4.6.1 and on 4.7.0 with matchVersion LUCENE_46 (133 runs, SHA-1-checked jars, all as expected); in 5.x, StandardAnalyzer.setVersion before 4.7.0 selects StandardTokenizer40 (not affected, not executed).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-734.html",
   "repro": "repro/LFV-734/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-818",
   "priority": "low",
   "priority_rank": 294,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / ASCIIFoldingFilter mapping table (foldToASCII switch)",
   "title": "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",
   "summary": "You index and search through a chain that lower-cases and then applies ASCIIFoldingFilter, documented to convert characters 'into their ASCII equivalents', and you type queries in plain ASCII. You expect 'naǧib' and 'NAǦIB' to be indexed as 'nagib', just as 'ağa' becomes 'aga'; instead six entries of the 1,242-entry folding table sit in the output group of the opposite case (ǥ and ǧ in 'G', ꞅ in 'S', Ꞅ in 's', Ɐ in 'a', Ꜿ in 'c', plus the contested ʗ in 'C'), so the term is 'naGib' and the query 'nagib' finds nothing. Each of the six lines carries a source comment that names the other case (for example [LATIN SMALL LETTER G WITH CARON] inside the 'G' group), and the fix is to move these case labels into the group of their own case.",
   "impact_class": "silent wrong results",
   "introduced_commit": "8660ccb303f6 (LUCENE-1390 'Added ASCIIFoldingFilter ...', SVN trunk r724053, credited in CHANGES as 'Andi Vajda, Steven Rowe via Mark Miller'; JIRA issue migrated as #2464, no PR); born buggy, not a regression: the final patch attachment in the JIRA archive has the identical table, so the placements come from the contributed patch, whose author described it as Perl-generated from Unicode 5.1 UnicodeData.txt and then 'moved things around to the appropriate places by hand' [read]",
   "introduced_date": "2008-12-06 (author and committer date of 8660ccb303f6; LUCENE-1390 opened 2008-09-17, resolved 2008-12-06, fix version 2.9)",
   "first_affected_version": "2.9.0 [exec] (first release with ASCIIFoldingFilter; 2.4.1, cut from the 2.4 branch, has no such class: compile error [exec]; its predecessor ISOLatin1AccentFilter did not map these letters [read])",
   "affected_versions": "every release from 2.9.0 to 10.5.2, 10.6.0 (by reading) and main a9779ef3c193 (the branch_10x and branch_10_6 heads carry the same table [read]). [exec] a JDK-only main() that drives the public TokenStream API by reflection fails with '6 of 6 letters fold to the ASCII letter of the opposite case' (U+0297 reported as 'C', not asserted; 9 same-case controls correct; the same BMP-wide fold digest b13b9b6ad318 in every run) on the 22 releases 2.9.0, 2.9.4, 3.0.0, 3.0.3, 3.1.0, 3.6.2, 4.0.0, 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.2.1, 6.3.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0 and 10.5.2 and on main with -ea and -da; the finder's JUnit fails 4 of 4 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (it needs the test framework of 9.1.0 or later); the independent reproduction's JUnit fails 4 of 4 on 9.12.3, 10.5.2 and main; all runs on JDK 25, Linux aarch64 only. [read] the same 1,242-row table at all 136 release tags of the history clone that contain the introducing commit; the public static foldToASCII(char[], int, char[], int, int) (LUCENE-2015, from 3.1) uses the same switch.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-818.html",
   "repro": "repro/LFV-818/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-565",
   "priority": "low",
   "priority_rank": 295,
   "novelty": "new",
   "withheld": false,
   "area": "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)",
   "title": "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",
   "summary": "You index the text '我们使用Ｌｕｃｅｎｅ' (or '我们使用Lucene') with the stock SmartChineseAnalyzer and search with the classic QueryParser: the term query 'Ｌｕｃｅｎｅ' and the half-width prefix 'Luc*' find the document, so you expect the full-width prefix 'Ｌｕｃ*' to find it too. Instead it finds 0 documents, with no error: the tokenizer's SegTokenFilter folds full-width Latin letters and digits to half-width and lower-cases A-Z, so the index holds 'lucen', but SmartChineseAnalyzer.normalize, which the query parsers apply to prefix, wildcard, regexp, range and fuzzy terms, is only a LowerCaseFilter, so the query term stays full-width ('ｌｕｃ*'). Likewise Analyzer.normalize returns 'ａｂｃ' for 'ＡＢＣ' and '１２３' for '１２３' (the index holds 'abc' and '123') and 'é' for 'É' (the index keeps 'É').",
   "impact_class": "silent wrong results",
   "introduced_commit": "7c2e7a0fb80a5bf733cf710aee6cbf01d02629eb on branch_6x (first released in 6.2.0) and its master twin e92a38af90d12e51390b4307ccbe0c24ac7b6b4e (first released in 7.0.0): LUCENE-7355 'Add Analyzer#normalize() and use it in query parsers' (jpountz; GitHub issue apache/lucene#8409, JIRA patch with 8 versions, no PR), which added SmartChineseAnalyzer.normalize(String, TokenStream) { return new LowerCaseFilter(in); } (main :137-140) while giving CJKAnalyzer and JapaneseAnalyzer CJKWidthFilter + LowerCaseFilter [read]. The index-side folding it fails to mirror dates from 2009 (SegTokenFilter full-width folding e01aad89fe2, LUCENE-1629; the createComponents comment 'SegTokenFilter lowercases Basic Latin text' 5265dc1bb20) and is unchanged except for reformatting",
   "introduced_date": "2016-07-12 (commit date of both commits; author date 2016-06-28)",
   "first_affected_version": "6.2.0 [exec] (the normalize-contract probe fails 3 of 4 on 6.2.0 and does not compile on 6.1.0, which has no Analyzer#normalize). In 6.2.0 it is a regression for AnalyzingQueryParser and QueryParser.setAnalyzeRangeTerms(true), which ran the analyzer's full chain, width folding included, before (probe C passes 6 of 6 on 5.5.5 and 6.1.0 and fails 5 of 6 on 6.2.0 and 6.6.6) [exec]. The default classic parser misses full-width multi-term queries already on 5.5.5, 6.0.0 and 6.1.0 through its own lowercaseExpandedTerms (String.toLowerCase, no width folding), a limitation of that parser rather than this defect; from 7.0.0, which removed that option and routes every multi-term term through Analyzer#normalize, this override is the cause (probe B passes 5 of 5 on main with the fix shadowed) [exec]",
   "affected_versions": "Every release 6.2.0 to 10.6.0 (10.6.0, released 2026-10-29, by reading) and main ea57360912ed (unreleased 11.0). [exec] probe A (normalize vs the indexed token for 'ＡＢＣ', '１２３' and 'É', with a half-width control) fails 3 of 4 on 6.2.0, 6.6.6, 7.0.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) and passes 4 of 4 on main with the fix; probe B (default classic parser end to end: 'Ｌｕｃ*', 'Ｌｕ?ｅｎ', 'Ｌｕｃｅｎ~1', '[Ｌｕａ TO Ｌｕｚ]', with half-width controls) fails 4 of 5 on 5.5.5, 6.0.0, 6.1.0, 6.2.0, 6.6.6, 7.0.0, 8.11.4, 9.12.3, 10.5.2 and main (-ea and -da) and passes 5 of 5 on main with the fix; the finder's JUnit fails 3 of 3 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the independent reproduction's JUnit fails 4 of 5 on main (-ea and -da), 10.5.2, 9.12.3 and 8.11.4. [read] by tag containment 7c2e7a0fb80 is in the 15 tags 6.2.0 to 6.6.6 and e92a38af90d in the 65 tags 7.0.0 to 8.8.1 and 9.0.0 to 10.5.2; 8.8.2 to 8.11.3 are not tagged in the history clone (between 8.8.1 [read] and 8.11.4 [exec]). Not fixed upstream: the override is unchanged on upstream main a95c754ee003 (2026-10-26) and, in the local clone, on origin/main a9779ef3c19 and the branch_10x and branch_10_6 tips; no open PR changes it. Not affected: 6.1.0 and earlier (no Analyzer#normalize; for the older classic-parser symptom see first_affected_version). Not executed: x86",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-565.html",
   "repro": "repro/LFV-565/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-317",
   "priority": "low",
   "priority_rank": 296,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / HTMLStripCharFilter (JFlex grammar: SingleQuoted, DoubleQuoted, OpenTagAttribute, EventAttribute)",
   "title": "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)",
   "summary": "You strip '<a href=\"C:\\Temp\\\">folder</a> text after <a href=\"x\">y</a> end' with HTMLStripCharFilter and expect 'folder text after y end', which is what 9.8.0, the HTML parsing rules (Python's html.parser as an independent check) and the same document without the trailing backslash give. Instead main returns 'y end': the scanner reads the backslash and the closing quote as an escaped quote, so the attribute value runs on to the next double quote (the one in href=\"x\"), everything from the first tag to the end of the second tag is treated as one tag, and 'folder text after' is never indexed. No error is raised, and a single-quoted value ending in a backslash loses text the same way.",
   "impact_class": "silent wrong results",
   "introduced_commit": "Layered, one root cause. Ordinary quoted attributes: 4cff584a48941c5c00bbcfaedf799b629dcc7806 (PR #11724, GITHUB#11556 / LUCENE-10520, by GitHub elliotzlin, merged by dweiss; branch_9x backport fc17405271983e27770993d277f144f1f5cc8f94), which added OpenTagAttribute = {Name} \\s* \"=\" \\s* ( {SingleQuoted} | {DoubleQuoted} ) to OpenTagContent and so applied the existing backslash-escape macros to every attribute value [exec]. On* event attributes: f3a363708ff95f28b5f29fe2cc27c1cd9fd0fca9 (LUCENE-3690 / GitHub #4764, the JFlex rewrite, svn era, no PR; branch_3x d387ae60fcf7ecb65596b756a0f8fc79923d0370), which wrote SingleQuoted / DoubleQuoted with the \\' / \\\" escape alternative and used them for EventAttribute and server-side-include strings [read]. PR #15756 (GITHUB#15754, 10.5.0) did not touch these macros [read]",
   "introduced_date": "2023-10-02 (PR #11724 merged; ordinary quoted attributes); 2012-01-22 (LUCENE-3690 on trunk, branch_3x 2012-01-24; on* event attributes)",
   "first_affected_version": "9.9.0 [exec] for ordinary quoted attributes (9.8.0 passes the finder's JUnit 3 of 3 and the independent reproduction's 6 of 6); 3.6.0 [exec] for on* event attributes (the class first shipped in Lucene in 3.6.0)",
   "affected_versions": "Ordinary quoted attributes (href, title, alt, class, data-*, ...): 9.9.0 to 9.12.3, 10.0.0 to 10.6.0 (10.6.0 by reading) and main ea57360912ed [exec]. On* event attributes (onclick, ...): every release from 3.6.0 to 10.6.0 (10.6.0 by reading) and main [exec]. 10.6.0 (by reading), 10.5.2 and 9.12.3 (the latest 9.x release) are affected. Not fixed upstream: upstream main e1c4184cb983 (2026-10-26), branch_10x and branch_10_6 have the same macros, and no open PR touches the grammar [read]. Not run: 10.5.1 (same scanner source as 10.5.0 and 10.5.2), x86 (pure scanner logic)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-317.html",
   "repro": "repro/LFV-317/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-708",
   "priority": "low",
   "priority_rank": 297,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / wikipedia: WikipediaTokenizer (JFlex grammar lexical states, WikipediaTokenizerImpl.jflex)",
   "title": "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",
   "summary": "You tokenize Chinese or Japanese wiki text with WikipediaTokenizer, for example '[[日本]]', '[[Category:日本]]', '== 日本 ==' or \"x '''東京''' y\", and expect the text inside the markup to become tokens, as it does for Latin and Korean text in the same markup ('[[Japan]]', '[[한국]]') and for Chinese/Japanese plain text ('日本' gives 日|<CJ> and 本|<CJ>). Instead every Chinese/Japanese character inside markup is skipped without an error: '[[日本]]', '[[Category:日本]]', '== 日本 ==' and '<ref>日本</ref>' give no token at all, '[http://example.org 日本]' gives only the URL, and \"x '''東京''' y\" gives x and y, with y typed bold. The cause is the grammar: its only CJ token rule is for plain text (WikipediaTokenizerImpl.jflex:201), while all nine markup lexical states have a token rule for ALPHANUM only and ignore every other character (:219-309), and the CJ character class is disjoint from ALPHANUM.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f715fc6031704bc1a3566044bb80a1a050b917ca (LUCENE-1103 'WikipediaTokenizer', migrated as GitHub #2180; Subversion r608852 from a JIRA patch, no pull request; committed by gsingers): the new contrib/wikipedia grammar copied the <YYINITIAL>{CJ} rule from StandardTokenizer's grammar and gave its nine new markup lexical states token rules for {ALPHANUM} only. No later commit added a {CJ} rule to a markup state: git log -S'{CJ}' on the grammar finds only this commit, and the later edits of these lines (b18f6ae9592 LUCENE-1103 position increments, 305c47f5005 LUCENE-1133, ec2b654231e LUCENE-3477, d516948bbde LUCENE-5357 '. | {WHITESPACE}' -> '[^]', af831d28105 LUCENE-10239 JFlex upgrade) all keep CJ ignored [read]",
   "introduced_date": "2008-01-04",
   "first_affected_version": "2.3.0 [exec] (released 2008-01-23; the tokenizer did not exist before: 2.2.0 has no WikipediaTokenizer [exec])",
   "affected_versions": "Every release from 2.3.0 through 10.5.2 and main a9779ef3c193 [exec]. By reading, all 141 release tags that contain the grammar have the single <YYINITIAL>{CJ} rule and the ALPHANUM-only state rules. Not executed: 2.3.2 and 2.4.0 (no artifact of the wikipedia module on Maven Central) and the other point releases (same grammar by reading). Not fixed: upstream main a95c754ee00 (2026-10-26) has the same grammar, and no open PR touches the wikipedia package or any .jflex file [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-708.html",
   "repro": "repro/LFV-708/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1096",
   "priority": "low",
   "priority_rank": 298,
   "novelty": "known",
   "withheld": false,
   "area": "analysis / kuromoji and nori number filters (stacked tokens inside a number)",
   "title": "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)",
   "summary": "You run 十一石二鳥と五 through JapaneseTokenizer (search mode, compounds kept, the configuration of the upstream TestJapaneseNumberFilter) and JapaneseNumberFilter, and expect the separate number 五 at the end to normalize to 5, since stacked tokens are documented to be left untouched. Instead the filter re-emits 十, drops 一, keeps 十 in its number buffer and later emits 十 + 五 = 15; KoreanNumberFilter has the same code.",
   "impact_class": "silent wrong results",
   "introduced_commit": "unknown (not bisected); [read] the posInc-0 branch has been unchanged since each filter was added (JapaneseNumberFilter, LUCENE-3922, 6.0.0; KoreanNumberFilter, LUCENE-8812, 8.2.0)",
   "introduced_date": "unknown (not bisected)",
   "first_affected_version": "unknown (not bisected); 6.0.0 (ja) and 8.2.0 (ko) by reading [read]; oldest executed 9.12.3 [exec]",
   "affected_versions": "9.12.3 [exec]; 10.5.2, 10.6.0, main 645d4fe14a20 [exec]; released 10.6.0 (-da) and main e1faeba08bde (-ea, -da) [exec].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/11398",
    "https://issues.apache.org/jira/browse/LUCENE-10362",
    "https://github.com/apache/lucene/issues/11397",
    "https://issues.apache.org/jira/browse/LUCENE-10361",
    "https://github.com/apache/lucene/issues/11395",
    "https://issues.apache.org/jira/browse/LUCENE-10359"
   ],
   "doc": "",
   "repro": "repro/LFV-1096/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-360",
   "priority": "low",
   "priority_rank": 299,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / kuromoji and nori number filters (JapaneseNumberFilter, KoreanNumberFilter: KeywordAttribute inside a number composition)",
   "title": "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)",
   "summary": "You put SetKeywordMarkerFilter in front of JapaneseNumberFilter (or KoreanNumberFilter) to protect a word made of numeral characters, as the class javadoc suggests for the name 京一, and expect that word to come out unchanged wherever it occurs. That works when the word starts a number (田中京一 gives 田中, 京一, the upstream testName), but the filter checks the keyword flag only on the first token of a number and accepts every following numeral token without looking at it, so a protected word right after a numeral is appended to the number: 社員の三京一 gives the single token 30000000000000001 (offsets 3-6) instead of 3 and 京一, and the Korean name 오경일 (tokens 오 / 경일, 경일 protected) gives 50000000000000001. No error is raised; a TermQuery for the protected word then misses the document (executed).",
   "impact_class": "silent wrong results",
   "introduced_commit": "4b93c66c252b (JapaneseNumberFilter: 'Added JapaneseNumberFilter (LUCENE-3922)', by GitHub cmoen, trunk svn r1656670, never backported to branch_5x) and 5a75b8a0808e (KoreanNumberFilter: 'LUCENE-8812: Add new KoreanNumberFilter that can change Hangul character to number ...', by GitHub danmuzi, master; branch_8x backport 36b90c605693 the same day, a port of the Japanese filter); both were committed from JIRA patches, no GitHub PR (the issues are now #4995 and #9856). Each commit adds the filter with the defect already in it: the isKeyword() check runs once, before the composition loop, and the continuation predicate 'numeralTerm = isNumeral(term) || isNumeralPunctuation(term)' never looks at the keyword flag [read]",
   "introduced_date": "2015-02-03 (JapaneseNumberFilter); 2019-06-09 (KoreanNumberFilter)",
   "first_affected_version": "6.0.0 [exec] for JapaneseNumberFilter (the trunk commit's 5.1.0 CHANGES entry was removed, no 5.x tag has the class; 5.5.5 executed compile_error); 8.2.0 [exec] for KoreanNumberFilter (8.1.1 executed compile_error)",
   "affected_versions": "every release of each filter: JapaneseNumberFilter 6.0.0 through 10.5.2, KoreanNumberFilter 8.2.0 through 10.5.2, plus main ea57360912ed (not fixed). Executed with the follow-up's public-API probes (2 triggers fail, 4 controls pass on every version): ja 6.0.0 (-ea and -da), 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); ko 8.2.0 (-ea and -da), 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) [exec]; the finder JUnit fails on main, 10.5.2 and 9.12.3 (each -ea and -da) and 10.0.0, the independent reproduction's suite on main (-ea, -da), 10.5.2 and 9.12.3 [exec]; the single isKeyword() call and the unchanged continuation predicate are in all 83 tagged releases with JapaneseNumberFilter and all 48 with KoreanNumberFilter in the history clone (which lacks the 8.8.2-8.11.x tags; 8.11.4 was executed) [read]. Upstream main e1c4184cb983 (2026-10-26) and branch_10x have byte-identical sources [read]. Before 9.1.0 KoreanNumberFilterFactory is not in the nori SPI file (added by LUCENE-10352), so the Korean filter is reached there by construction or class name; the affected range is unchanged",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-360.html",
   "repro": "repro/LFV-360/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-651",
   "priority": "low",
   "priority_rank": 300,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / TeeSinkTokenFilter (SinkTokenStream replay through AttributeSource.restoreState without clearAttributes(): attributes that only the sink's chain adds)",
   "title": "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",
   "summary": "You index one field from a TeeSinkTokenFilter and a second field from one of its sinks, wrapped in a keyword marker and a stemmer (for example SetKeywordMarkerFilter protecting 'quick', then PorterStemFilter), and expect the sink field to get what the same chain gives on the tokenizer: [the, quick, fox, jump] for 'The quick foxes jumped'. Instead it gets [the, quick, foxes, jumped]: the sink replays each token with restoreState() but never calls clearAttributes(), and the KeywordAttribute that only the sink's chain added is not in the tee's captured states, so once 'quick' is marked as a keyword every later token stays marked and is not stemmed. Nothing is thrown; a query for stemmed:fox finds nothing.",
   "impact_class": "silent wrong results",
   "introduced_commit": "31a5f0edcc474f739e8392eac7261b9483fc60bf (LUCENE-1693 'AttributeSource/TokenStream API improvements', GitHub #2767, svn r797665, by Michael Busch; SVN/JIRA era, no PR): it added TeeSinkTokenFilter, whose SinkTokenStream gets its own cloneAttributes() copy of the tee's attributes and an incrementToken() that only calls restoreState() [read]. LUCENE-6973 (073dbdc17e3, backported as 1ff4e84f89f; first released in 5.5.0) rewrote the class and kept the restore-only incrementToken() and end(); the missing super.end() in SinkTokenStream.end() dates from LUCENE-1448 (c311d5730cb, 2009-07-25) [read]",
   "introduced_date": "2009-07-24 (31a5f0edcc4)",
   "first_affected_version": "2.9.0 [exec], the first release with TeeSinkTokenFilter (reachable there with a sink-side filter that adds its own attribute; the stock trigger, KeywordMarkerFilter or StemmerOverrideFilter before PorterStemFilter, exists from 3.1.0 [exec]); 2.4.1 has no TeeSinkTokenFilter and its predecessor TeeTokenFilter/SinkTokenizer replays correctly [exec]",
   "affected_versions": "Every release from 2.9.0 to 10.6.0 (10.6.0 by reading) and main a9779ef3c193; never fixed. [exec] 40 follow-up history runs (seed DEADBEEF): a sink-side filter adding its own attribute set on one token fails on 2.9.0 (-ea and -da), 2.9.4, 3.0.0, 3.0.3, 3.1.0 and 3.6.2, each with a passing control that adds the attribute to the tee first; the stock keyword-marker + PorterStemFilter repro fails on 3.1.0, 3.6.2, 4.0.0, 4.2.1, 4.3.0, 4.10.4, 5.0.0, 5.5.5, 6.0.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da), and passes on main with the fix; the finder's JUnit fails 3 of 3 on main, 10.5.2 and 9.12.3 (-ea and -da); the independent reproduction's JUnit fails 4 of 5 on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's on main (-ea and -da) and 10.5.2; upstream main a95c754ee003 has a byte-identical TeeSinkTokenFilter.java and branch_10x and branch_10_6 match 10.5.2, so 10.6.0 (released 2026-10-29 from branch_10_6) and the unreleased 10.x and 11.0 lines are affected (not executed). The end() half (no super.end()) has an effect only from 4.5.0, when LUCENE-3849 made the base TokenStream.end() reset attributes [read], and was not executed separately. JDK 25.0.3, aarch64; pure Java logic.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-651.html",
   "repro": "repro/LFV-651/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-654",
   "priority": "low",
   "priority_rank": 301,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / nori UserDictionary (right context id of user nouns, used by the Viterbi connection costs)",
   "title": "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",
   "summary": "You load a nori user dictionary whose line for the noun 학교 ('school') ends with a space, or carries an inline comment as in '학교 # memo' (the parser deletes '#' to the end of the line but keeps the space before it), and expect the same analysis as with the plain line '학교', because the parser splits the line on whitespace and gets the same noun with no segmentation. Instead UserDictionary.java:94 takes the noun's right context id, which tells the tokenizer whether the noun's last syllable ends in a consonant, from the last character of the whole line, here the space, so the noun gets the generic id and the word after it is analysed differently: on 9.12.3 '학교이' gives 이/VCP with '학교' but 이/J with '학교 ', and KoreanAnalyzer turns '학교가방을 샀다' into [학교][가방][사] with '학교' but [학교][방][사] with '학교 ', losing the term 가방 ('bag'). The two line forms disagree in every release from 7.4.0 to 10.6.0 (10.6.0 by reading) and on main (main: '학교이' gives 이/JKS vs 이/VCP, '사람이나' gives [사람] vs [사람][이]), and a shorter segmentation such as '세종시 세종' takes the id from 종 (final consonant) instead of 시 (none) in the same way.",
   "impact_class": "silent wrong results",
   "introduced_commit": "e851b89cbeb1f55edc0f2c1276e2ae812eca2643 (LUCENE-8231 'Add a new analysis module (nori) similar to Kuromoji but to handle Korean', by jimczi; JIRA patch workflow, no pull request; the issue is now apache/lucene#9278) and its same-day branch_7x copy 8651fbaa8bc65fdfec397ad4e7ebe2b5acf78d7b, which shipped in 7.4.0 [read]. Not a regression: the defect is present from the module's first commit",
   "introduced_date": "2018-04-13",
   "first_affected_version": "7.4.0 [exec] (nori's first release, tagged 2018-06-22); 7.3.1 and earlier have no nori module [exec]",
   "affected_versions": "Every nori release from 7.4.0 through 10.5.2 (latest 9.x 9.12.3), 10.6.0 (by reading) and main a9779ef3c193; never fixed. [exec] the follow-up's version-portable JUnit (4-argument KoreanTokenizer constructor, right id read through reflection) fails 4 of 6 on all 67 nori releases on Maven Central (7.4.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2) and on main, also with -da on 7.4.0, 9.12.3, 10.5.2 and main, while its controls pass; the finder's JUnit fails 2 of 2 on main (-ea and -da), 10.5.2, 10.0.0, 9.12.3, 9.0.0, 8.11.4 and 8.2.0 (it does not compile on 8.1.1: its 5-argument constructor came with LUCENE-8784 in 8.2.0); the independent reproduction's tests fail 5 of 7 on main, 10.5.2 and 9.12.3 (each -ea and -da) and 9.0.0. Which line form reads wrong depends on the version: in 7.4.0-7.6.0 (inverted constants, fixed by LUCENE-8603) the generic id equals the coda id, so only vowel-final nouns (학교, 나무, 사과) are affected; from 7.7.0 nouns with and without a final consonant are affected; from 10.0.0 the stale context ids of the separate candidate nori-userdict-context-ids-stale-after-dictionary-upgrade make the plain line the one that reads wrong for some inputs ('학교이'), but the right-id split itself (3534 or 3535 vs 3533) is identical from 7.7.0 to main. [read] UserDictionary.java:94 is unchanged on upstream main a95c754ee003, branch_10x and branch_10_6 (prior-art check, 2026-10-27); the 7 commits ea57360912ed..a9779ef3c193 do not touch lucene/analysis/nori. All runs on JDK 25, aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-654.html",
   "repro": "repro/LFV-654/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-855",
   "priority": "low",
   "priority_rank": 302,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / icu (ICUFoldingFilter UTR#30 folding data: the hand-written 'Rule: verbatim' Cyrillic block of DiacriticFolding.txt, compiled into utr30.nrm)",
   "title": "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 ч",
   "summary": "You index Tajik text such as 'Ҷумҳурии Тоҷикистон' with ICUFoldingFilter, whose javadoc lists 'Diacritic removal (including stroke, hook, descender)', and expect the same words typed without the Tajik letters, 'Чумхурии Точикистон', to find it, as they do for ҳ, қ and the other WITH DESCENDER letters. Instead the hand-copied line '04B7>04BC' in DiacriticFolding.txt maps CHE WITH DESCENDER to ABKHASIAN CHE, so ҷ and Ҷ are indexed as ҽ while the query's ч stays ч, and the query gets 0 hits. In Abkhaz, which uses ҷ, ҽ and ҿ as three separate letters, all three fold to ҽ and match each other.",
   "impact_class": "silent wrong results",
   "introduced_commit": "3599d0c60b17e395b9cd3a3f745187a5d32bb8be (svn trunk r936657, 'LUCENE-1343: Add ICUFoldingFilter, normalizes unicode text for search', issue LUCENE-1343 = #2420, by GitHub rmuir; no PR), backported to branch_3x as 534809c2eae7addcd93ede794e1e42d72a87e105 (r941694, 'LUCENE-1343: backport'), the commit that shipped in 3.1.0 [read] [exec]. The line was copied, with the rest of the block ('These are from UTR#30 DiacriticFolding.txt'), from the 2004 UTR#30 draft data file (since withdrawn), which itself maps U+04B6/U+04B7 to U+04BC; wrong from the start, so not a regression",
   "introduced_date": "2010-04-22 (trunk author date 2010-04-22T08:47:49Z; branch_3x backport author date 2010-05-06T12:27:18Z)",
   "first_affected_version": "3.1.0 [exec] (the first release with ICUFoldingFilter; 3.0.3 [exec]: API absent, the probe fails to compile on the ICU package and class only, and Maven Central has no lucene-icu 3.0.3 artifact)",
   "affected_versions": "every release from 3.1.0 to 10.5.2 (all 138 final releases on Maven Central: lucene-icu 3.1.0-3.6.2, lucene-analyzers-icu 4.0.0-8.11.4, lucene-analysis-icu 9.0.0-10.5.2), the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193 [exec] [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-855.html",
   "repro": "repro/LFV-855/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-668",
   "priority": "low",
   "priority_rank": 303,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / Sorani normalizer (SoraniNormalizer.normalize; SoraniNormalizationFilter, SoraniAnalyzer and the 'soraniNormalization' factory)",
   "title": "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",
   "summary": "You analyze Sorani Kurdish text with the stock SoraniAnalyzer or SoraniNormalizationFilter. The normalizer's javadoc says a word-final HEH (U+0647) is converted to AE (U+06D5) and that formatting characters such as directional controls are removed, so خانه ('house') followed by an invisible right-to-left mark should normalize like خانه itself, to خانە. Instead the HEH rule asks 'is this the last character?' while the trailing mark is still in the buffer, and the mark is deleted only later in the same pass, so خانه+RLM (and +LRM, +ALM) becomes خانه with a plain HEH and no longer matches خانە, with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "2140f4368ade00f1d3b6f2bb25ecaf257c639c3d (trunk, Subversion r1555359, 'LUCENE-5379: Kurdish Analyzer' by rmuir; JIRA LUCENE-5379, migrated as apache/lucene#6442; no PR, pre-GitHub) with its same-day branch_4x backport a670b8d5b22 (r1555360), the copy that shipped in 4.7.0 [read]: the 'case HEH: if (i == len - 1)' test and the later FORMAT deletion in the default branch arrived together, in today's order. Not a regression: the four later commits on the file (813ca77250d LUCENE-7013 license header, 8ef6a0da568 LUCENE-9570 reformat, 8ac26737913 LUCENE-10003 array syntax, 694d797526a LUCENE-10561 package-private) do not change the logic.",
   "introduced_date": "2014-01-04 (trunk and branch_4x; first released in 4.7.0, tagged 2014-02-25)",
   "first_affected_version": "4.7.0 [exec] (the first release with the org.apache.lucene.analysis.ckb package; the follow-up's cross-version main() repro fails all 4 filter and analyzer checks there, Analyzer.normalize being absent before 6.2.0, and both controls pass). 4.6.1, the last release before it, has no Sorani analysis API [exec], so no release ever applied the rule across a trailing mark.",
   "affected_versions": "Every release that ships the Sorani analysis API, 4.7.0 through 10.5.2, and main a9779ef3c193; not fixed. [exec] the follow-up's version-independent public-API repro (SoraniNormalizationFilter with a trailing RLM, LRM and ALM, the SoraniAnalyzer token stream and, from 6.2.0, SoraniAnalyzer.normalize; 2 controls) fails on 4.7.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.0.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da), with both controls passing, and passes on main with the fix shadowed; the finder's JUnit fails 4 of 5 on 9.12.3, 10.5.2 and main (-ea and -da) (it needs org.apache.lucene.tests.analysis, so it does not compile on 9.0.0); the independent reproduction's JUnit fails 6 of 10 on 9.12.3, 10.5.2 and main. [read] the normalize() body is identical, ignoring whitespace and the signature, from 4.7.0 to main, and upstream main a95c754ee003 (2026-10-26) and branch_10x still contain 'case HEH: if (i == len - 1)' (read 2026-10-27). All runs used JDK 25.0.3; ALM (U+061C, Unicode 6.3) is not a FORMAT character on JDKs with older Unicode tables (Java 8), where the ALM would stay in the term and the HEH would still stay HEH (not executed).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-668.html",
   "repro": "repro/LFV-668/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-046",
   "priority": "low",
   "priority_rank": 304,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / vectors",
   "title": "COSINE vectors whose float32 squared norm underflows pass validation and give Inf/NaN scores or poison OSQ segments",
   "summary": "You index, or query with, a non-zero COSINE float vector whose float32 squared norm is 0 or subnormal. You expect it to be rejected like an all-zero vector or to score sensibly. Instead it is accepted: on the default codec it scores +Inf/NaN, a NaN batch maximum hides 64 neighbouring documents and CheckIndex falsely fails; on OSQ one such vector makes the segment centroid NaN, so kNN returns 0 hits and every merge fails.",
   "impact_class": "silent wrong results",
   "introduced_commit": "#366 (f4861159c3c), which added COSINE: latent, not a regression [exec]",
   "introduced_date": "2021-10-11",
   "first_affected_version": "9.0.0 [exec]",
   "affected_versions": "9.0.0 to 10.5.2 (33 releases) and main [exec]; the 0-hit searches and the CheckIndex failure from 10.4.0, the quantized merge failure from 10.2.0",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-046.html",
   "repro": "repro/LFV-046/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-579",
   "priority": "low",
   "priority_rank": 305,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / vectors writers (Lucene99HnswVectorsWriter and Lucene104ScalarQuantizedVectorsWriter field writers over a flat field writer; columnar addBatch DENSE vector bulk path)",
   "title": "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",
   "summary": "You index vectors with IndexWriter#addBatch and a DENSE VectorColumn into an HNSW or scalar-quantized format whose per-field flat storage is your own FlatFieldVectorsWriter (plugged in through the public Lucene99FlatVectorsWriter strategyFactory constructor, without overriding addDenseValues), and Lucene rejects the third vector of a 3-document batch (NaN, or a zero vector with COSINE). You expect what the addDenseValues javadoc and Lucene's own recovery test promise: the batch's documents are deleted, the writer stays open and consistent, and the next commit writes a readable, searchable segment. Instead the flat writer has kept the batch's first two vectors while the HNSW wrapper added no graph nodes for them (and the scalar-quantized wrapper no centroid sums or COSINE magnitudes), so with assertions on the next commit fails ('Level 0 expects to have all nodes', or an assertion in the quantizer) and closes the writer, losing every uncommitted document, and with assertions off it commits an HNSW graph that cannot be read back (EOFException, CheckIndex at level 2 or more fails, a kNN query for a document's own vector returns another document), or the COSINE quantized writer throws ArrayIndexOutOfBoundsException at commit or commits NaN codes so that kNN finds no document of the segment.",
   "impact_class": "data corruption",
   "introduced_commit": "a9779ef3c1939fcd8aaab1b9485f036311797a1d (apache/lucene#16734 'Add bulk vector path to columnar addBatch', by mayya-sharipova, merged to main 2026-10-26) [exec]. Inside the PR, the two wrapper overrides came from PR commit e5f1df0c6a7 (2026-10-01), added after a reviewer (jimczi) asked that the HNSW and scalar-quantized field writers forward to their flat delegate [read]",
   "introduced_date": "2026-10-26 (merged; commit date 2026-10-26 -0400)",
   "first_affected_version": "unreleased (main only, 11.0.0-SNAPSHOT since a9779ef3c193; CHANGES.txt lists #16734 under 11.0.0, so it would first ship in 11.0.0 unless fixed or backported first; not on branch_10x, branch_10_6 or branch_10_5) [exec]",
   "affected_versions": "main a9779ef3c193 [exec]; upstream main a95c754ee003 (2026-10-26) [read]. Not affected: the parent f4cc6ac2097c, the previous hunt main ea57360912ed, 10.5.0 and 10.5.2 [exec]; 9.12.3 and older [exec]; branch_10x, branch_10_6 and branch_10_5 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-579.html",
   "repro": "repro/LFV-579/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-521",
   "priority": "low",
   "priority_rank": 306,
   "novelty": "new",
   "withheld": false,
   "area": "facet / taxonomy writer (DirectoryTaxonomyWriter.addCategory exception safety: cacheIsComplete and reader-manager freshness after a failed near-real-time reader open)",
   "title": "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",
   "summary": "You index facet categories with a default DirectoryTaxonomyWriter; one addCategory call throws an IOException because the writer could not open its near-real-time reader (for example on the call whose new category makes the 4000-entry cache evict), and you keep using the writer, as IndexWriter allows after a non-fatal exception. You expect a later addCategory of a category that is already in the taxonomy to return its existing ordinal, as TaxonomyWriter.addCategory promises. Instead the writer still trusts its cache as complete (or its old reader), indexes the category again and returns a new ordinal (l0: 4001 instead of 1; a retried 'new': 14 instead of 13), and commit() persists one label under two ordinals, so its facet counts are split between them.",
   "impact_class": "data corruption",
   "introduced_commit": "Two sites. Site A (addToCache calls refreshReaderManager() before 'cacheIsComplete = false', so a refresh that throws leaves the cache marked complete right after an eviction): the facet module's first commit, LUCENE-3079 'add faceting module' (now #4152, committed by shaie), d4e1a420d525ecf022ee8c3594f3683005c5cc85 (branch_3x, svn r1141060) and its trunk port 4291f52c70d7b6324456663cc3a7ec0df855ccb7 (svn r1141246, rmuir) [read]. Site B (addCategoryDocument indexes the document and advances nextID before the fallible getTaxoArrays() and addToCache): LUCENE-4596 'DirectoryTaxonomyWriter concurrency bug' (now #5661, by shaie), bc61e7cdc9b43f8eff78da42d96481cdfd4aa288 (trunk, svn r1418860) and 2bde91dc0d2a8d2a29072bd36a19949d2ff07524 (branch_4x, svn r1418873), which moved addToCache last on purpose to fix a concurrency bug [exec]. Default-configuration exposure of site A: dc33ade76d36834ffe7b862f966ca31414712490 (#12092, main) and 9d6173148d7a7c25128f86ee61fca00ac88baaf7 (#12093, branch_9x), both by vigyasharma, addressing #12000, which made the evicting LruTaxonomyWriterCache(4000) the default [exec]",
   "introduced_date": "2011-06-29 (site A, LUCENE-3079); 2012-12-09 (site B, LUCENE-4596); 2023-01-18 (#12092 / #12093: site A reachable with the default cache)",
   "first_affected_version": "3.4.0 (2011-09-14) [exec], with an explicitly configured LruTaxonomyWriterCache (site A); with the default configuration 4.1.0 (2013-01-21) [exec] (site B), and site A also from 9.5.0 (2023-01-25) [exec]; 3.3 and earlier have no facet module [read]",
   "affected_versions": "every release before 10.6.0 with the facet module, 3.4.0 through 10.5.2, plus main ea57360912ed; never fixed. Site A with an explicit LRU cache: 3.4.0 - 10.5.2 and main [exec]. Site A with the default cache: 9.5.0 - 10.5.2 and main [exec]; not triggered on 3.4.0 - 9.4.2, whose default caches never evict (Cl2oTaxonomyWriterCache to 7.0.1, UTF8TaxonomyWriterCache 7.1.0 - 9.4.2) [exec]. Site B: 4.1.0 - 10.5.2 and main [exec]; not affected 3.4.0 - 4.0.0, which cache the category before touching the parent array [exec]. The finder's 3-test JUnit fails 3 of 3 on main, 10.5.2, 9.12.3 and 9.5.0 with -ea, and with -da on main, 10.5.2 and 9.12.3 (on 9.4.2 test 1 fails only because its trigger is unreachable with the non-evicting default cache) [exec]; the independent reproduction's own JUnit fails 2 of 2 on main, 10.5.2 and 9.12.3 with -ea and -da [exec]; -ea and -da agree everywhere both were run. DirectoryTaxonomyWriter.java is unchanged from f339e24e8ed (#12337, 2024-02-08, in 10.0.0) through branch_10_6 and upstream main ffa9d816eeb4 (2026-10-26) [read]. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-521.html",
   "repro": "repro/LFV-521/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-978",
   "priority": "low",
   "priority_rank": 307,
   "novelty": "new",
   "withheld": false,
   "area": "facet / taxonomy writer (DirectoryTaxonomyWriter.replaceTaxonomy failure path: deleteAll before addIndexes, writer state reset only on success)",
   "title": "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",
   "summary": "You call replaceTaxonomy on a DirectoryTaxonomyWriter to swap in a rebuilt taxonomy, the call throws (in the repro an IOException while a file of a valid, closed source is read, or IndexNotFoundException because the source holds no index), and the application then closes the writer as usual or keeps using it. You expect the failed call to leave the taxonomy that the writer and its last commit describe, so that addCategory returns 'its existing ordinal' for an existing category (TaxonomyWriter.java:53) and the root keeps ordinal 0. Instead replaceTaxonomy has already emptied the internal index with deleteAll() while the writer keeps its old ordinal counter, cache and parent arrays: close() commits a taxonomy of size 0 (expected 4), a kept-open writer returns ordinal 2 for dim/a although the commit no longer has it and stores a new label with ordinal 4 at docID 0, and over a main index that still refers to the old ordinals the facet counts a=2 b=1 x=1 y=1 come out as x=3 y=2.",
   "impact_class": "data corruption",
   "introduced_commit": "8b5af86c45bb0caaf82a26b34f0dc1af21d97fde (trunk, svn r1346784) and its branch_4x port 806e16859e4ade83eea9e9d0cfba79fb50877180 (svn r1346793, the commit that shipped in 4.0.0-ALPHA), LUCENE-4108 'Add replaceTaxonomy to DirectoryTaxonomyWriter' (now #5180, by shaie; an SVN-era patch, no PR) [read] [exec]",
   "introduced_date": "2012-06-06 (author date = commit date for both commits: 08:46:10 UTC trunk, 09:05:02 UTC branch_4x; issue opened 2012-06-04, resolved 2012-06-18)",
   "first_affected_version": "4.0.0-ALPHA (2012-06-29) [exec], the first release with the API; first GA release 4.0.0 (2012-10-11) [exec]; 3.6.0 and 3.6.2 have no replaceTaxonomy [exec] (the author declined a 3.6.1 backport, #5180). The locked-source trigger exists only from 4.7.0 (LUCENE-5228, d3416c198a1, made addIndexes(Directory...) take the source's write lock; before it such a replace succeeds) [exec]",
   "affected_versions": "every release from 4.0.0-ALPHA to 10.6.0 (branch_10_6 head 4ae946e5a9b9) and main a9779ef3c193; never fixed [exec] [read]. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-978.html",
   "repro": "repro/LFV-978/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-617",
   "priority": "low",
   "priority_rank": 308,
   "novelty": "new",
   "withheld": false,
   "area": "core index / UpgradeIndexMergePolicy and IndexUpgrader with OneMergeWrappingMergePolicy delegates (SoftDeletesRetentionMergePolicy)",
   "title": "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",
   "summary": "You configure soft deletes with SoftDeletesRetentionMergePolicy(\"soft\", MatchAllDocsQuery::new, new TieredMergePolicy()), which must keep every soft-deleted document, and upgrade a one-segment index written by Lucene 10.5.2 (10 visible plus 3 soft-deleted documents) with new IndexUpgrader(dir, thatConfig, false).upgrade(). You expect the segment to be rewritten in the current format with all 13 documents, exactly as happens when the same index has two old segments. Instead TieredMergePolicy treats the lone segment as already merged, UpgradeIndexMergePolicy rewrites it with its own 'merge remaining ones into new segment' OneMerge that the retention policy never wraps, and the 3 retained documents are purged with no error (maxDoc 13 -> 10; partial retention queries lose their documents the same way).",
   "impact_class": "silent wrong results",
   "introduced_commit": "02fa5a0b0593 (branch_7x; master ecc17f902330), LUCENE-8233 'Add support for soft deletes to IndexWriter' (JIRA patch, no GitHub PR; migrated issue apache/lucene#9280). It added SoftDeletesRetentionMergePolicy as a OneMergeWrappingMergePolicy whose OneMerge wrapper (wrapForMerge -> applyRetentionQuery) is the only thing that keeps retained soft-deleted documents through a merge, and nothing routes UpgradeIndexMergePolicy's own merge through it [read]. The defective line spec.add(new OneMerge(newInfos)) (UpgradeIndexMergePolicy.java:136) is older: LUCENE-3082 (600a50bb2ae8, 2011-05-09, first release 3.2). It has bypassed OneMergeWrappingMergePolicy wrapping since that class appeared (LUCENE-7688, 6.5.0) but lost no data before soft deletes [exec]. LUCENE-7976 (branch_7x 9c4e315c1cb3, master 2519025fdafe, 7.5.0) widened the trigger from a lone non-compound-file old segment to any lone old segment without deletes [exec].",
   "introduced_date": "2018-04-04 (LUCENE-8233 committed to branch_7x and master); the defective line 2011-05-09 (LUCENE-3082); trigger widened 2018-06-15 (LUCENE-7976)",
   "first_affected_version": "7.4.0 [exec], the first release with soft deletes and SoftDeletesRetentionMergePolicy. On 7.4.0 the lone old segment must not be a compound file (a lone compound-file old segment is merged by TieredMergePolicy itself, wrapped, and kept [exec]), and the only IndexUpgrader trigger is an index written by an older release that started soft-deleting under 7.4.0 [exec]. 7.5.0 is the first release in which an ordinary upgrade of a soft-deletes index (written by 7.4.0) loses the documents, compound file or not [exec]. 7.3.1 and earlier: the API is absent [exec].",
   "affected_versions": "Every release from 7.4.0 to 10.6.0 (10.6.0 by reading), and main a9779ef3c193; never fixed. Executed (retain-all policy, one old segment without hard deletes, 13 -> 10 documents) on 7.4.0 (-ea and -da), 7.5.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) with official release jars and JDK 25 [exec]; the two-old-segment control keeps all 13 documents on 7.4.0, 7.5.0, 8.0.0, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main [exec]; the releases in between share the unchanged code path [read]. The branch_10_6 head (10.6.0, released 2026-10-29) and the unreleased branch_10x head have the same code [read]. The 7 commits on main since the hunt's previous base do not touch any of the files involved. Not affected: 7.3.1 and earlier (no soft deletes) [exec].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-617.html",
   "repro": "repro/LFV-617/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-520",
   "priority": "low",
   "priority_rank": 309,
   "novelty": "new",
   "withheld": false,
   "area": "facet / taxonomy writer (DirectoryTaxonomyWriter.addCategoryDocument with the ordinal-document enrichment hook: ReindexingEnrichedDirectoryTaxonomyWriter / enrichOrdinalDocument)",
   "title": "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",
   "summary": "An application adds its own fields to taxonomy ordinal documents with ReindexingEnrichedDirectoryTaxonomyWriter (or an enrichOrdinalDocument override), IndexWriter rejects one category's field (for example a term over 32766 bytes or a vector of a different dimension), addCategory throws IllegalArgumentException, and the application skips that category and keeps going. You expect only that category to be missing and every later addCategory to return the category's ordinal, the one a taxonomy reader reports for it, with an existing category keeping its ordinal (TaxonomyWriter.addCategory). Instead IndexWriter keeps the rejected document as a deleted document that still uses up a docID while the writer's ordinal counter does not move, so every later category gets an ordinal one below its docID: readers resolve it to the previous category (even the rejected label), facet counts land under the wrong labels or throw ArrayIndexOutOfBoundsException or CorruptIndexException, and a reopened writer returns 3 instead of 2 for a category that already exists.",
   "impact_class": "data corruption",
   "introduced_commit": "f339e24e8ed64bf64ef4bb05111d252ecdacde1e (main) and its branch_9x backport 2d713d904d011767f5e98bbc763f84a0b4fa508f: apache/lucene#12337 'Index arbitrary fields in taxonomy docs' (author stefanvodita, for issue #12336; CHANGES 9.10.0 'GITHUB#12336: Index additional data per facet label in the taxonomy') [read]. It added the first way to put arbitrary, rejectable fields into an ordinal document and so made older code reachable: 'indexWriter.addDocument(d); int id = nextID++;' dates from 4291f52c70d7 (2011-06-29, LUCENE-3079, the faceting module port; nextID.getAndIncrement() since bcc116057d1, #11775, 2022), and IndexWriter's keep-the-docID-and-delete behaviour for non-aborting failures is documented in DocumentsWriterPerThread since 858e309c7b1 (2014, LUCENE-5843); before #12337 the category's own term could not be rejected because FacetLabel.MAX_CATEGORY_PATH_LENGTH (LUCENE-5048, a287431293e, 2013) keeps it below IndexWriter.MAX_TERM_LENGTH",
   "introduced_date": "2024-02-08 (#12337 merged 2024-02-08T11:02:12Z; PR opened 2023-05-27)",
   "first_affected_version": "9.10.0 [exec] (first release with enrichOrdinalDocument and ReindexingEnrichedDirectoryTaxonomyWriter; 10.0.0 [exec] is the first affected 10.x release); not affected: 9.9.2 and earlier, where the API is absent (both repros fail to compile on 9.9.2 and the plain-writer control passes [exec])",
   "affected_versions": "every release from 9.10.0 through 10.5.2 (the last 10.x release before 10.6.0), including 9.12.3 (latest 9.x), plus main ea57360912ed; never fixed. [exec] fails: 9.10.0 (-ea and -da), 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da), each with the finder's JUnit (2 of 2) and the independent reproduction's JUnit (4 of 5, control passes). [read] 9.11.0, 9.11.1, 9.12.0-9.12.2 and 10.1.0-10.5.1 by tag containment of the introducing commits and unchanged code of both writer files; upstream main, branch_10x and branch_10_6 have no commit on the two files after #12337 (GitHub commits API, 2026-10-26). Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-520.html",
   "repro": "repro/LFV-520/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-977",
   "priority": "low",
   "priority_rank": 310,
   "novelty": "new",
   "withheld": false,
   "area": "facet / taxonomy (ReindexingEnrichedDirectoryTaxonomyWriter.reindexWithNewOrdinalData)",
   "title": "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",
   "summary": "You call reindexWithNewOrdinalData on a ReindexingEnrichedDirectoryTaxonomyWriter with a new ordinal-data appender, the appender throws for one category (in the repro an IllegalStateException on d/b; an appender that reads the last label component throws on the root category, which reaches the appender only during a reindex), and the application then closes the writer as usual. You expect the method's promise 'The ordinals themselves will be preserved, so the caller does not need to update references to them in the main index' to hold, or at least the last committed taxonomy to survive the failed call. Instead the method has already deleted the whole taxonomy and re-added only the categories before the failing one, and close() commits that: the taxonomy shrinks from 5 to 3 categories, d/b and d/c resolve to -1 while main-index documents still carry their ordinals 3 and 4, and if the writer is kept in use new categories take those ordinals, so facet counts a=2 b=1 w=1 z=1 come out as w=3 z=2 with no error (other layouts make FastTaxonomyFacetCounts throw ArrayIndexOutOfBoundsException).",
   "impact_class": "data corruption",
   "introduced_commit": "f339e24e8ed64bf64ef4bb05111d252ecdacde1e (main) and its branch_9x cherry-pick 2d713d904d011767f5e98bbc763f84a0b4fa508f (the commit that shipped in 9.10.0), apache/lucene#12337 'Index arbitrary fields in taxonomy docs' (author stefanvodita; issue #12336; CHANGES 9.10.0 New Features: 'GITHUB#12336: Index additional data per facet label in the taxonomy.') [read] [exec]. The commit in DirectoryTaxonomyWriter.close() is older (javadoc from LUCENE-3079, 2011; the explicit commit() line from LUCENE-4972, e2c54ff680b8, 2013) and only persists the damage",
   "introduced_date": "2024-02-08 (f339e24e8ed6 authored and committed 2024-02-08T11:02:12Z, squash merge; cherry-pick 2d713d904d committed 2024-02-08T11:13:36Z; PR opened 2023-05-27)",
   "first_affected_version": "9.10.0 [exec], the first release with the API; 9.9.2 has no ReindexingEnrichedDirectoryTaxonomyWriter [exec]; the main-line commit first ships in 10.0.0 [read]",
   "affected_versions": "9.10.0, 9.11.0, 9.11.1, 9.12.0, 9.12.1, 9.12.2, 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2, 10.6.0 (branch_10_6 head 4ae946e5a9b) and main a9779ef3c193 [exec]. ReindexingEnrichedDirectoryTaxonomyWriter.java is byte-identical (sha1 prefix cb9719702c76) in all 19 release tags, the history head 7cecf795236 and main a9779ef3c193, and the deleteAll() body is identical in all 19 tags [read]; the releases not executed are inferred from that. Not fixed upstream: the last commit touching the file on main (head 645d4fe14a20, 2026-10-28), branch_10x and branch_10_6 is still f339e24e8ed6 [read]. Not a regression. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-977.html",
   "repro": "repro/LFV-977/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-244",
   "priority": "low",
   "priority_rank": 311,
   "novelty": "new",
   "withheld": false,
   "area": "core / codecs: term vectors (TermVectorsWriter.addAllDocVectors merge copier; Lucene90 compressing term-vector writer and reader), reached through IndexWriter.addIndexes(CodecReader)",
   "title": "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",
   "summary": "You copy an index with IndexWriter.addIndexes(CodecReader...) through a reader that removes some terms consistently from the postings and the term vectors (CheckIndex at its strictest level accepts this reader), so one document's term-vector field is left with zero terms. You expect the new segment to read back and merge like any other, as the postings do (the postings writer simply drops the emptied field). Instead the default term-vector format writes per-field AvgCharsPerTerm floats that its own reader does not expect, so when the emptied field stores offsets the other documents of the chunk throw 'offset 0 is invalid' on read, and because the reader lists the emptied field but returns null for it, the next merge that re-encodes the segment fails with 'Wrong number of values added' and closes the IndexWriter, on every retry.",
   "impact_class": "data corruption",
   "introduced_commit": "5837fe83bd813b021d133c9f806cbcf215d24f67 ('LUCENE-4599: New compressed TVF impl: CompressingTermVectorsFormat', Adrien Grand (jpountz), 2013-01-21, Subversion r1436556, no pull request; LUCENE-4599 = apache/lucene#5664; branch_4x backport 4a62a579a70): the writer writes AvgCharsPerTerm when any field instance of the chunk has the OFFSETS flag while the reader reads it only when the chunk has an offset occurrence, and the reader returns null from terms() for a listed zero-term field; made the default term-vector format by 94b17a28de5 (LUCENE-4733 = apache/lucene#5798, 2013-02-02; branch_4x e3710747d87). Latent precondition: 873f1999244 (LUCENE-2621 = apache/lucene#3695, rmuir, 2011-11-16) added the codec-agnostic merge copier TermVectorsWriter.addAllDocVectors with startDocument(Fields.size()) before the fields are inspected, the null-Terms skip and startField(numTerms = 0) for an empty Terms, harmless with Lucene40TermVectorsFormat [exec]. Symptom change, not the bug: 873ac5f162a (LUCENE-9907, apache/lucene#72, 2021-04-15, first released in 9.0.0) moved flushFields/flushFlags to DirectWriter, whose count check makes the poisoned merge throw instead of silently writing wrong-document term vectors [read]",
   "introduced_date": "2013-01-21 (compressing term-vector format, LUCENE-4599); 2013-02-02 (made the default, LUCENE-4733); the merge-copier part dates from 2011-11-16 (LUCENE-2621)",
   "first_affected_version": "4.2.0 [exec] (tag 2013-03-11; the first release whose default term-vector format is the compressing one; on the 4.x API the trigger is addIndexes(IndexReader...) with a FilterAtomicReader, from 5.0.0 addIndexes(CodecReader...) with SlowCodecReaderWrapper); 4.1.0 is not affected [exec], and the 4.2.0 jars with only the destination term-vector format switched back to Lucene40TermVectorsFormat are not affected either [exec]",
   "affected_versions": "every release from 4.2.0 through 10.5.2, 10.6.0 (by reading) and main ea57360912ed. [exec] with a filter that removes the term from both the postings and the term vectors: 4.2.0, 4.10.4, 5.5.5, 6.6.6, 7.0.0, 8.11.4, 9.0.0 and 9.4.2 (follow-up history probes, -ea and -da), 9.5.0 and 9.12.3 (finder src-9x), 10.5.2 and main (-ea and -da): all fail; the independent reproduction's independent test fails on main (-ea, -da), 10.5.2 (-ea) and 9.12.3 (-ea, -da); the security probe also ran 10.3.2 and 10.4.0 (-da). Symptoms differ by version: before 9.0.0 with -da the re-encoding merge succeeds but writes one document's term vectors under another document (4.2.0-8.11.4), from 9.0.0 it throws 'Wrong number of values added' and closes the writer; chunk reads before 10.4.0 with -da return silently wrong bytes (including other documents' term bytes on 9.12.3 and 10.3.2) or throw ArrayIndexOutOfBoundsException, from 10.4.0 (#15570) they throw IOException 'offset 0 is invalid'. [read] every release in between has the same lines by blame; 5.0.0-5.2.x not executed (older Terms#iterator API). Not affected: 4.1.0 and older [exec]. Not fixed on main [exec]; branch_10x 657014b3c57 and branch_10_6 4ae946e5a9b have the same TermVectorsWriter and reader files [read]. All runs on aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-244.html",
   "repro": "repro/LFV-244/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-760",
   "priority": "low",
   "priority_rank": 312,
   "novelty": "new",
   "withheld": false,
   "area": "index / index sorting (IndexingChain index-sort field validation and flush-time sort)",
   "title": "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)",
   "summary": "You configure an index sort on a field, for example new Sort(new SortField(\"sort\", SortField.Type.STRING)), and add a document that carries that field only as a StringField, without the SortedDocValuesField that sorting reads, before any committed document has the field. You expect addDocument to reject the document up front, as it has rejected a doc-values field of the wrong type since LUCENE-8441 (7.5.0), or the field to count as missing. Instead addDocument accepts it, and the next flush or commit throws IllegalStateException 'unexpected docvalues type NONE for field 'sort' (expected=SORTED). Re-index with correct docvalues type.' and closes the IndexWriter, so every document added since the last commit is lost.",
   "impact_class": "crash",
   "introduced_commit": "Flush-time symptom: LUCENE-9330 'Make SortFields responsible for index sorting and serialization' (apache/lucene-solr#1440 by romseygeek, issue #10370): master de2bad9039054af753bc2c847565f63f05f4fdd7 (first released in 9.0.0) and branch_8x ad0cefb8ec279e4fae0b104d487deb36ff2f9d27 (first released in 8.6.0). It replaced the 8.5 flush code, which skipped a sort field without a doc-values writer ('// safe to ignore, sort field with no values or already seen before'), with SortField#getIndexSorter reading through DocValues.getNumeric/getSorted/getBinary, whose checkField throws for a field whose FieldInfo has doc-values type NONE [exec]. The missing up-front check is older [read]: since index sorting moved into IndexWriterConfig (LUCENE-6766, 6.2.0) such a document has always been accepted; LUCENE-8441 (679b4aa71d2 on master, 276a851b054 on branch_7x, 7.5.0) validated only fields that carry doc values, and LUCENE-9334 (d03662c48bf, 9.0.0) moved that check into IndexingChain#initializeFieldInfo behind 's.docValuesType != DocValuesType.NONE'.",
   "introduced_date": "2020-05-22 (LUCENE-9330, master and branch_8x); the validation gap dates from 2016-05 (LUCENE-6766, 6.2.0)",
   "first_affected_version": "8.6.0 for the flush-time writer close [exec]; 8.5.2, the last release before it, commits the document [exec]. The underlying validation gap is in every release since 6.2.0 [exec]: there the bad segment was committed, and then every sorted search on the field and every merge that included the segment threw, the merge closing the writer in later sessions too (CheckIndex reports the index as not clean from 6.5.0)",
   "affected_versions": "[exec] the flush symptom (document accepted, commit throws IllegalStateException, writer closed with a tragic exception, buffered documents lost) on all 49 releases from 8.6.0 to 10.5.2 (8.6.0-8.6.3, 8.7.0, 8.8.0-8.8.2, 8.9.0, 8.10.0-8.10.1, 8.11.0-8.11.4, every 9.x release 9.0.0-9.12.3, every 10.x release 10.0.0-10.5.2) and on main a9779ef3c193, with the version-portable flush probe (-ea); the candidate JUnit fails 2 of 2 on main (-ea and -da), 10.5.2, 9.12.3 and 9.1.0; the independent reproduction's JUnit fails for all 7 built-in sort types on main (-ea and -da), 10.5.2 and 9.12.3, and its BinarySortField test on main; the intended-behaviour check's probe fails on main, 10.5.2, 10.4.0 and 9.12.3. [exec] not affected at flush: 7.5.0 and 8.4.0-8.5.2 (the commit succeeds), but 6.2.0-8.5.2 have the older, persistent form described under first_affected_version. In 8.6.0-8.11.4 the document also gets through when the field already has doc values in a committed segment [exec]; from 9.0.0 only on the field's first appearance. Not fixed upstream: main 645d4fe14a2 [exec]; branch_10x 657014b3c57 and branch_10_6 4ae946e5a9b (10.6.0 RC1, released 2026-10-29) carry the same NONE guard at IndexingChain.java:1321 [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-760.html",
   "repro": "repro/LFV-760/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-787",
   "priority": "low",
   "priority_rank": 313,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / document suggester (CompletionFieldsConsumer type check at flush and merge; core flush and merge abort paths)",
   "title": "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)",
   "summary": "You index a SuggestField document and a ContextSuggestField document under the same field name; addDocument accepts both, and the suggest module's design (LUCENE-6459) says such a mix is rejected with an IllegalArgumentException, so you expect an input error that leaves the writer and your other documents alone. Instead the type is compared only in CompletionFieldsConsumer while postings are written, so the IllegalArgumentException 'single field name has mixed types' fires inside flush or merge, where IndexWriter treats every exception as tragic: the writer closes and drops every uncommitted document. If the two types landed in different segments, both commit cleanly, but every merge that combines them closes the writer, also in any new writer, until you delete all documents of one type.",
   "impact_class": "index unusable",
   "introduced_commit": "be4d58c7740bea4e797eb1acff6355eb260e7c93 (trunk, svn r1682158) and its branch_5x commit 380bb29f395 (svn r1682170, shipped in 5.3.0): LUCENE-6459 'Query Interface for suggest API' (now apache/lucene#7518; committed by GitHub mikemccand for GitHub areek; no PR, svn era). It added ContextSuggestField (type byte 1) next to SuggestField (type byte 0), the type byte in every completion posting payload, the only type comparison (CompletionTermWriter.write, at flush and merge) and its only test, testMixedSuggestFields [read]. Present from the first day of the API; not a regression",
   "introduced_date": "2015-05-28 (trunk and branch_5x commits)",
   "first_affected_version": "5.3.0 [exec]; 5.2.1 and earlier have no ContextSuggestField (compile error, API absent, not a result about the bug). Correction to the finder's 'since 5.2': the branch_5x commit is not an ancestor of the 5.2.0 or 5.2.1 tags, and CHANGES.txt lists LUCENE-6459 under 5.3.0",
   "affected_versions": "Every release from 5.3.0 through 10.6.0 (10.6.0 by reading) and main ea57360912ed and a9779ef3c193; never fixed (upstream main f7bcc0abd816, branch_10x, branch_10_6 and branch_9x carry the same check; no open PR touches CompletionFieldsConsumer, SuggestField, ContextSuggestField or CompletionQuery, read-only check 2026-10-27). [exec] follow-up main() probe and JUnit: FAIL on 5.3.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main a9779ef3c193 (-ea; -da also on 5.3.0 and main), same-type controls pass; finder's JUnit fails 4 of 4 on main (-ea and -da), 10.5.2, 10.0.0, 9.12.3, 9.0.0 and 8.11.2 (version-portable copy); the independent reproduction's JUnit fails 5 of 6 on main (-ea and -da), 10.5.2 and 9.12.3 (-ea and -da); the intended-behaviour check re-ran the finder's JUnit on main and 10.5.2. [read] all 94 release tags 5.3.0-10.5.2 in the history clone contain the check unchanged in substance; the clone lacks the 8.8.2-8.11.x tags (8.11.4 executed). Releases 5.x-8.x ran on JDK 25, outside their supported JDKs; the failing path is plain Java and the controls pass on the same JVM",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-787.html",
   "repro": "repro/LFV-787/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-759",
   "priority": "low",
   "priority_rank": 314,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter doc-values updates with index sorting (BinarySortField, custom IndexSorter)",
   "title": "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",
   "summary": "You configure an index sort with a BinarySortField subclass whose key is derived from another doc-values field (sort by the numeric field price, ties broken by the binary field sku, declared on sku), index a(5), b(7), c(8), and then change c's price to 1 with updateNumericDocValue; you expect the writer either to reject the update, as it rejects an update of sku itself ('cannot update docvalues field involved in the index sort'), or to keep the segment sorted. Instead the update is accepted, the segment stays in the order a, b, c while still declaring the sort, CheckIndex reports 'segment has indexSort=<binary: \"sku\"> but docID=1 sorts after docID=2', and a top-1 search sorted by the index sort returns a instead of c because it stops at the first non-competitive document. The cause is that IndexWriterConfig#setIndexSort protects only the SortField#getField names, while a custom index sort may read any field.",
   "impact_class": "data corruption",
   "introduced_commit": "ad0cefb8ec2 (branch_8x, first released in 8.6.0) and de2bad90390 (master, first released in 9.0.0): LUCENE-9330 (now #10370), apache/lucene-solr#1440 'Make SortFields responsible for index sorting and serialization' by romseygeek, approved by jpountz [read]. It made index sorting pluggable (SortField#getIndexSorter, IndexSorter value providers that read any field from a LeafReader, SPI SortFieldProvider) and switched the index-sort doc-values type check to probing the sorter, but left indexSortFields and the update guards keyed on SortField#getField. The guard itself comes from LUCENE-7581 (#8632, 4efbde4e762, 6.4.0), complete when written; apache/lucene#16202 (e6f12f31d08 on main, 5a3ec9ad9d8 on branch_10x, 10.5.0, by jimczi) added BinarySortField, the first javadoc that sanctions a key derived from other doc-values fields; #16581 (169cbffd12f; backport eaa3a7a9edb, released in 10.6.0) made SORTED_NUMERIC companion fields updatable too",
   "introduced_date": "2020-05-22 (LUCENE-9330 merged); 2026-06-05 for the BinarySortField form (#16202)",
   "first_affected_version": "8.6.0 [exec]; BinarySortField form 10.5.0 [exec]",
   "affected_versions": "[exec] generic form (a Type.CUSTOM SortField declaring sku whose IndexSorter reads NUMERIC price): fails on all 49 releases 8.6.0 to 10.5.2 and on main a9779ef3c193 with -ea, also with -da on 8.6.0, 9.12.3, 10.5.2 and main (follow-up history sweep); the intended-behaviour check's own JUnit probe fails on 9.12.3, 10.5.2 and main. BinarySortField form (the finder's JUnit): fails on 10.5.0, 10.5.1, 10.5.2 and main (-ea and -da); the independent reproduction's JUnit on 10.5.0, 10.5.2 and main. SORTED_NUMERIC companion via updateSortedNumericDocValue: main (bounded-exhaustive harness) and 10.6.0 by reading (#16581 shipped in 10.6.0 as backport eaa3a7a9edb). [read] branch_10_6 (10.6.0, released 2026-10-29) has the same code; upstream main f7bcc0abd81 is unchanged (no commit after a9779ef3c193 touches IndexWriter.java, IndexWriterConfig.java, BinarySortField.java or IndexSorter.java). Not affected: 8.5.2 and older (no accepted index sort can read a field other than SortField#getField). All runs with JDK 25.0.3 on aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-759.html",
   "repro": "repro/LFV-759/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-726",
   "priority": "low",
   "priority_rank": 315,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter addIndexes(CodecReader...) accounting (reserveDocs, addIndexesReaderMerge soft-delete count) x MergePolicy#findMerges(CodecReader...) / OneMerge#wrapForMerge",
   "title": "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)",
   "summary": "You install a merge policy whose findMerges(CodecReader...) returns a OneMerge whose wrapForMerge removes documents (its javadoc allows this: 'add/remove fields or documents'), for example to drop soft-deleted or expired documents while importing, and call IndexWriter.addIndexes(CodecReader...); you expect the writer to account for the documents the merge actually wrote, as the regular merge path does. Instead addIndexes reserves the live-document count of the unwrapped readers, so getPendingNumDocs stays too high for the rest of the writer session, and with soft deletes it stores the unwrapped readers' soft-delete count in the new segment, so DocStats.numDocs under-counts and CheckIndex (level 2 and up) reports 'actual soft deletes: 0 but expected: 1'. With assertions off, later operations then build on that wrong count: a live document can vanish from the committed index, and a later ordinary forceMerge can merge two documents into one doc ID (a search for one returns the other) or fail with CorruptIndexException.",
   "impact_class": "data corruption",
   "introduced_commit": "f7cab1645017d863331b42900581b67d3591e2da (apache/lucene#12622, 'Add a merge policy wrapper that performs recursive graph bisection on merge.', author jpountz; branch_9x backport 6b1538b33136a4737ad0d22b3633e62f3d7f362b, same day) [exec]. It made IndexWriter#addIndexesReaderMerge call merge.wrapForMerge on each incoming reader (IndexWriter.java:3542-3546) and reworded the OneMerge#wrapForMerge javadoc to 'add/remove fields or documents', but left the two counts on the unwrapped readers: merge.totalMaxDoc (MergePolicy.java:245-256), which addIndexes reserves (IndexWriter.java:3341-3356), and the soft-delete count (IndexWriter.java:3502-3512, persisted at 3600-3601). Those count sites come from 698f40ad51af (#633, LUCENE-10216, 2022-07-06; branch_9x 5dd8e9bdc5a) and were right until #12622, because before it the merged readers were exactly the counted readers [read].",
   "introduced_date": "2023-11-23 (main f7cab164501 and branch_9x 6b1538b3313)",
   "first_affected_version": "9.9.0 (tag 2023-12-04) [exec]: first release containing 6b1538b3313; 9.8.0 does not contain it [git merge-base] and is not affected [exec]. On the 10.x line the main commit f7cab164501 first ships in 10.0.0 [exec].",
   "affected_versions": "9.9.0, 9.9.1, 9.9.2, 9.10.0, 9.11.0, 9.11.1, 9.12.0, 9.12.1, 9.12.2, 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2, 10.6.0 (by reading) and main (11.0.0-SNAPSHOT). Executed: 9.9.0, 9.12.3, 10.0.0, 10.5.2, main a9779ef3c193 and the commit build 6b1538b3313. Read only: the other releases (all four fix-site statements and the wrapForMerge call are present in every release tag from 9.9.0 to 10.5.2), and the heads branch_10_6 2763db11b0a (contained in 10.6.0, released 2026-10-29) and the unreleased branch_10x 1309534296e (same statements). Not affected: 9.4.0 to 9.8.0 (the API exists but addIndexes ignores OneMerge#wrapForMerge, so the counts match what is written [exec]); before 9.4.0 the API does not exist (MergePolicy#findMerges(CodecReader...) and OneMerge(CodecReader...) were added by #633) [exec]. Not fixed upstream: main a95c754ee003 (2026-10-26) has identical IndexWriter.java, MergePolicy.java and PendingSoftDeletes.java [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-726.html",
   "repro": "repro/LFV-726/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-151",
   "priority": "low",
   "priority_rank": 316,
   "novelty": "new",
   "withheld": false,
   "area": "facet / range and range-on-range facet counts (FacetResult.value with a fastMatchQuery)",
   "title": "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",
   "summary": "You build a range facet counter (LongRangeFacetCounts or DoubleRangeFacetCounts on a single-valued field or values source, or a range-on-range counter) with a fastMatchQuery that removes only hits outside every range, which is what it is for, and read FacetResult.value. You expect the same dimension total as without the fastMatchQuery: the number of hits that fall into at least one range. Instead each segment adds all of its hits up front but subtracts only the documents the fastMatchQuery let through, so the hits it rejected stay in the total (3 instead of 1 in the minimal repro, while the range count is 1), and the same documents and query give 3 in one segment and 1 in two.",
   "impact_class": "silent wrong results",
   "introduced_commit": "20a280c33cd9 (trunk, 'LUCENE-5418: faster drill-down/sideways on costly filters', by mikemccand; same-day branch_4x commit 5c0bbfb86f5e, the one released in 4.7.0; JIRA LUCENE-5418, migrated as apache/lucene#6481, svn patch without a GitHub PR): it added the optional fast-match filter to LongRangeFacetCounts and DoubleRangeFacetCounts and kept the older per-segment 'totCount += hits.totalHits' (LUCENE-5339/5371, 2013), so rejected documents are added and never subtracted [read]; the range-on-range copy came with cbfed77fd33c (apache/lucene#11901 'Github#11869: Add RangeOnRangeFacetCounts', by mdmarshmallow, merged 2022-12-30; branch_9x d9fc418914ae, released in 9.5.0)",
   "introduced_date": "2014-02-06 (LUCENE-5418, classic range facets); 2022-12-30 (#11901, range-on-range facets)",
   "first_affected_version": "4.7.0 [exec] for LongRangeFacetCounts and DoubleRangeFacetCounts (4.6.1 has no such class or fast-match parameter [exec]); 9.5.0 [exec] for Long/DoubleRangeOnRangeFacetCounts (9.4.2 has no rangeonrange package [exec])",
   "affected_versions": "every release from 4.7.0 to 10.5.2 and main ea57360912ed. [exec] classic range facets on 4.7.0, 4.10.4, 5.3.0, 5.5.5, 6.6.6, 7.0.0, 7.7.3, 8.11.4, 9.0.0, 9.10.0, 9.11.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea, and -da on 4.7.0 and main); range-on-range (Long and Double) on 9.5.0, 9.12.3, 10.5.2 and main; the candidate JUnit fails 2/2 on 9.5.0, 9.12.3, 10.5.2 and main. [read] the same bulk add is at every release tag from 4.7.0 to 10.5.2; 5.0.0-5.2.1 and 8.9.0-8.11.3 not run. The shape changed in 9.11.0 (#12408, backported as #13300; on main since 10.0.0): before it every rejected hit was counted (two-segment probe 5 instead of 1), from it on only the rejected hits of segments where the fastMatchQuery has a scorer (3 instead of 1), which is what makes the total depend on segment layout. Not fixed upstream: upstream main fetched 2026-10-26 still has the four bulk adds.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-151.html",
   "repro": "repro/LFV-151/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-727",
   "priority": "low",
   "priority_rank": 317,
   "novelty": "new",
   "withheld": false,
   "area": "facet / taxonomy facets (TaxonomyFacets#getTopChildrenForPath and #getAllChildren: FacetResult.value of a sub-path; FastTaxonomyFacetCounts, TaxonomyFacetFloatAssociations with a DoubleValuesSource)",
   "title": "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",
   "summary": "You index two documents with taxonomy facets in a dimension configured only with setHierarchical(\"Publish Date\", true): one labeled Publish Date/2010 and one labeled Publish Date/2010/10. Both documents have a value for the path Publish Date/2010 (a DrillDownQuery on it matches 2 and getSpecificValue(\"Publish Date\", \"2010\") returns 2), so FacetResult.value of getTopChildren(10, \"Publish Date\", \"2010\") and getAllChildren(\"Publish Date\", \"2010\") should be 2, as its javadoc ('Total number of documents containing a value for this path') and SortedSetDocValues faceting with the same config say. FastTaxonomyFacetCounts returns 1 for both: for a single-valued dimension it adds up the path's immediate children and never uses the path's own rolled-up count, so the document labeled at 2010 itself is left out.",
   "impact_class": "silent wrong results",
   "introduced_commit": "7477fde1cb063b5c849369afa531bb28df4566fc (LUCENE-5339 'Simplify the facet module APIs' = apache/lucene#6403, by mikemccand; merge to branch_4x, svn r1555342, 2014-01-04; trunk merge 9d0b60388da, r1555338, same day; Subversion era, no pull request) [read]. The child-sum code was first written on the lucene5339 branch in 5458dbf2484 (2013-11-14) and took its current shape in 189feaacb6f (2013-11-20: requireDimCount and 'Our sum'd dim count is accurate, so we keep it') and 458786d0f41 (2013-11-27: IntTaxonomyFacets / FloatTaxonomyFacets). It was copied into getAllChildren by LUCENE-10550 (#914, bdcb4b37164, 9.3.0) and moved into TaxonomyFacets by #12966 (9ba4af7b883; 9.x backport 42884fab46d, #13358; 9.11.0) with unchanged values [exec]. At introduction the code matched its javadoc ('Total value for this path (sum of all child counts, or sum of all child values), even those not included in the topN'); LUCENE-9953 (#131 = 65820e5170e on main, lucene-solr #2491 = 3a7387d039b on branch_8x, merged 2021-05-18) rewrote the javadoc to 'Total number of documents containing a value for this path' without changing the taxonomy code. Not a regression within the current API.",
   "introduced_date": "2014-01-04 (7477fde1cb0 / 9d0b60388da; code first written 2013-11-14 on the lucene5339 branch); contradicts its javadoc since 2021-05-18 (LUCENE-9953)",
   "first_affected_version": "4.7.0 [exec] (the behaviour; then documented as the child sum). 8.9.0 is the first release whose FacetResult.value javadoc it contradicts [read]; 9.1.0 is the first release where SortedSetDocValues faceting returns the inclusive value for the same config [exec]. 4.6.1 and older have no Facets / FacetsConfig API [exec]; 4.6.1's old facet API returns the inclusive value 2 for the same data under all three OrdinalPolicy values [exec]",
   "affected_versions": "Every lucene-facet release on Maven Central from 4.7.0 to 10.5.2 (119 releases, including 8.11.4 and 9.12.3) [exec]; -da also executed on 4.7.0, 7.2.0, 8.8.2, 8.9.0, 9.0.0, 9.1.0, 9.3.0, 9.12.3, 10.0.0 and 10.5.2 with the same result; the finder's JUnit (needs 9.3.0+ APIs) fails on 9.3.0, 9.12.3, 10.0.0, 10.5.2 and main a9779ef3c193 (-ea and -da). Not fixed: no lucene/facet commit on upstream main a95c754ee00 since a9779ef3c193, branch_10x and branch_10_6 have the identical value branch [read], so 10.6.0 (released 2026-10-29 from branch_10_6) is affected too, and no open PR changes it. All runs on JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-727.html",
   "repro": "repro/LFV-727/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1104",
   "priority": "low",
   "priority_rank": 318,
   "novelty": "known",
   "withheld": false,
   "area": "facet / taxonomy facets getTopDims (TaxonomyFacets dimension admission)",
   "title": "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)",
   "summary": "You index one document with IntAssociationFacetField(0, \"a\", \"x\") and one with IntAssociationFacetField(1, \"b\", \"x\"), aggregate them with TaxonomyFacetIntAssociations and SUM, and call getTopDims(10, 10), expecting [b=1, a=0], the same as getAllDims(10), as the Facets#getTopDims javadoc says. Instead getTopDims returns [b=1]: it admits a dimension only when its value is not 0 (TaxonomyFacets.java:652), while getAllDims has reported zero-valued dimensions with hits since 9.11.0. Float associations behave the same.",
   "impact_class": "silent wrong results",
   "introduced_commit": "#12966 (9ba4af7b883 on main, 2024-04-05; 9.x backport 42884fab46d through #13358, 2024-05-14) [read]: it made taxonomy facets report labels and dimensions whose value is 0 but kept the value test of getTopDims (from the 2022 getTopDims work, #747 / #806), so the two methods disagree; executed: 9.10.0 passes, 9.11.0 fails",
   "introduced_date": "2024-04-05 (main), 2024-05-14 (9.x backport) [read]",
   "first_affected_version": "9.11.0 [exec]",
   "affected_versions": "9.11.0, 9.12.3, 10.5.2 and 10.6.0 (released) [exec]; main a9779ef3c193 and e1faeba08bde with -ea and -da [exec]; 9.10.0 not affected [exec]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/pull/13287",
    "https://github.com/apache/lucene/issues/12966",
    "https://github.com/apache/lucene/issues/13191",
    "https://github.com/apache/lucene/issues/13287"
   ],
   "doc": "",
   "repro": "repro/LFV-1104/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-884",
   "priority": "low",
   "priority_rank": 319,
   "novelty": "new",
   "withheld": false,
   "area": "grouping / GroupSelector score needs (FirstPass, SecondPass/TopGroups, AllGroups, AllGroupHeads collector score modes)",
   "title": "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)",
   "summary": "You group hits into score ranges, for example with new DoubleRangeGroupSelector(DoubleValuesSource.SCORES, new DoubleRangeFactory(0, 1, 10)), and sort the groups by a field, expecting each hit in the range of its own score, which is what the same search returns with the default relevance group sort (three ranges, [1,2) = {0, 3}, [2,3) = {1}, [3,4) = {2, 4}, in the repro). Instead GroupingSearch returns one empty group [0,1) (LongRangeGroupSelector: LongRange(0, 1)), and AllGroupsCollectorManager on its own reports one range instead of three, because the grouping collectors take their ScoreMode only from their sorts or reducer, so the query runs without scores and the selector, which reads the collector's Scorable through DoubleValuesSource.fromScorer, sees the placeholder score 0 for every hit. GroupSelector has no way to say that it needs scores; a GroupSelector#needsScores() hook (true for the range selectors when their source needs scores), ORed into the four collectors' score modes, fixes it.",
   "impact_class": "silent wrong results",
   "introduced_commit": "7c350d22c7070acf362fb4f477e6797f2711c910 (master; branch_8x backport 5e62c42c5f304eee7b5695f97f02a2aea7d00366), LUCENE-7889 'Allow grouping on Double/LongValuesSource' (apache/lucene-solr#1484 by romseygeek, merged 2020-05-11 with no review comments; JIRA mirror apache/lucene#8940) [read]: it added the abstract GroupSelector.setScorer and the two range selectors, whose setScorer binds source.getValues(context, DoubleValuesSource.fromScorer(scorer)), but gave GroupSelector no way to request scores and changed no collector's scoreMode(). The score-mode lines are older and were complete when written, because no selector read a scorer before (LUCENE-6912 31b6cd6851c, 2015; LUCENE-4100 4fc5a872ded, 2017; LUCENE-8412 55bfadbce11, 2018). Not a regression: the bug was born with the feature.",
   "introduced_date": "2020-05-11 (author date 17:34:01+01:00 for both the master and the branch_8x commit); first released in 8.6.0",
   "first_affected_version": "8.6.0 [exec] (the first release with the range selectors; git tag --contains on the branch_8x backport starts at 8.6.0, on the master commit at 9.0.0); 8.5.2 has no range selectors (both repros fail to compile there [exec]), so no earlier release works correctly with this API",
   "affected_versions": "every release that has the range selectors: all 49 releases 8.6.0-8.11.4, 9.0.0-9.12.3 and 10.0.0-10.5.2 [exec], plus branch_10_6 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193 [exec]. The finder's JUnit fails with wrong groups on 8.6.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0 and 10.5.2 (-ea; -da as well on 8.6.0 and 10.5.2) and 3 of 4 on branch_10_6 and main (-ea and -da). The standalone AllGroups/AllGroupHeads path shows this bug only since apache/lucene#16247 (10.6.0, released 2026-10-29, and main); on 8.6.0-10.5.2 it throws LFV-414's NullPointerException instead. With the candidate fix shadowed over main the probe and the JUnit pass. Not fixed on upstream main c5ab3e57b9b (2026-10-28).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-884.html",
   "repro": "repro/LFV-884/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1126",
   "priority": "low",
   "priority_rank": 320,
   "novelty": "new",
   "withheld": false,
   "area": "grouping / function grouping (queries function value fillers: FloatDocValues and siblings; contract in core util.mutable MutableValueFloat)",
   "title": "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)",
   "summary": "You index two documents with a float doc-values field a = 5 and a = 7 and no field b, and group all documents with GroupingSearch by the function sum(a, b). You expect one null group holding both documents, because sum(a, b) does not exist for either of them and the grouping javadocs put documents without a group value 'in a null group'. You get two groups that both read as null, one per partial sum, because FloatDocValues' value filler stores the partial sum as the value of a MutableValueFloat whose exists flag is false, against MutableValueFloat's documented rule that a missing value must be 0; with -ea the search throws AssertionError in MutableValueFloat.hashCode, and since 10.4.0 a group limit of 1 makes the second pass throw NullPointerException.",
   "impact_class": "silent wrong results",
   "introduced_commit": "595587963a77b4899b716b664c3cac8a5a13d9de (branch_5x merge, svn r1632432; first released in 5.0.0) and the trunk commit d8146460f0eca4641f0e48793b6053a88be5c7d1 (svn r1632414; on that line from 6.0.0), both for LUCENE-5961 'FunctionValues.exist(int) isn't returning false in cases where it should for many math based value sources' (Chris M. Hostetter, hossman; migrated as apache/lucene#7023; SVN commits, no GitHub PR). It made sum/product (MultiFloatFunction) and pow/div (DualFloatFunction) report exists() false when an input is missing, while floatVal() keeps returning the partial result; this made the bug reachable. The filler lines that copy value and exists independently are older (0742b30b724, 2011-04-15, Solr; moved into the Lucene queries module by LUCENE-3240/LUCENE-3249 in 2011), and the zero-when-missing rule and its asserts come from LUCENE-5790 (474d846bb5b, 4.10.0) [read]. The second-pass NullPointerException is a later consequence of the same root cause, via #15167 (a4ebe984087 on main, 898d38a4fd3 on branch_10x, gaobinlong, author date 2025-10-06, first released in 10.4.0) [exec].",
   "introduced_date": "2014-10-16 (author dates of d8146460f0e, 19:05Z, and 595587963a7, 20:25Z); the NullPointerException path 2025-10-06 (#15167)",
   "first_affected_version": "5.0.0 [exec]; the second-pass NullPointerException from 10.4.0 [exec]",
   "affected_versions": "every release from 5.0.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT) [read]. Executed with -da (documents without a value split into one null group per partial sum): 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.12.3, 10.3.2, 10.4.0, 10.5.2, 10.6.0 and main; with -ea (AssertionError at MutableValueFloat.hashCode): 5.0.0, 9.12.3, 10.5.2, 10.6.0 and main. With a group limit of 1 the second pass throws NullPointerException at GroupReducer.collect on 10.4.0, 10.6.0 and main; from 5.0.0 to 10.3.2 the same search instead silently reports totalGroupedHitCount 1 instead of 2 [exec]. Not affected: 4.10.4 and earlier 4.x, where sum(a,b) reported exists=true (4.10.4 executed with -ea and -da). Not new in 10.6 (10.5.2 fails). The one-test JUnit compiles from 10.4.0 on (it uses MatchAllDocsQuery.INSTANCE); older versions ran a main() probe of the same search or the independent reproduction's test. Not fixed upstream: the newest upstream commits on FloatDocValues.java (8ef6a0da568, 2020-12-28), MultiFloatFunction.java (54283150a81, 2026-06-14), MutableValueFloat.java (2d6ad2fee6d, 2020-12-23), ValueSourceGroupSelector.java (a4ebe984087, 2025-10-06) and GroupReducer.java (2cbf261032d, 2021-01-05) all predate 5adff78bb168 (author dates, read through the GitHub API at 2026-11-02; upstream main was 1c2072f0284). Executed on Linux aarch64 with JDK 25.0.3 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1126.html",
   "repro": "repro/LFV-1126/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-324",
   "priority": "low",
   "priority_rank": 321,
   "novelty": "new",
   "withheld": false,
   "area": "facet / SortedSetDocValues faceting (DefaultSortedSetDocValuesReaderState: the per-dimension DimTree and OrdRange built from the field's ordinals in term order, shared by SortedSetDocValuesFacetCounts and ConcurrentSortedSetDocValuesFacetCounts)",
   "title": "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",
   "summary": "You index hierarchical SortedSetDocValues facets, for example cat/shoes/red in one document and cat/'shoes<TAB>' (an untrimmed input) in another, and expect getTopChildren(10, 'cat', 'shoes') to return red=1, as taxonomy faceting does for the same labels. Instead it returns null and the leaf 'shoes<TAB>' reports red=1: the encoded paths sort by byte, a character below the path delimiter U+001F places 'shoes<TAB>' between 'shoes' and 'shoes U+001F red', and the reader state infers parent, child and sibling links only from the order of consecutive ordinals. The same happens for a label that contains U+001F or U+001E (FacetsConfig escapes both with U+001E), and dimension names such as 'd' next to 'd<TAB>' make dimension d disappear or, for a flat multiValued + requireDimCount dimension, lose one label, all with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "b4e27f2c638d31473c48503d0def2259b5d5a408 (main, 2022-01-10; LUCENE-10250 / PR #509 'Add support for arbitrary length hierarchical SSDV facets', by GitHub mdmarshmallow, merged by gsmiller), shipped through the branch_9x backport c7650cdec2cb4ed6b31c536a8eb2818c868dc42b; the flat multiValued + requireDimCount variant also needs 9e560c1af19e3d785af52ebb6bdc12b8c75ed125 (LUCENE-9952 / PR #611; branch_9x backport 225fd1527c8f78a1837538ea0dcbe3644166ef13, PR #621), which indexes the bare dimension term and treats ordRange.start() as the dimension ordinal [read]",
   "introduced_date": "2022-01-10 (b4e27f2c638 on main and the branch_9x backport c7650cdec2c, same day); flat variant 2022-01-24 (9e560c1af19 / 225fd1527c8)",
   "first_affected_version": "9.1.0 [exec] (tagged 2022-03-16; both changes are in its CHANGES.txt); last unaffected 9.0.0 [exec]",
   "affected_versions": "All 32 releases from 9.1.0 to 10.5.2 (the last release before 10.6.0) and main ea57360912ed. [exec] the finder's JUnit (repro/src) fails 4 of 6 on every release from 9.3.0 to 10.5.2 and on main; its legacy variant (repro/src-legacy, no getAllChildren) fails 4 of 4 on 9.1.0 and 9.2.0; the version-portable flat probe is wrong on every release from 9.1.0 on and correct on 8.11.4 and 9.0.0; -da gives the same results on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (82 history runs). The independent reproduction's JUnit fails 6 of 8 on main (-ea and -da), 10.5.2, 9.12.3 and 9.1.0 (on 9.1.0 one of the 6 is an API limit of that release, not this bug); the intended-behaviour check's probe fails on main and 10.5.2; the security probe fails 5 of 7 as expected on main and 10.5.2. Unaffected: 9.0.0 and earlier, where every SSDV term was dim/label and each dimension's terms were contiguous (executed on 8.11.4 and 9.0.0; older releases [read]). Not fixed upstream: upstream main e1c4184cb983 (2026-10-26) keeps the adjacency logic (last change to DefaultSortedSetDocValuesReaderState.java is the cosmetic #15842) and branch_10x last changed the file in #12454 [read]. Not executed: x86 (pure Java logic), releases before 8.11.4.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-324.html",
   "repro": "repro/LFV-324/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-597",
   "priority": "low",
   "priority_rank": 322,
   "novelty": "new",
   "withheld": false,
   "area": "facet / SortedSetDocValues faceting (FacetsConfig.processSSDVFacetFields path encoding with DELIM_CHAR U+001F / ESCAPE_CHAR U+001E, decoded by DefaultSortedSetDocValuesReaderState)",
   "title": "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",
   "summary": "You index three documents under a flat SortedSetDocValues facet dimension named 'color<U+001F>code', configured multiValued and requireDimCount, with labels {x, y}, {x} and {z}, and expect getTopChildren to return value=3 with x=2, y=1, z=1, as taxonomy faceting does for the same name. Instead it returns value=2 with only y=1 and z=1, and getAllDims also shows a phantom dimension 'color' with label 'code'. FacetsConfig escapes U+001F/U+001E in every facet term except this one bare dimension term (FacetsConfig.java:494), while the reader decodes every term as if it were escaped, so the raw term is read back as a different path.",
   "impact_class": "silent wrong results",
   "introduced_commit": "9e560c1af19e3d785af52ebb6bdc12b8c75ed125 (LUCENE-9952 / apache/lucene#611 'Fix dim count inaccuracies in SSDV faceting when a dim is multi-valued', author gsmiller, merged 2022-01-24; branch_9x backport 225fd1527c8f78a1837538ea0dcbe3644166ef13, #621) [read]. The PR's first revision 74205b42b946 escaped the term (pathToString(facetLabel.components, 1)); review comment r788936337 suggested facetField.dim as an equivalent simplification, the author agreed (r789158522) and commit d9a9621acca2 switched to the raw form; the two are equal only for names without U+001F/U+001E",
   "introduced_date": "2022-01-24 (#611 on main and backport #621 on branch_9x, same day)",
   "first_affected_version": "9.1.0 [exec]; last unaffected 9.0.0 [exec] (8.11.4 also executed, not affected): before 9.1.0 SSDV wrote no bare dimension term for flat dimensions and ignored requireDimCount",
   "affected_versions": "All 32 releases 9.1.0 through 10.5.2, 10.6.0 (by reading) and main a9779ef3c193, never fixed. [exec] the follow-up's version-neutral history probe (relative oracle: the same documents under a dimension named 'color') is wrong on every one of the 32 releases and on main with -da, and on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main with -ea, and correct on 8.11.4 and 9.0.0; the finder's JUnit fails 3 of 4 on main (-ea and -da), 10.5.2, 9.12.3 and 9.1.0; the independent reproduction's JUnit fails 3 of 5 on main (-ea and -da), 10.5.2, 9.12.3 and 9.1.0; the intended-behaviour check's probe fails 3 of 7 on main and 10.5.2. [read] FacetsConfig.java lines 491-495 are unchanged on main since 2022; branch_10_6 was not in the local clone then and 10.6.0 was not executed; the prior-art check read the line unchanged on branch_10_6. Hierarchical SSDV dimensions write their bare term with pathToString and were never affected. Not executed: x86 (pure Java logic), ConcurrentSortedSetDocValuesFacetCounts (shares the reader state). Runs on JDK 25.0.3, aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-597.html",
   "repro": "repro/LFV-597/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-541",
   "priority": "low",
   "priority_rank": 323,
   "novelty": "new",
   "withheld": false,
   "area": "facet / taxonomy writer (DirectoryTaxonomyWriter category identity: writer cache key vs taxonomy index term, perhapsFillCache)",
   "title": "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",
   "summary": "You add a facet value with an unpaired surrogate, for example FacetField(\"dim\", \"x\\uD83D\") built from a string cut inside an emoji, in one writer session and the same value again in a later session, with the default DirectoryTaxonomyWriter; you expect the existing ordinal back, as TaxonomyWriter.addCategory promises, and one facet entry with count 2. Instead, once the second session has filled its cache from the index (after 11 new categories by default), the cached key is the stored form \"x\\uFFFD\", the original string misses, the writer trusts its now complete cache and indexes the label again (ordinal 14 instead of 2), so the facet result shows x\\uFFFD (1) twice. The duplicate stays in the taxonomy for good; within one fresh session the writer likewise gives \"x\\uD83D\" and \"x\\uFFFD\" ordinals 2 and 3, although the taxonomy reader resolves both to 2.",
   "impact_class": "data corruption",
   "introduced_commit": "d4e1a420d52 (LUCENE-3079 'add faceting module', branch_3x; trunk port 4291f52c70d the same day; JIRA, no PR) [read]. The default configuration was masked in 7.1.0-9.4.2 by LUCENE-7975 (6cee162e195 on branch_7x, a9fb4ddf80f on master; default UTF8TaxonomyWriterCache keyed by the U+FFFD-replaced UTF-8 bytes; incidental, its discussion is about speed and memory) and exposed again by #12093 'Deprecate support for UTF8TaxonomyWriterCache' (9d6173148d7, branch_9x, first released in 9.5.0; main twin #12092 dc33ade76d3, first released in 10.0.0; default LruTaxonomyWriterCache(4000) keyed by FacetLabel; motivated by the ThreadLocal leak #12000, no discussion of label identity) [read]. So 9.5.0 is a regression of the default configuration, not the origin",
   "introduced_date": "2011-06-29 (LUCENE-3079); default configuration masked 2017-10-03 (LUCENE-7975, 7.1.0) and exposed again 2023-01-18 (#12093 / #12092, 9.5.0)",
   "first_affected_version": "3.4.0 [exec] (the first release with the facet module; 3.3 has none)",
   "affected_versions": "Default configuration: 3.4.0-7.0.1 and 9.5.0-10.5.2 and main ea57360912ed; 7.1.0-9.4.2 only with an explicitly configured LruTaxonomyWriterCache. [exec] the finder's JUnit (or a faithful port for the older APIs) fails on 3.4.0, 4.0.0, 4.6.1, 4.7.0, 7.0.1, 9.5.0, 9.12.3, 10.5.2 and main (-ea and -da); passes with the default cache on 7.1.0, 8.11.4 and 9.4.2 (also 8.11.2 and 9.0.0 with the earlier 2-test version); fails with an explicit LruTaxonomyWriterCache(4000) on 7.0.1, 8.11.4 and 9.4.2 (and 8.11.2); the independent reproduction's JUnit fails on main, 10.5.2, 9.12.3 and 9.5.0 and passes on 9.4.2. [read] the other releases from git tag --contains and unchanged code. 3.x is wider: its on-disk lookup and reader compare Java strings, so the duplicate appears without a cache fill and the reader returns -1 for the ill-formed label (3.4.0 no-fill control fails; 4.0.0 and 4.6.1 no-fill controls pass). Reach by era [read]: Cl2oTaxonomyWriterCache.isFull() is always false, so in 3.4.0-7.0.1 the cross-session duplicate should occur at any taxonomy size; from 9.5.0 only while the taxonomy fits in the 4000-entry cache (the intended-behaviour check reach probe, executed). Not fixed upstream: no commit on the affected files after ea57360912ed. All runs on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-541.html",
   "repro": "repro/LFV-541/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-425",
   "priority": "low",
   "priority_rank": 324,
   "novelty": "new",
   "withheld": false,
   "area": "facet / sampling (RandomSamplingFacetsCollector.amortizeFacetCounts x FacetsConfig drill-down term indexing)",
   "title": "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",
   "summary": "You sample facet counts with RandomSamplingFacetsCollector on a dimension whose FacetsConfig skips drill-down terms (DrillDownTermsIndexing NONE, or FULL_PATH_ONLY / DIMENSION_AND_FULL_PATH on a hierarchical dimension), call amortizeFacetCounts to scale the sampled counts up to estimates of the full counts, and expect what the default indexing gives: about sampled / samplingRate per label, capped by the label's real count. Instead each label is capped at reader.docFreq of its drill-down term, which these modes do not index at all (docFreq 0) or index only for the documents whose full path is that label, so a label seen 15 times in a 10% sample comes back as 0 and a label on 1000 documents comes back as 500. Nothing fails, and in the same FacetResult the amortized dimension total (for example 1000) no longer matches its children (all 0).",
   "impact_class": "silent wrong results",
   "introduced_commit": "3648a1020a8ab6b729ed53e0360499e624bb0cd1, apache/lucene#25 LUCENE-9385 'Add option to skip indexing facet drill down terms' (zacharymorn, merged to main 2021-03-27); first released through the branch_8x backport e812a5085904 (apache/lucene-solr#2471, 2021-03-29; hash and PR number from the JIRA commit-bot comment, the commit itself not inspected) [exec]. An interaction, not a change to the faulty lines: the docFreq cap (RandomSamplingFacetsCollector.java:239-241, still the lines of e50b392f467c, LUCENE-5476, 4.8.0, 2014, by git blame) was a real upper bound while every drill-down term was always indexed, and LUCENE-9385 made those terms optional without updating amortizeFacetCounts",
   "introduced_date": "2021-03-27 (main; branch_8x backport 2021-03-29); the cap itself dates from 2014-03-20",
   "first_affected_version": "8.9.0 [exec]; 8.8.2 lacks the trigger API [exec]",
   "affected_versions": "8.9.0 through 10.5.2 and main ea57360912ed; not fixed upstream (upstream main and branch_10x have no commit to RandomSamplingFacetsCollector.java since 2024-09-10 and the cap lines are unchanged on upstream main, read 2026-10-26). [exec] The finder repro (the same documents, config and assertions in three API-version ports) fails the same 3 of 4 tests with the same numbers on 8.9.0, 8.11.4, 9.0.0, 9.2.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea; -da also on main); the independent reproduction's independent test fails 5 of 9 on 9.12.3, 10.5.2 and main (-ea, and -da on main). [read] 8.10.x, 8.11.0-8.11.3, 9.1.0, 9.3.0-9.12.2 and 10.1.0-10.5.1: the same code as the executed endpoints. Not affected: 8.8.2 and older, where the option does not exist and every dim/.../label drill-down term is indexed [exec]. Unreleased 10.x branches other than branch_10x were not checked. Old releases ran on JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-425.html",
   "repro": "repro/LFV-425/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-367",
   "priority": "low",
   "priority_rank": 325,
   "novelty": "new",
   "withheld": false,
   "area": "facet / DrillDownQuery (clone() and the per-dimension BooleanQuery.Builder state)",
   "title": "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)",
   "summary": "You build a DrillDownQuery that restricts color=red, call clone(), and add color=blue to the clone (or to the original), expecting the copy you did not touch to keep matching only red, as clone() and the upstream testClone imply. Instead both copies match red OR blue: the clone shares each dimension's internal BooleanQuery.Builder with its source, and add() on an existing dimension appends a SHOULD clause to that shared builder in place. Since 9.0 a copy that was already searched keeps a cached snapshot and shows the leaked value only after its own dimension changes again (then 3 hits where 2 are correct), and the two copies stay equals() with the same hashCode while they match different documents.",
   "impact_class": "silent wrong results",
   "introduced_commit": "45a73c005e6bc6b1c24e8636cfb5433c6a726a9d, LUCENE-5339 'simplify DrillDownQuery' (GitHub mikemccand, svn r1542804 on branch lucene5339; migrated issue #6403 'Simplify the facet module APIs'), landed as trunk 9d0b60388da8 and branch_4x 7477fde1cb06 (svn r1555338 / r1555342, 'LUCENE-5371, LUCENE-5339: ... simplify facet APIs'); SVN era, no PR [read] [exec]. Not LUCENE-6570, which git blame shows today: 4aafacfbef4 (trunk) / 94716da23a5 (branch_5x, released 5.3.0) only carried the existing sharing over to List<BooleanQuery.Builder> (this.dimQueries.addAll)",
   "introduced_date": "2013-11-17 (branch commit); 2014-01-04 (trunk and branch_4x); first released 2014-02 in 4.7.0",
   "first_affected_version": "4.7.0 [exec] (last unaffected 4.6.1 [exec]; DrillDownQuery and clone() exist since 4.2.0, LUCENE-4750)",
   "affected_versions": "every release from 4.7.0 to 10.5.2 and main ea57360912ed [read]; executed with repro.sh (JDK 25, SHA-1-verified release jars, API-adapted sources for old lines): FAIL on 4.7.0, 4.10.4, 5.0.0, 5.2.1, 5.3.0, 5.5.5, 6.0.0, 6.6.6, 7.7.3, 8.11.2, 9.0.0, 9.12.3, 10.5.2 and main (-ea and -da); PASS on 4.6.1 (old-API equivalent). In 4.7.0-5.2.1 only add(String, String...) triggers it (add(String, Query) on an existing dimension throws there, LUCENE-5418); from 5.3.0 both overloads do. Since 9.0.0 (LUCENE-9956, per-copy cache of built dimension queries) the symptom depends on whether a copy was already searched [exec]. Upstream main DrillDownQuery.java is unchanged since #16056 (2026-05-14), the tested version (prior-report record)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-367.html",
   "repro": "repro/LFV-367/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-900",
   "priority": "low",
   "priority_rank": 326,
   "novelty": "new",
   "withheld": false,
   "area": "core / search collectors (PositiveScoresOnlyCollector; FilterCollector scoreMode and setWeight forwarding; TotalHitCountCollector Weight#count shortcut)",
   "title": "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)",
   "summary": "You wrap a collector in PositiveScoresOnlyCollector, whose javadoc says it 'makes sure only documents with scores > 0 are collected' and which Collector's overview says 'wraps any other Collector', and expect the wrapped collector to see exactly the matches that score > 0: in the repro 6 hits for the TermQuery g:y with a TopFieldCollector sorted by a field, and counts 0 for (f:x)^0 and 6 for (g:y)^2 OR (f:x)^0 with a TotalHitCountCollector. Instead the sort-by-field collector receives 0 hits and the counter reports 12 for both queries, because PositiveScoresOnlyCollector, which reads scorer.score() itself, inherits two FilterCollector hooks: scoreMode() reports the wrapped collector's no-score mode, so the search builds scorers without scores and the > 0 test reads placeholder values (0 for TermQuery, so real hits are dropped; a constant positive value for FunctionScoreQuery over MatchAllDocsQuery, so zero-score hits get through), and setWeight() hands the wrapped TotalHitCountCollector the Weight, so it counts whole segments with Weight#count and never goes through the filter. Overriding scoreMode() to return COMPLETE when the wrapped collector needs no scores, and passing on a Weight whose count() returns -1 (or not forwarding setWeight at all), fixes both.",
   "impact_class": "silent wrong results",
   "introduced_commit": "two legs, neither an edit to PositiveScoresOnlyCollector.java (byte-identical in 5.0.0 and 5.1.0, and in 9.2.0 and 9.3.0) [read]: (1) score-mode leg: 8c0dbb90087716841b895d839e15a8edfdbb8dae (branch_5x, svn r1657571; trunk 010e352f60301b1ab3967ad70413240163703ec4, r1657554), LUCENE-6218 'don't decode freqs or enumerate all positions, when scores are not needed' (apache/lucene#7280, by rmuir, Subversion era, no PR): it added Collector#needsScores() and FilterCollector#needsScores() { return in.needsScores(); }, which PositiveScoresOnlyCollector (a FilterCollector subclass since LUCENE-5527, 85642f59ddf, 2014, first released in 5.0.0) inherited although it reads scores; LUCENE-4100 (4fc5a872ded, 2017, first released in 8.0.0) renamed the hook to scoreMode() and kept the forwarding. (2) count leg: e983d391d71f3f3a628eb5520e8714623ac05202 (branch_9x; main 4c1ae2a332cb85878310142ebb9fd5beba0345f2), LUCENE-10620 / apache/lucene#964 'Pass the Weight to Collectors' by jpountz: it added Collector#setWeight with forwarding in FilterCollector and MultiCollector and made TotalHitCountCollector count through Weight#count; it has no CHANGES entry (9.3.0's CHANGES does not mention LUCENE-10620 or setWeight). Not born with the class (LUCENE-1575, 2.9): it broke when FilterCollector gained hooks that a filtering subclass must override.",
   "introduced_date": "2015-02-05 (score-mode leg; branch_5x 14:11:57Z, trunk 12:34:28Z, author date = commit date); 2022-06-23 (count leg; author date 2022-06-23T17:56:15+02:00 on both branches, PR #964 merged 15:56:15Z)",
   "first_affected_version": "5.1.0 [exec] (score-mode leg: 4.10.4 and 5.0.0 pass, 5.1.0 fails, and 5.1.0 passes once a needsScores() { return true; } override is added to its own copy of the class); the count leg from 9.3.0 [exec] (with only the score-mode leg shadow-fixed, 9.2.0 passes and 9.3.0 still fails the count checks until setWeight is not forwarded)",
   "affected_versions": "every release from 5.1.0 to 10.5.2 (106 releases; a class-file scan of every release jar shows FilterCollector forwarding the hook and PositiveScoresOnlyCollector declaring no override [read]), branch_10x, branch_10_6 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193. Executed fail: a version-portable main() probe on 5.1.0, 5.2.0, 5.2.1, 5.3.0, 5.4.0, 5.5.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.2.0, 9.3.0, 9.7.0, 9.8.0, 9.12.3, 10.0.0, 10.5.2 and main [exec]; the finder's JUnit (or its 8.x/9.x API copy) on 8.0.0, 8.11.4, 9.0.0, 9.1.0, 9.2.0, 9.3.0, 9.7.0, 9.8.0, 9.9.0, 9.10.0, 9.11.0, 9.12.3, 10.0.0, 10.5.2, branch_10_6 and main (-ea; -da as well on 10.5.2 and main) [exec]; the independent reproduction's own JUnit on 9.12.3, 10.5.2 and main (-ea and -da) [exec]. 4.10.4 and 5.0.0 pass [exec]. The visible symptom changes with unrelated scorer changes while the cause stays the same: from 5.1.0 positive hits are lost for some queries (for every positive TermQuery from 5.2.1 to 7.7.3); 8.0.0-9.7.0 let zero-boost hits through while plain TermQuery hits survive; from 9.8.0 every positive TermQuery hit is lost again (not bisected; 9.7.0..9.8.0 contains #12383, the dummy SimScorer for non-scoring term weights); from 9.3.0 a wrapped TotalHitCountCollector also counts through Weight#count. Not fixed on upstream main c5ab3e57b9b (2026-10-28).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-900.html",
   "repro": "repro/LFV-900/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-882",
   "priority": "low",
   "priority_rank": 327,
   "novelty": "new",
   "withheld": false,
   "area": "misc / DocValuesStats long statistics (DocValuesStatsCollectorManager concurrent reduce)",
   "title": "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",
   "summary": "You index ordinary large long values, for example 24 epoch-nanosecond timestamps in 6 segments, compute LongDocValuesStats (or SortedLongDocValuesStats) with DocValuesStatsCollectorManager exactly as its class javadoc shows on new IndexSearcher(reader, executor), and expect mean() = 1.7616096115E18, 'the mean of all values of the field' and the value the same search without an executor returns, because merge() promises 'the combined statistics of both segments as if they had been collected together'. Instead mean() is 2.243809386908707E17 (about 8x too small; other slicings give a negative mean) and variance() and stdev() are wrong too, because merge() recomputes the combined mean as (sum + otherSum) / count from long sums that have wrapped past Long.MAX_VALUE, while serial collection keeps a running mean that never reads the sum. Only sum() is documented as possibly overflowing; count(), min() and max() stay right.",
   "impact_class": "silent wrong results",
   "introduced_commit": "0210af757c54 (main, 'Introduce DocValuesStatsCollectorManager (#15653)', by gaobinlong, co-authored by javanna; backport 1833c658f063 on branch_10x): it added DocValuesStatsCollectorManager and merge() with combinedMean = (sum().doubleValue() + otherStats.sum().doubleValue()) / n, a formula already in the PR's first commit 88f84b033918 (2026-02-02); the wrapping long sum is older (LUCENE-7590, 295cab7216c, 2016-12-15, documented 'might overflow') but before #15653 mean() and variance() came only from the running update and never read it [read]",
   "introduced_date": "2026-05-19 (author and commit date of 0210af757c54 and of the backport 1833c658f063; PR #15653 opened 2026-02-02)",
   "first_affected_version": "10.5.0 [exec] (10.4.0 and older have no DocValuesStatsCollectorManager and no merge() [exec]; their only route, one DocValuesStatsCollector, gives the exact mean [exec])",
   "affected_versions": "10.5.0, 10.5.1 and 10.5.2, the branch_10_6 head 4ae946e5a9b9 (10.6.0, released 2026-10-29) and main a9779ef3c193. [exec] the finder's JUnit fails 2 of 2 on 10.5.0, 10.5.1, 10.5.2 (-ea and -da), branch_10_6 and main (-ea and -da); the independent reproduction's JUnit fails 3 of 4 on 10.5.0, 10.5.2 and main (-ea and -da); the intended-behaviour check re-ran the finder's repro on main (-ea and -da) and 10.5.2 (-da); all runs on JDK 25. Not affected: 10.4.0, every earlier 10.x and all 9.x (no merge() and no manager: the repro does not compile on 10.4.0 and 9.12.3, and a control that passes one DocValuesStatsCollector to an executor searcher passes 2 of 2 on 9.12.3, 10.4.0 and 10.5.2, with sum() wrapped and mean() and variance() exact). [read] Not fixed upstream: DocValuesStats.java and DocValuesStatsCollectorManager.java were last changed by #15653 on main (origin/main c5ab3e57b9ba, re-checked 2026-10-28), branch_10x, branch_10_6 and branch_10_5.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-882.html",
   "repro": "repro/LFV-882/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-684",
   "priority": "low",
   "priority_rank": 328,
   "novelty": "new",
   "withheld": false,
   "area": "classification / k-NN classifiers and BooleanPerceptronClassifier (training query)",
   "title": "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)",
   "summary": "You index three labelled documents ('aa bb' as Y, 'aa' as X, 'aa' as X), build KNearestNeighborClassifier with k = 3 once with no training query and once with MatchAllDocsQuery (the parameter is documented as 'a Query to eventually filter the docs used for training the classifier', and this one removes nothing), and expect the same answer for 'aa bb bb'. Instead the answer flips from Y (class scores Y 0.333, X 0.309) to X (X 0.417, Y 0.333), because the training query and the class-field WildcardQuery are added as scoring Occur.MUST clauses, so their scores are added to every neighbour's MoreLikeThis score before each vote is weighted by score / maxScore; a training query whose score differs between documents, such as TermQuery(split:train) on a text field every document has, even replaces the nearest neighbour (k = 1: 'aa', class X, becomes 'aa bb', class Y). KNearestFuzzyClassifier and KNearestNeighborDocumentClassifier return different class scores in the same way, and BooleanPerceptronClassifier, which trains in the score order of the same kind of query, learns a different model ('aa' answers true instead of false).",
   "impact_class": "silent wrong results",
   "introduced_commit": "e60f7af1d16c5467a1300abe575ddb983212bfb2 (trunk, LUCENE-5284 \"added method for training with a Query filter\", Tommaso Teofili, 2013-10-17, svn r1532983): the training query is added to the k-NN search as a scored Occur.MUST clause (and BooleanPerceptronClassifier trains in its score order). The branch_4x backport 3df19e13b2dc55b4dc3d1e4c804ec5c2affd48ad (LUCENE-5290, same day, r1533003) is the commit that put it into a release (4.6.0). Today's lines KNearestNeighborClassifier.java:174-178 blame to debb363f6e3 / branch_4x a8a8242f50f (LUCENE-5338, 2013-11-11, class-field WildcardQuery MUST, training-query MUST moved into the MoreLikeThis BooleanQuery; also 4.6.0) and e60f7af1d16. Constant-score training queries started to matter with 35810f4c77d / branch_5x 2ddb06f6087 (LUCENE-6654, 2015-08-03, score/maxScore vote weighting, 5.3.0). Commit-level runs confirm each step [exec]. No later commit changed these clause occurs; Occur.FILTER has never appeared in lucene/classification [read].",
   "introduced_date": "2013-10-17 (trunk e60f7af1d16, branch_4x backport 3df19e13b2d the same day); 2013-11-11 (LUCENE-5338 class-field clause, debb363f6e3 / a8a8242f50f); 2015-08-03 (LUCENE-6654 score/maxScore vote weighting, 35810f4c77d / 2ddb06f6087); first release 4.6.0, 2013-11-22",
   "first_affected_version": "4.6.0 [exec] (KNearestNeighborClassifier with a training query whose score varies between documents; commit-level runs isolate 3df19e13b2d as the step that introduces it, its parent has no training-query API). Constant-score training queries such as MatchAllDocsQuery change results from 5.3.0 (LUCENE-6654), when the vote became score / maxScore. The classification module's earlier releases 4.2.0-4.5.1 have no training-query API [exec]. Per class, each from its first release [exec]: BooleanPerceptronClassifier 5.0.0, KNearestNeighborDocumentClassifier 6.0.0, KNearestFuzzyClassifier 7.0.0.",
   "affected_versions": "Every release from 4.6.0 to 10.5.2 [exec]: all 121 releases in that range (4.6.0-4.6.1, 4.7.0-4.7.2, 4.8.0-4.8.1, 4.9.0-4.9.1, 4.10.0-4.10.4, all 5.x, 6.x, 7.x, 8.x including 8.8.2-8.11.4, 9.x, and 10.0.0-10.5.2), plus main a9779ef3c193 (unreleased 11.0) with -ea and -da. Not affected: 4.2.0-4.5.1 (7 releases; the classification module first shipped in 4.2.0), which have no training-query API [exec]. Per class [exec]: KNearestNeighborClassifier 4.6.0+; BooleanPerceptronClassifier 5.0.0+ (its first release); KNearestNeighborDocumentClassifier 6.0.0+ (first release); KNearestFuzzyClassifier 7.0.0+ (first release). Constant-score training queries (MatchAllDocsQuery) change k-NN results only from 5.3.0 (LUCENE-6654); in 4.6.0-5.2.1 only training queries whose score varies between documents do. Not fixed upstream as of main a9779ef3c193. [exec] The candidate JUnit fails 4 of 4 on 9.12.3 (9.x API copy), 10.5.2 and main (-ea and -da); the independent reproduction's JUnit fails 7 of 8 on main (-ea and -da), 10.5.2 and 9.12.3 (its one passing test is the zero-score control); the follow-up history probes ran 248 executions over every release from 4.2.0 to 10.5.2, main and five commit-level checkouts.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-684.html",
   "repro": "repro/LFV-684/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-801",
   "priority": "low",
   "priority_rank": 329,
   "novelty": "new",
   "withheld": false,
   "area": "classification / KNearestFuzzyClassifier (textFieldNames 'field^boost' syntax; NearestFuzzyQuery field lookup)",
   "title": "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",
   "summary": "You build a KNearestFuzzyClassifier with a text field written as 'text^2' or 'title^10', as its constructor javadoc says you may, and expect the same classes as with the plain field name (with that field weighted more). Instead the entry is used verbatim as the name of a field called 'text^2', which does not exist, so that field adds no terms to the query: with one text field assignClass returns null and getClasses an empty list, and with several fields the boosted one is silently ignored. The sibling KNearestNeighborClassifier, whose javadoc has the same sentence, parses the boost and classifies normally.",
   "impact_class": "silent wrong results",
   "introduced_commit": "bd9e32d358399af7c31e732314e1ef1dd89bcfa1 ('LUCENE-7838 - added knn classifier based on flt', by @tteofili; JIRA LUCENE-7838 = apache/lucene#8889; committed directly, no pull request): the commit that added the class already had the javadoc sentence 'they can contain boosting indication e.g. title^10' and passed each name unchanged to FuzzyLikeThisQuery.addTerms [read]; 92e460389dc (2017-06-29, same issue, in 7.0.0) replaced it with NearestFuzzyQuery and kept the raw-name lookup [read]. The sentence and its parsing came together to KNearestNeighborClassifier in 35810f4c77d (LUCENE-6654, 2015); this class copied the sentence but not the parsing [read]. Not a regression.",
   "introduced_date": "2017-05-18 (bd9e32d3583); 2017-06-29 (92e460389dc, NearestFuzzyQuery form)",
   "first_affected_version": "7.0.0 [exec]; 6.x is not affected because it has no KNearestFuzzyClassifier [exec]",
   "affected_versions": "every release that has the class: 7.0.0 to 10.5.2, 10.6.0 (by reading) and main a9779ef3c193 (unreleased 11.0) [exec]; the releases in between by inference: all 65 release tags 7.0.0..10.5.2 carry the javadoc sentence and no '^' parsing [read]. branch_10_6 and upstream main head have no change to KNearestFuzzyClassifier.java since f0fd51c4d5c4 (2024-09-11) [read], so 10.6.0 (released 2026-10-29) ships it. Executed on Linux aarch64 with JDK 25 only (pre-10 releases too).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-801.html",
   "repro": "repro/LFV-801/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-681",
   "priority": "low",
   "priority_rank": 330,
   "novelty": "new",
   "withheld": false,
   "area": "classification / utils: DatasetSplitter (split, createNewDoc fieldNames branch)",
   "title": "DatasetSplitter.split with explicit fieldNames copies only the first value of each multi-valued field into the split indexes",
   "summary": "You split an index into training, test and cross-validation indexes with DatasetSplitter.split and name the fields to copy, for example {id, text, cls}, where text has two stored values in each document. You expect each new document to carry both values of text, as it does when fieldNames is null ('all should be used'). Instead only the first value is copied, because the named-fields branch reads document.getField(name), which returns only the first value, so the second and later values are missing from the stored fields and from the postings of every output index, with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "3459b28334e2f3103336c0485b3f21da6dbaeeb9 (trunk, 2012-11-29, svn r1415060, '[LUCENE-4345] - added utility class for creating training / test / cv index from a single index'; no PR, it predates GitHub PRs; JIRA LUCENE-4345 / #5411 is the issue under which the classification module was built). The released code came through the branch_4x backport 21e86983ed42 (2013-02-20, 'LUCENE-4781 - backporting classification module to branch_4x'), whose DatasetSplitter.java is byte-identical to release 4.2.0's [read]. Not a regression: from the first commit the named-fields branch read getField(fieldName) and the all-fields branch looped over getFields(). Later commits did not change the behaviour: bf1355346c6 (LUCENE-6045, trunk 2015-05-04, first released in 6.0.0) only added the null check, 112078eaf909 (LUCENE-7196, trunk, first released in 7.0.0; in 6.1.0 through its identical branch_6x cherry-pick ff3661abdaa) moved the copy unchanged into createNewDoc() (git blame of today's lines points there; 6.0.1 and 6.1.0 both reproduce), 7f8b7ffbcad (LUCENE-9570) reformatted and 47f8c1baa2e (#11998) switched to StoredFields [read].",
   "introduced_date": "2012-11-29 (trunk commit 3459b28334e); release line: backport 21e86983ed4 on 2013-02-20; first released in 4.2.0 (tagged 2013-03-11)",
   "first_affected_version": "4.2.0 [exec] (2013-03-11, the first release that ships the classification module and DatasetSplitter). There is no last unaffected release: 4.1.0 has no lucene/classification directory [read], no lucene-classification jar on Maven Central (HTTP 404) [exec] and no DatasetSplitter class in its other jars (ClassNotFoundException) [exec].",
   "affected_versions": "Every release that has DatasetSplitter, 4.2.0 through 10.5.2 (128 releases) and 10.6.0 (by reading), and main a9779ef3c193; not fixed. [exec] the follow-up's version-portable main() repro (7 API-era variants; 3 documents with two stored text values each, DatasetSplitter(0.3, 0.3) so one document lands in each output index; control fieldNames null, then {id, text, cls}) reproduced in all 132 runs: all 128 releases 4.2.0-10.5.2 with -ea, main with -ea, and -da on 9.12.3, 10.5.2 and main; control 3/3 documents keep both values and docFreq(text:second)=3, named mode 0/3 and docFreq 0, in the test, cross-validation and training indexes alike; with the candidate fix shadowed in on main it passes. The finder's JUnit fails on main (-ea and -da), 10.5.2 and 9.12.3, and so do the independent reproduction's and the intended-behaviour check's own JUnits. [read] upstream main a95c754ee00 (2026-10-26), branch_10x 1309534296e and branch_10_6 2763db11b0a have the same DatasetSplitter.java as a9779ef3c193.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-681.html",
   "repro": "repro/LFV-681/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-683",
   "priority": "low",
   "priority_rank": 331,
   "novelty": "new",
   "withheld": false,
   "area": "classification / utils: DatasetSplitter (split: class count used as the GroupingSearch group limit)",
   "title": "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",
   "summary": "You split an index with DatasetSplitter.split(reader, train, test, cv, analyzer, false, \"cls\"), where one segment holds d0 without a class value, d1 of class a and d2 of class b. You expect every live document in one of the three new indexes, and every class present, which is what the grouping by class was added for (LUCENE-7196). Instead d2, and with it all of class b, is in none of the outputs: split asks GroupingSearch for as many groups as there are class values, but the documents without a value form one more (null) group that takes one of those slots; and if a segment has no class field at all, split throws NullPointerException from terms(classFieldName).size() before its try block, so its three IndexWriters are never closed.",
   "impact_class": "silent wrong results",
   "introduced_commit": "Labelled-class loss: ff3661abdaa5b4ae33496dc378ae917f7a7a723b (branch_6x, 2016-04-08, 'LUCENE-7196 - guaranteed class coverage in split indexes through grouping by class (cherry picked from commit 112078e)'), the commit that shipped in 6.1.0; its trunk twin 112078eaf909bdda27a092d13a8431c046a82ac0 (same day, same DatasetSplitter.java, first released in 7.0.0) is what git blame on main credits for the GroupingSearch lines and the gs.search(..., 0, noOfClasses) call. It replaced 'copy every hit of a MatchAllDocsQuery' with GroupingSearch by class and a group limit equal to the number of class values, which never counts the null group of documents without a value; the later rewrites of that count kept this (LUCENE-6766 in 6.2.0, LUCENE-7350 in 6.4.0, LUCENE-7400 in 7.0.0). So it is a regression of LUCENE-7196, not inherited behaviour. NullPointerException half: 87d8b5450a6d75fdd4b724b24a3722054b6d00f8 (master, 2016-12-12, 'LUCENE-7591 - approximate to no. of terms when DVs are not available', first released in 7.0.0), which replaced a deliberate IllegalStateException with leave.reader().terms(classFieldName).size() and no null check. The writers have been opened before the try since the class was created (3459b28334e2, LUCENE-4345, 2012); an input can reach that leak only since 6.2.0, when a check that can throw came before the try. All are svn-era commits by @tteofili with no pull request and no CHANGES entry; the issues LUCENE-7196 / #8251 and LUCENE-7591 / #8642 never mention documents without a class value. [exec]",
   "introduced_date": "2016-04-08 (LUCENE-7196, labelled-class loss); 2016-12-12 (LUCENE-7591, NullPointerException half)",
   "first_affected_version": "6.1.0 [exec] (tagged 2016-06-12) for the labelled-class loss; 7.0.0 [exec] (tagged 2017-09-08) for the NullPointerException. Last unaffected release: 6.0.1 [exec], whose split() has no classFieldName parameter and copies every document.",
   "affected_versions": "Labelled-class loss: every release from 6.1.0 to 10.5.2 (90 releases) and main a9779ef3c193; not fixed. Segment without the class field: 7.0.0-10.5.2 (74 releases) and main throw NullPointerException and leave all three output directories locked; 6.2.0-6.6.6 (15 releases) throw IllegalStateException ('the classFieldName \"cls\" must index sorted doc values', the documented precondition) before the try and also leave the three directories locked; 6.1.0 copies that document and releases the locks. Not affected: 5.5.5, 6.0.0 and 6.0.1 (no class-aware split; every document is copied). [exec] the follow-up's version-portable main() probe (core API only, split() overload chosen by reflection, NIOFSDirectory) on all 93 releases 5.5.5-10.5.2 and on main with -ea, plus -da on 10.5.2 and main (104 executed runs with the JUnit and commit-isolation runs): scenario A (one segment: u0 unlabelled, d1=a, d2=b) gives [d1, u0] on every affected version; the fully labelled control gives [d0, d1, d2] everywhere; scenario A2 (unlabelled document last) gives [d1, d2], so then only the unlabelled document is dropped. The finder's JUnit (compiles from 9.5 on) fails 2 of 2 on 9.12.3, 10.5.2 and main (-ea and -da); the independent reproduction's JUnit fails 3 of 4 on main (-ea and -da), 10.5.2 and 9.12.3. [read] lucene/classification and lucene/grouping are unchanged between ea57360912ed and a9779ef3c193; upstream, DatasetSplitter.java last changed in #15499 (2025-12-11, a refactor), and no open PR changes the class count or the null handling (prior-report search against upstream main a95c754ee003, 2026-10-26).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-683.html",
   "repro": "repro/LFV-683/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-388",
   "priority": "low",
   "priority_rank": 332,
   "novelty": "new",
   "withheld": false,
   "area": "classification / BM25NBClassifier (assignClass and getClasses)",
   "title": "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)",
   "summary": "You index four training documents labelled fruit ('apple banana', 'apple pear') or vehicle ('car truck', 'car bus') plus one document labelled heldout that your training query split:train excludes, build BM25NBClassifier with that query and classify 'apple', expecting fruit, which is what the classifier answers when the heldout document is absent. Instead assignClass returns heldout (getClasses: heldout 0.568, fruit 0.273, vehicle 0.159), and the same happens with no training query when every document of a label is deleted but its segment is not yet merged ('apple' -> gone 0.681). BM25NBClassifier makes every term of the class field a candidate class (MultiTerms.getTerms), and for a class with no live, query-matching document both of its searches find no hit, so calculateLogPrior falls back to 0 and getTermProbForClass to 1 (log 0): the class scores exactly 0, while each trained class sums log(top BM25 score) over the prior and every input token, which is negative whenever those scores are below 1.",
   "impact_class": "silent wrong results",
   "introduced_commit": "89905001831de12dd8cb18647d3d54944899ccdf 'LUCENE-7823 - added bm25 nb classifier' (by GitHub tteofili; issue apache/lucene#8874; committed directly to master, no pull request) wrote the class enumeration and both zero-hit fallbacks [read]. Later commits on these lines only adapted APIs (fd9164801e7 LUCENE-7875, 331ccf39106 LUCENE-8405, 9ca053712af LUCENE-8430, f0fd51c4d5c #13762). Amplifier, not cause: cf016f8987e8 (LUCENE-8563, apache/lucene#9609, in 8.0.0) removed the (k1+1) factor from BM25, which lowered every trained class's log score by exactly (1+t)*ln(2.2) for t input tokens while the untrained class stays at 0 [exec], so the wrong top-1 answer fires for ordinary short inputs from 8.0.0 on.",
   "introduced_date": "2017-05-11 (89905001831); amplified 2018-11-14 (cf016f8987e8, LUCENE-8563)",
   "first_affected_version": "7.0.0 [exec] (tagged 2017-09-18, the first release with the class; CHANGES 7.0.0 'LUCENE-7823: Pure query based naive bayes classifier using BM25 scores'; 6.5.1, 6.6.0 and 6.6.6 lack the API [exec]). On 7.0.0 and 7.7.3 the wrong top-1 answer shows only for inputs with words absent from the class documents (deleted variant, 2 of 4) while ordinary short inputs pass with the untrained class at p > 0; from 8.0.0 ordinary short inputs fail too [exec]",
   "affected_versions": "Every release from 7.0.0 to 10.5.2 and main ea57360912ed; not fixed upstream (upstream main cf398bfb142c, 2026-10-26: BM25NBClassifier.java byte-identical to the tested file, fallbacks still at :219 and :230). [exec] follow-up history harness (5 ordinary inputs and 2 unknown-word inputs, each with the training-query and the deleted variant; control index checked first): 7.0.0 and 7.7.3 ordinary inputs pass (0 of 10 assigned; the untrained class gets p > 0 in 10 of 10), unknown-word inputs fail (2 of 4); 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main fail (10 of 10 and 4 of 4). The finder's JUnit fails 2 of 2 on main (-ea and -da), 10.5.2 and 9.12.3 (9.x accessor variant repro/src-9x); the independent reproduction's JUnit fails 2 of 3 (its control passes) on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's portable main() fails on main (-ea and -da) and 8.0.0. Not affected: 6.x and earlier (class absent). [read] 8.8.2-8.11.3 are not tagged in the history clone; 8.11.4 was executed.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-388.html",
   "repro": "repro/LFV-388/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-682",
   "priority": "low",
   "priority_rank": 333,
   "novelty": "new",
   "withheld": false,
   "area": "classification / utils: DatasetSplitter (split, test/cv/training assignment loop)",
   "title": "DatasetSplitter puts at most about half of each class into the test index, whatever testRatio is",
   "summary": "You split an index with new DatasetSplitter(0.8, 0).split(...) to put 80% of the documents into the test index. You expect about 8 of every 10 documents of each class in the test index, as crossValidationRatio 0.8 gives 8 of 10 in the cross-validation index. Instead the test index gets only 5 of 10 and training gets the other 5, because the loop lets a document into the test index only when its running counter b is even (DatasetSplitter.java:153, 'if (b % 2 == 0 && tc < testSize)'), so at most every other document can be a test document, with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "3459b28334e2f3103336c0485b3f21da6dbaeeb9 (trunk, 2012-11-29, svn r1415060, '[LUCENE-4345] - added utility class for creating training / test / cv index from a single index', tteofili; no PR, it predates GitHub PRs; JIRA LUCENE-4345 / #5411 is the issue under which the classification module was built). It added 'if (b % 2 == 0 && testWriter.maxDoc() < size * testRatio)' for the test branch and no parity condition on the cross-validation branch. The released code came through the branch_4x backport 21e86983ed42 (2013-02-20, LUCENE-4781 / #5846), with the same guard. Not a regression: the guard is in the first commit of the class. 112078eaf909 (LUCENE-7196 / #8251, 2016-04-08, first released in 6.1.0) rewrote the loop per class and kept 'b % 2 == 0' unchanged; git blame of line 153 points there only because the right half of the condition was rewritten [read].",
   "introduced_date": "2012-11-29 (trunk commit 3459b28334e); release line: backport 21e86983ed4 on 2013-02-20; first released in 4.2.0 (tagged 2013-03-11)",
   "first_affected_version": "4.2.0 [exec] (2013-03-11, the first release that ships the classification module and DatasetSplitter). There is no last unaffected release: DatasetSplitter.java is absent from the 4.0.0-alpha, 4.0.0-beta, 4.0.0 and 4.1.0 tags [read], and Maven Central has no lucene-classification 4.1.0 jar (HTTP 404) [exec].",
   "affected_versions": "Every release that has DatasetSplitter, 4.2.0 through 10.5.2, and main a9779ef3c193; not fixed. [exec] the follow-up's history runs (one class of 10 documents, testRatio 0.8, cv 0; each run first checks the control crossValidationRatio 0.8 -> 8 of 10, which passes in every version): 4.2.0, 4.10.4, 5.0.0, 6.0.1, 6.1.0, 6.3.0, 6.4.0, 7.7.3, 8.8.1 and 8.11.4 (version-specific main() drivers for the four API eras) and 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main with -ea and -da (the candidate JUnit) all give test/cv/training 5/0/5 instead of 8 test documents; shadow controls on 4.2.0, 6.1.0 and 8.8.1 (the release's own source with only 'b % 2 == 0 && ' removed) give 8/0/2, so the drivers detect exactly this guard. The finder's JUnit (also re-run by the intended-behaviour check) and the own tests of the independent reproduction also fail on 10.5.2 and 9.12.3. [read] the guard is in all 119 release tags of the history clone (8.8.2 and 8.9.0-8.11.3 are not tagged there and lie between the executed 8.8.1 and 8.11.4); upstream main a95c754ee003 (2026-10-26) and branch_10x still have line 153 unchanged.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-682.html",
   "repro": "repro/LFV-682/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-088",
   "priority": "low",
   "priority_rank": 334,
   "novelty": "new",
   "withheld": false,
   "area": "document / LatLonPoint#nearest",
   "title": "LatLonPoint#nearest reports an EQUAL_TO TotalHits that counts deleted documents",
   "summary": "You index documents with a LatLonPoint field, delete or update some of them, and call LatLonPoint.nearest(searcher, field, lat, lon, n) with n larger than the index. You expect TopFieldDocs.totalHits, which is labelled TotalHits.Relation.EQUAL_TO (exact), to count only documents that can be hits, here the hits returned. Instead the total is the per-segment sum of PointValues#getDocCount, an index statistic that still counts deleted documents, so 3 documents with one deleted return 2 hits but report exactly '3 hits', more than reader.numDocs().",
   "impact_class": "silent wrong results",
   "introduced_commit": "fcd98fd3370b (#897, LUCENE-10266 'Move nearest-neighbor search on points to core'), which copied the sandbox code into core unchanged [read]. Not a regression: the getDocCount sum dates from f6c7fc7a2658 (LUCENE-7069, 2016, sandbox) and the EQUAL_TO label from 9ca053712af0 (LUCENE-8430, 2018, a mechanical change when totalHits became a TotalHits object) [read]",
   "introduced_date": "2022-06-13 (in core; sandbox origin 2016-04-14, EQUAL_TO label 2018-07-30)",
   "first_affected_version": "10.0.0 (first release with nearest() in core; the same expression shipped in the sandbox from 6.1.0 to 9.12.3, out of scope)",
   "affected_versions": "every 10.x release before 10.6.0, 10.0.0 to 10.5.2 (12 releases), and main ea57360912ed [exec]; no 9.x release has nearest() in core [exec]; branch_10_6 and branch_10x carry the 10.5.2 file unchanged, so the released 10.6.0 has it too [read]; not fixed upstream [read]; the sandbox predecessors 6.1.0-9.12.3 give the same wrong total [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-088.html",
   "repro": "repro/LFV-088/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-746",
   "priority": "low",
   "priority_rank": 335,
   "novelty": "new",
   "withheld": false,
   "area": "spatial3d / Geo3D distance sort comparator (Geo3DPointDistanceComparator.compareBottom bounds shortcut; Geo3DDocValuesField.newDistanceSort and newPathSort)",
   "title": "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)",
   "summary": "You sort a query with Sort(Geo3DDocValuesField.newDistanceSort(field, lat, lon, maxRadiusMeters, planet), secondary SortField) and expect search(q, n, sort) to return the first n hits of the sorted order: every hit outside the radius reports distance +Infinity (like a document without the field), so the secondary field should order them. Instead, five documents at latitude 60 sorted around (0,0) with a 1,000 km radius and a secondary 'tie' key descending give top 2 = [1, 0] although the full order is [4, 3, 2, 1, 0] (WGS84; the same on SPHERE with a 0.2 planet-radius circle; with a sixth document missing the field, [5, 1] instead of [5, 4]), and newPathSort does the same. The cause: once the queue bottom is +Infinity, compareBottom rejects (-1) every later document whose points lie outside the shape's bounding box instead of reporting a tie (0), so the secondary SortField is never consulted.",
   "impact_class": "silent wrong results",
   "introduced_commit": "07af00d8e7bc4ce2820973e2ab511bfe536654c6 on master and its branch_6x twin 8a407f0399c6575d6f4bb087f1d9fdc7d112e5d2, 'LUCENE-7212: Add Geo3D sorted document fields.' (JIRA LUCENE-7212, now apache/lucene#8267, still open; pre-GitHub patch on the JIRA issue, no pull request; committer GitHub DaddyWri). It added newDistanceSort, newPathSort, Geo3DPointSortField and Geo3DPointDistanceComparator, whose compareBottom starts at cmp = -1 and skips ('continue') every value outside priorityQueueBounds from the first version on. Preconditions from earlier commits: 23422908165f (LUCENE-7212, 2016-04-19) added getDistanceBounds, which returns the shape's own bounds for the outside sentinel; 688c67f8ff22 (LUCENE-6578, 2015) made computeDistance return that sentinel (then Double.MAX_VALUE), and a911eb856196 (LUCENE-7288, 2016-05-18) changed it to +Infinity. [read]",
   "introduced_date": "2016-05-17 (master and branch_6x)",
   "first_affected_version": "6.1.0 [exec] (tag commit 4726c5b2d2e, 2016-06-12), the first release with the Geo3D sorts; 6.0.0 and 6.0.1 have no Geo3DDocValuesField [exec], so no earlier release is affected",
   "affected_versions": "every lucene-spatial3d release from 6.1.0 through 10.5.2 (all 90 releases >= 6.1.0 in the Maven Central metadata) and main a9779ef3c193. Executed (JDK 25): the follow-up's portable main() fails on all 90 releases (-ea) and on main (-ea and -da), and passes on main with the fix shadowed; the finder's JUnit fails on main (-ea, -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit (including the newPathSort case) fails on main and 10.5.2 (-ea, -da), 9.12.3 and 8.11.4 (a copy differing only in the LuceneTestCase import); the intended-behaviour check's probe fails on main and 10.5.2. Not fixed upstream: Geo3DPointDistanceComparator.java on upstream main f7bcc0abd816 is byte-identical to the tested commit (last commit 2cbf261032dc, 2021, a reformat), the same on branch_10x, and no open PR touches it or GeoBaseDistanceShape.java [read]. Caveats: all runs used JDK 25; the commit-level runs paired the commit's spatial3d sources with the 6.1.0 core jar; the path sort was executed on 8.11.4 and later only, older releases by reading.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-746.html",
   "repro": "repro/LFV-746/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-293",
   "priority": "low",
   "priority_rank": 336,
   "novelty": "new",
   "withheld": false,
   "area": "queries / intervals (Intervals.before, OffsetIntervalsSource PRECEDING)",
   "title": "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'",
   "summary": "You search with Intervals.before(source, reference), for example before(term new, phrase(new, york)) on the text 'new york', or before(term york, term york) on the one-word text 'york'. You expect no match, because the javadoc says before 'Returns intervals from the source that appear before intervals from the reference' and nothing comes before the first word. Instead both documents match: before() is built from a helper that places a pseudo-interval one position before each reference match, and for a reference at position 0 the helper clamps that position to 0 instead of producing nothing, so a source at position 0 counts as 'before' it; prepend one unrelated word and the same text correctly stops matching.",
   "impact_class": "silent wrong results",
   "introduced_commit": "7d34bfdaad37a25bfda5df2bf2c2bd1a31540bc2 (master) and its branch_8x copy 3593af2ac55f12a2ce2cfa76fd58407aa3fafa67 (same day, same diff; the commit the 8.x releases contain), 'LUCENE-8629: New interval functions: before, after, within, overlapping' (romseygeek; a JIRA patch, migrated to apache/lucene#9675, no GitHub PR) [read]. The one commit created both halves: Intervals.before as containedBy(source, extend(PRECEDING(reference), MAX, 0)) and the PRECEDING start() = Math.max(0, pos - 1). Later commits that touched the class (LUCENE-8633, LUCENE-3041, LUCENE-8477, LUCENE-8856, LUCENE-9050, LUCENE-9099, LUCENE-9570) did not change that logic. Present since the API was created, not a regression",
   "introduced_date": "2019-01-07 (7d34bfdaad37 and 3593af2ac55f)",
   "first_affected_version": "8.0.0 [exec] (release tag 2019-03-13; lucene-sandbox artifact, package org.apache.lucene.search.intervals; CHANGES 8.0.0 New Features 'LUCENE-8629: New interval functions: Intervals.before(), Intervals.after(), Intervals.within() and Intervals.overlapping()'); 7.6.0 and 7.7.3 have no Intervals.before [exec]; the before()-only fix applied to the 8.0.0 sources makes the 8.0.0 port pass 2 of 2 [exec]",
   "affected_versions": "every release from 8.0.0 through 10.5.2 and main ea57360912ed. [exec] by the follow-up history sweep (the finder's 2-test JUnit, ported only in its package line and test-framework imports for releases before 9.1.0; its positive control passes everywhere): 8.0.0, 8.1.1, 8.2.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main all fail 2 of 2 with identical messages under -ea and -da; the independent reproduction (4 tests including a bounded-exhaustive oracle and the Matches API) and the intended-behaviour check (shift-invariance probe) also fail on 10.5.2 and 9.12.3. [read] 3593af2ac55f is in every 8.x tag of the history clone (8.0.0 to 8.8.1) and 7d34bfdaad37 in every 9.x and 10.x tag (9.0.0 to 10.5.2); 8.8.2 to 8.11.3 were not run individually. Exposure: lucene-sandbox 8.0.0 to 8.1.x, lucene-queries (org.apache.lucene.queries.intervals) from 8.2.0 (LUCENE-8856), query strings through StandardQueryParser fn:before from 9.1.0 (LUCENE-10223; executed on main by a separate check and on main, 10.5.2 and 9.12.3 by the security probe). Not affected: every release up to 7.7.3 (API absent) [exec]. Not fixed: upstream main HEAD was the tested commit at search time, OffsetIntervalsSource was last changed in 2020 (a reformat) on main and branch_10x, and no open PR touches OffsetIntervalsSource or before() [read]; 10.6.0 (released 2026-10-29) was not checked (it was not on Maven Central on 2026-10-26). All runs on aarch64 with JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-293.html",
   "repro": "repro/LFV-293/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-805",
   "priority": "low",
   "priority_rank": 337,
   "novelty": "new",
   "withheld": false,
   "area": "queries / intervals (RepeatingIntervalsSource.minExtent for ordered/unordered of equal sub-sources; Disjunctions rewrite under phrase/maxgaps)",
   "title": "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'",
   "summary": "You search with Intervals.phrase(x, Intervals.or(Intervals.ordered(a, a), a), c), meaning 'x, then either a a or a, then c', on the text 'x a a c' and expect a hit, because phrase(x, ordered(a, a), c) alone matches it and Intervals.or is documented to rewrite itself under gap-sensitive parents so that alternatives of different lengths are not lost. Instead it finds nothing: ordered(a, a) and unordered(a, a) are built as a RepeatingIntervalsSource whose minExtent() returns the minExtent of a single 'a' (1) instead of 2, the rewrite assumes that only single-position sources report 1 and so keeps or(ordered(a, a), a) as one OR, and inside that OR the interval of 'a a' contains the interval of a single 'a' and is minimized away. The same query with two different words, phrase(x, or(ordered(a, b), a), c) on 'x a b c', matches as expected.",
   "impact_class": "silent wrong results",
   "introduced_commit": "aa916bac3c3369a461afa06e384e070657c32973 (branch_8x, the commit first released, in 8.5.0) and 7c1ba1aebeea540b67ae304deee60162baee2e12 (master, the same patch on the same day): 'LUCENE-9099: Correctly handle repeats in ORDERED and UNORDERED intervals' (apache/lucene-solr#1097, the JIRA issue is now apache/lucene#10141; author romseygeek; one approving review by jimczi, no inline review comments), which made Intervals.ordered(a, a) and Intervals.unordered(a, a) deduplicate into a RepeatingIntervalsSource whose minExtent() is 'return in.minExtent();' [read] [exec]. It broke the stated assumption of the older LUCENE-8477 rewrite (f1782d0dd119 master / 2571bf355f8 branch_8x, apache/lucene-solr#620, 2019-03-27, first released in 8.1.0) that 'all combinatorial sources have a minExtent > 1', which held when written (ordered(a, a) reported 2 on 8.2.0 to 8.4.1 [exec])",
   "introduced_date": "2020-02-06 (aa916bac3c3 and 7c1ba1aebee); precondition 2019-03-27 (LUCENE-8477, f1782d0dd119)",
   "first_affected_version": "8.5.0 [exec] (8.4.1, the last release before LUCENE-9099, is not affected [exec]: ordered(a, a).minExtent() is 2 there and the ordered shape finds its hit; its unordered shape already returns 0 there for the older reason LUCENE-9099 fixed, unordered(a, a) matching a single 'a')",
   "affected_versions": "every release from 8.5.0 through 10.5.2 (52 releases: 8.5.0-8.11.4 (19), 9.0.0-9.12.3 (21), 10.0.0-10.5.2 (12)) and main a9779ef3c193 [exec]. Not affected [exec]: 8.2.0, 8.3.0, 8.3.1, 8.4.0, 8.4.1. Not affected [read]: 8.1.x (rewrite present, no RepeatingIntervalsSource; sandbox package, not executed) and earlier releases (no automatic rewrite). Not fixed [read]: branch_10_6 head 4ae946e5a9b, branch_10x and upstream main 20ced71c1e6e have the same minExtent() body and splitDisjunctions grouping, so the released 10.6.0 has it",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-805.html",
   "repro": "repro/LFV-805/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-826",
   "priority": "low",
   "priority_rank": 338,
   "novelty": "new",
   "withheld": false,
   "area": "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)",
   "title": "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",
   "summary": "You build phrase(x, or(W, y), d) with W = maxwidth(5, or(phrase(b, c), b)) and expect the hit on 'x b c d' that phrase(x, W, d) finds, because Intervals.or 'Automatically rewrites if wrapped by an interval source that is sensitive to internal gaps' and adding an alternative y that occurs in no document cannot remove a match. Instead the rewrite (Disjunctions.splitDisjunctions) asks the outer or() for its alternatives only one level deep, so W reaches the phrase whole (here grouped with y into one minimizing or(), because W's shortest match is one position), the inner or() drops the interval 'b c' in favour of the 'b' it contains, and the query returns no hits. The same happens with fixField(g, or(...)) or extend(or(...), 0, 0) in place of maxwidth, with containedBy or maxgaps as the parent, and with an ordered() alternative whose own or() has alternatives of different lengths.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f1782d0dd1195c823c79aab87529ebd7e8217b95 (master, released from 9.0.0) and its branch_8x backport 2571bf355f82e193d50ec2509f83ba698b262562 (the first released form, in 8.1.0), both 2019-03-27: 'LUCENE-8477: Automatically rewrite disjunctions when internal gaps matter' (apache/lucene-solr#620 by romseygeek; the JIRA issue is now apache/lucene#9523). It added the gap-sensitive rewrite with the one-level Disjunctions.splitDisjunctions, its minExtent-1 grouping and the wrapper pull-ups [read] [exec]. An incomplete fix, not a regression: before it no form was rewritten",
   "introduced_date": "2019-03-27 (f1782d0dd11 and the branch_8x backport 2571bf355f8)",
   "first_affected_version": "8.1.0 [exec] (8.1.0 and 8.1.1 shipped the intervals package in lucene-sandbox as org.apache.lucene.search.intervals; LUCENE-8856 moved it to the queries module in 8.2.0). 8.0.0 [exec] has no rewrite at all, so there the directly wrapped form misses too and the inconsistency does not exist; the nested query has returned no hit in every release",
   "affected_versions": "every release from 8.1.0 through 10.5.2 and 10.6.0 (its intervals sources at branch_10_6 RC1 4ae946e5a9b [exec], below) [exec]; branch_10_6 head 4ae946e5a9b [exec], so the released 10.6.0 has it; main a9779ef3c193 [exec]; upstream main 20ced71c1e6 [read]. Reachable from query text through StandardQueryParser fn: functions from 9.1.0 (LUCENE-10223) [exec]; before that through the Java Intervals API only",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-826.html",
   "repro": "repro/LFV-826/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-670",
   "priority": "low",
   "priority_rank": 339,
   "novelty": "new",
   "withheld": false,
   "area": "spatial-extras / prefix-tree heatmap faceting (HeatmapFacetCounter.calcFacets, also reached through PrefixTreeStrategy.calcFacets; coarse 'ancestor' leaf cells reported by PrefixTreeFacetCounter)",
   "title": "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",
   "summary": "You index non-point shapes (rectangles, polygons) with the default RecursivePrefixTreeStrategy and ask PrefixTreeStrategy.calcFacets (HeatmapFacetCounter) for a heatmap with a circle or another non-rectangular input shape; the javadoc says the grid covers the input's bounding rectangle and that 'the non-intersecting cells will all be 0'. Instead, a document whose shape was indexed as a leaf cell coarser than the heatmap level has its count added to every heatmap cell under that leaf, including cells that do not intersect the input shape at all, because the code that spreads these coarse ('ancestor') counts never checks the cells against the input shape; point documents and rectangular inputs come out right. In the minimal repro (the setup of Lucene's own testQueryCircle plus one square document), 8 cells that are disjoint from the circle report 1 instead of 0, with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "248121bb3f74a8af032ccd66f903904eaa3e1c59 (LUCENE-6191 'Spatial 2D heatmap for PrefixTreeStrategy', GitHub mirror apache/lucene#7253, by dsmiley; svn trunk r1658298, SVN era, no PR), with the branch_5x backport b1c673bcca4d1d8493812121f8bb32acef3040dc (r1658302, same ancestor logic) [read]: the non-rectangular inputShape parameter, the javadoc 'the non-intersecting cells will all be 0' and the ancestor-spreading code arrived together in the feature's first commit. Not a regression: the later commits on the block (LUCENE-6650 Filter to Bits, LUCENE-7015/7060 module and package moves, LUCENE-7291 b33d7176aa3 dateline split, LUCENE-7787 7d57d63375e MatchNoBits short-circuit, LUCENE-9570 reformatting) did not change the omission.",
   "introduced_date": "2015-02-09 (trunk 248121bb3f7 and branch_5x b1c673bcca4 the same day; first released in 5.1.0)",
   "first_affected_version": "5.1.0 [exec] (the first release with HeatmapFacetCounter; the history repro fails there with the same 8 cells, and its points-only control passes). 5.0.0, the last release before it, has no heatmap API [exec], so every release that ships the heatmap is affected.",
   "affected_versions": "Every release from 5.1.0 through 10.6.0 (10.6.0 by reading), and main a9779ef3c193; not fixed. [exec] the finder's repro (the JUnit, or a main() port of it for the 5.x, 6.x, 7.x and 8.x APIs) fails with the same 8 cells on 5.1.0, 5.5.5, 6.0.0, 6.6.6, 7.7.3, 8.11.2, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da on main); the points-only control passes on 5.1.0 and 6.0.0; the independent reproduction's JUnit fails 4 of 6 on 9.12.3, 10.5.2 and main; the intended-behaviour check's downstream-scenario probe fails on 10.5.2 and main. [read] git tag --contains: 5.1.0-5.5.5 (backport), 6.0.0-8.8.1 and 9.0.0-10.5.2; the 8.8.2-8.11.4 tags are not in the history clone (8.11.2 and 8.11.4 were executed); HeatmapFacetCounter.java and PrefixTreeFacetCounter.java on a9779ef3c193 are byte-identical to the history clone HEAD, and HeatmapFacetCounter is functionally unchanged on upstream main a95c754ee003, branch_10x and branch_10_6 (read 2026-10-27).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-670.html",
   "repro": "repro/LFV-670/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-678",
   "priority": "low",
   "priority_rank": 340,
   "novelty": "new",
   "withheld": false,
   "area": "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)",
   "title": "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",
   "summary": "You use the Geo3d spatial context, build a line from (0,0) to (10,0) with buffer(1), and expect a corridor reaching 1 degree from the line, because spatial4j distances are in the units of x and y (degrees in a geo context) and spatial4j's standard geo context and the same factory's 1-degree circle both say a point at (5, 20) is DISJOINT. Instead the line CONTAINS that point and its bounding box is about [-57.3, 67.3] x [-57.3, 57.3]: Geo3dLineStringBuilder.build hands the buffer straight to GeoPathFactory.makeGeoPath, whose width is an angle in radians, while the factory's circle() and Geo3dRectangleShape.getBuffered convert degrees with DEGREES_TO_RADIANS. The same happens when the Geo3d context reads spatial4j's polyshape string for a 1-degree buffered line, and every buffer above about 1.5708 is rejected with 'Cutoff angle out of bounds', so a buffer of 2 degrees cannot be built at all.",
   "impact_class": "silent wrong results",
   "introduced_commit": "035523ba7a86773500c053129f65c9a6dc4fd384 (main) and its branch_7x cherry-pick 85491401d54c59e1593a5c9f13dca7bfcdda31a2 (the commit that shipped in 7.1.0): LUCENE-7951 'Spatial4j implementations using Geo3d' (issue apache/lucene#9000); the code matches apache/lucene-solr#246 by GitHub iverase (closed unmerged 2017-09-29), committed by GitHub dsmiley [read]. Not a regression: the defect came in together with the API.",
   "introduced_date": "2017-09-20 (both commits); first release 7.1.0 (release commit 2017-10-13, tag 2017-10-16)",
   "first_affected_version": "7.1.0 [exec]",
   "affected_versions": "Every release from 7.1.0 to 10.5.2 (72 releases), 10.6.0 (by reading) and main a9779ef3c193; not fixed upstream. [exec] the finder's JUnit fails 2 of 2 on each of the 72 releases (-ea, seed DEADBEEF; 7.1.0-7.6.0 with the junitcore runner; 7.x to 9.0.0 with a copy that differs only in the LuceneTestCase import) and on main with -ea and -da; the independent reproduction's JUnit fails 5 of 5 on main (-ea, -da), 10.5.2 and 9.12.3; the intended-behaviour check's JUnit fails 3 of 5 (the 3 buffer assertions) on main (-ea, -da) and 10.5.2. [read] upstream main a95c754ee003 (2026-10-26), branch_10x and branch_10_6 still pass the raw distance; no open PR touches Geo3dShapeFactory.java, GeoPathFactory.java or GeoStandardPath.java. The 'Cutoff angle out of bounds' symptom is in every release by code identity (the same range check since 7.1.0; executed on main and 10.5.2 only).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-678.html",
   "repro": "repro/LFV-678/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-777",
   "priority": "low",
   "priority_rank": 341,
   "novelty": "new",
   "withheld": false,
   "area": "spatial-extras / PointVectorStrategy distance value source (vector/DistanceValueSource missing-document value; makeDistanceValueSource, makeRecipDistanceValueSource)",
   "title": "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)",
   "summary": "You index points with PointVectorStrategy in a non-geo SpatialContext (for example world bounds -1000..1000), add a document without a point, and sort a query by makeDistanceValueSource(point).getSortField(false), expecting the point-less document last, as BBoxStrategy, SerializedDVStrategy and the prefix-tree strategies do: in a non-geo context they give it Double.MAX_VALUE, the rule LUCENE-4208 set for all strategies ('180 if geo, Double.MAX_VALUE otherwise'). Instead it gets distance 180.0, so with a document at (500, 0) and the query point (0, 0) the ascending order is none,far instead of far,none, and makeRecipDistanceValueSource over the query box -1000..1000 scores it 0.440 against 0.220 for a real document 500 units away. The cause: vector/DistanceValueSource sets nullValue = 180 * multiplier with no isGeo() branch; the branch was dropped in the 7.0 port from ValueSource to DoubleValuesSource (LUCENE-7737).",
   "impact_class": "silent wrong results",
   "introduced_commit": "2f2e00ffe235ba590f43bf07dabd4201e6da53c6, 'LUCENE-7737: Remove spatial-extras dependency on queries module' (JIRA LUCENE-7737, migrated as apache/lucene#8788; a patch attached to the issue, no pull request; author romseygeek, reviewed by dsmiley and jpountz; lucene-solr master). While porting vector/DistanceValueSource from ValueSource to DoubleValuesSource it removed 'nullValue = (strategy.getSpatialContext().isGeo() ? 180 * multiplier : Double.MAX_VALUE)' and added 'this.nullValue = 180 * multiplier;' in the constructor. The same commit kept the rule in the Solr legacy copy of the class (solr/core/.../legacy/DistanceValueSource.java) and in util/DistanceToShapeValueSource and util/ShapeFieldCacheDistanceValueSource. The rule came from 577e25c7ffc (LUCENE-4208, 2012, in 4.0.0) and was kept by 47bf70812ba (LUCENE-5118, the multiplier). [read]",
   "introduced_date": "2017-06-13 (authored), 2017-06-27 (committed; LUCENE-7737 resolved the same day)",
   "first_affected_version": "7.0.0 [exec] (fails with -ea and -da; tag commit 2017-09-08). 6.6.0, the last release before the commit (tag commit 2017-05-29), and 6.6.6, the latest 6.x, pass [exec], as does 6.5.1; 4.0.0 to 6.6.6 have the isGeo() rule [read]",
   "affected_versions": "every release from 7.0.0 through 10.5.2 (all of 7.x, 8.x, 9.x and 10.x: 65 release tags contain 2f2e00ffe23, and 8.8.2 to 8.11.4 were cut from branch_8x) and main a9779ef3c193. Executed (JDK 25, the follow-up's version-portable main(), public API only): fails on 16 releases, 7.0.0, 7.7.3, 8.0.0, 8.8.2, 8.9.0, 8.10.0, 8.10.1, 8.11.0 to 8.11.4, 9.0.0, 9.12.3, 10.0.0 and 10.5.2 (7.0.0, 9.12.3 and 10.5.2 also with -da), and on main (-ea and -da); passes on 6.5.1, 6.6.0 (-ea and -da) and 6.6.6. The finder's JUnit fails on main (-ea, -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails on main (-ea, -da), 10.5.2 and 9.12.3; the intended-behaviour check reproduced on main (-ea, -da) and 10.5.2 (-da). The remaining 7.x to 10.x releases contain the commit [read]; the file is byte-identical in 9.0.0, 9.12.3, 10.5.2 and main. Not fixed upstream: upstream main f7bcc0abd81 (2026-10-27) still has 'this.nullValue = 180 * multiplier;' and no open PR touches DistanceValueSource.java [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-777.html",
   "repro": "repro/LFV-777/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-320",
   "priority": "low",
   "priority_rank": 342,
   "novelty": "new",
   "withheld": false,
   "area": "facet / range drill-down queries (LongRange and DoubleRange ValueSourceQuery and MultiValueSourceQuery) and the query cache",
   "title": "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",
   "summary": "You build a range filter or drill-down with LongRange or DoubleRange#getQuery(fastMatchQuery, valueSource) whose fast-match query reads a doc-values field (for example NumericDocValuesField.newSlowExactQuery(\"inStock\", 1)), run it through a query cache, then change that field for one document in place with IndexWriter#updateNumericDocValue and reopen the reader. You expect the reopened searcher to use the new value, because a query that depends on updated doc values must report itself not cacheable (SegmentCacheable), and the fast-match query alone does. Instead the range query's Weight#isCacheable asks only the value source, the segment keeps its core cache key, and the cache keeps serving the pre-update result (5 hits instead of 4 in the repro) until the segment is merged away or the entry is evicted.",
   "impact_class": "silent wrong results",
   "introduced_commit": "276e317e9424 (master, 'LUCENE-8042: Add SegmentCachable interface', by romseygeek, +1 by rmuir; JIRA patch workflow, no GitHub PR; migrated as apache/lucene#9090); branch_7x backport 6e4f9a62e7cc, the commit released in 7.2.0. It replaced the never-cacheable 'getCacheHelper ... return null; // TODO delegate to LongValuesSource?' left by LUCENE-8017 (a886a001a4c) with 'return valueSource.isCacheable(ctx)' and did not consult the fastMatchWeight created in the same createWeight [read]; the multi-valued overloads copied the same body in 82703757fe05 (main) / 60b499b907d3 (branch_9x), 'LUCENE-10245: Addition of MultiDoubleValues(Source) and MultiLongValues(Source) ...', apache/lucene#543 by gsmiller, first released in 9.1.0",
   "introduced_date": "2017-11-07 (LUCENE-8042 author date; committed 2017-11-10 on master and branch_7x); 2022-01-10 (#543 merged, multi-valued overloads)",
   "first_affected_version": "7.2.0 [exec] (tagged 2017-12-19); the multi-valued getQuery overloads from 9.1.0 [exec] (9.0.0 has no such API: compile error [exec]). 7.1.0 also serves the stale count [exec], but for an older and broader root cause (the query cache then ignored doc-values updates for every query, so the fast-match query alone is stale too), fixed by LUCENE-8017 in 7.2.0",
   "affected_versions": "every release from 7.2.0 to 10.6.0 (10.6.0 by reading) and main ea57360912ed. [exec] single-valued JUnit (2 of 3 fail, the fast-match-alone control passes) on 7.2.0, 7.7.3, 8.0.0, 8.11.4 and 9.0.0 (-da also on 7.2.0 and 8.11.4); the canonical JUnit (4 getQuery overloads plus the isCacheable check, 5 of 5 fail) on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-da also on 9.12.3, 10.5.2 and main); zero-configuration IndexSearcher (default LRUQueryCache and UsageTrackingQueryCachingPolicy, 12,000-doc segment, query repeated) stale on 9.12.3 and 10.5.2, correct on main, which has had no default query cache since GITHUB#14187 (unreleased); zero configuration not executed on 7.x or 8.x. [read] every isCacheable body that exists is unchanged at all 62 release tags from 7.2.0 to 10.5.2 in the history clone (the two single-valued bodies at the 30 tags 7.2.0-9.0.0, all four from 9.1.0) and in the bytecode of the 8.8.2-8.11.4 facet jars; 10.6.0 (released 2026-10-29; branch_10_6) by source only. Not fixed upstream: unchanged on upstream main e1c4184cb983 and branch_10x (2026-10-26)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-320.html",
   "repro": "repro/LFV-320/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-336",
   "priority": "low",
   "priority_rank": 343,
   "novelty": "new",
   "withheld": false,
   "area": "core / search: LateInteractionFloatValuesSource (late-interaction multi-vectors) and the query cache",
   "title": "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",
   "summary": "You score documents against a query multi-vector with LateInteractionFloatValuesSource, filter on that score through a query cache (for example FunctionMatchQuery(source, s -> s > 0.75), or DoubleRange#getQuery in the facet module), then replace one document's LateInteractionField multi-vector in place with IndexWriter#updateBinaryDocValue and reopen the reader. You expect the reopened searcher to stop matching that document, because a source that reads doc values must report itself not cacheable once those doc values have been updated (SegmentCacheable). Instead isCacheable always returns true, the segment keeps its core cache key, and the cache keeps serving the pre-update result (5 hits instead of 4 in the repro) until the entry is evicted or the segment is merged away.",
   "impact_class": "silent wrong results",
   "introduced_commit": "d9618080b340 (apache/lucene#14729 'Support for Re-Ranking Queries using Late Interaction Model Multi-Vectors' by vigyasharma, main; branch_10x backport 7de24ce973d0, released in 10.3.0) [read]; not a regression in any release: the class shipped with the defect and no version ever had a correct isCacheable",
   "introduced_date": "2025-07-08 (#14729 merged on main; branch_10x backport the same day)",
   "first_affected_version": "10.3.0 [exec] (first release with the class; 10.2.2 and 9.12.3 give compile_error because the API is absent [exec])",
   "affected_versions": "all 7 releases from 10.3.0 to 10.5.2 (10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2) and main ea57360912ed with an installed LRUQueryCache [exec]; with zero configuration (default IndexSearcher cache and caching policy, 12,000-doc segment, the same query run 6 times) 10.3.0 and 10.5.2 [exec], not main, which has had no default query cache since GITHUB#14187 (unreleased) [exec]; 10.6.0 (branch_10_6) not executed, same file blob 3bf3bcb3d0b9 and still a default LRUQueryCache [read]; 10.2.2 and older, including all 9.x, not applicable because the class does not exist [exec]; not fixed upstream: isCacheable still returns true on upstream main e1c4184cb983 and branch_10x [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-336.html",
   "repro": "repro/LFV-336/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-947",
   "priority": "low",
   "priority_rank": 344,
   "novelty": "new",
   "withheld": false,
   "area": "spatial-extras / composite: CompositeVerifyQuery (Weight#isCacheable) and the query cache",
   "title": "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",
   "summary": "You wrap an index query that reads a doc-values field, for example NumericDocValuesField.newSlowExactQuery(\"v\", 1), in new CompositeVerifyQuery(indexQuery, shapePredicate), run it through a query cache, then change that field for one document in place with IndexWriter#updateNumericDocValue and reopen the reader. You expect the reopened searcher to see the new value, because a query that depends on updated doc values must report itself not cacheable (SegmentCacheable), and the index query alone does. Instead CompositeVerifyQuery's Weight#isCacheable asks only the shape predicate, the segment keeps its core cache key, and the cache keeps serving the pre-update result ([0, 1, 2] instead of [1, 2] in the repro; 5025 instead of 5024 hits with the release-default cache settings).",
   "impact_class": "silent wrong results",
   "introduced_commit": "276e317e9424252d89df7596851c7cd3559d79b1 (master, 'LUCENE-8042: Add SegmentCachable interface', by romseygeek, +1 by rmuir; JIRA patch workflow, no GitHub PR; migrated as apache/lucene#9090); branch_7x backport 6e4f9a62e7cc221dcb49788ab683c87f764f2f4a, the commit released in 7.2.0. It replaced the never-cacheable 'getCacheHelper ... return null; // TODO delegate to PredicateValueSource?' that LUCENE-8017 (a886a001a4c master / 6f522dd66fe branch_7x, #9065) had added four days earlier with 'return predicateValueSource.isCacheable(ctx)', and did not consult the indexQueryWeight built in the same createWeight [read]",
   "introduced_date": "2017-11-07 (author date of both commits; committed 2017-11-10 on master and branch_7x)",
   "first_affected_version": "7.2.0 [exec] (tagged 2017-12-19). 7.1.0 also serves a stale count [exec], but for an older, framework-wide root cause (the query cache then had no per-Weight cacheability, so the index query alone is stale too), fixed by LUCENE-8017 in 7.2.0; CompositeVerifyQuery itself exists since 5.2.0 (LUCENE-5579)",
   "affected_versions": "every release from 7.2.0 to 10.5.2, 10.6.0 (released 2026-10-29) and main. [exec] history probe (explicit LRUQueryCache, 10,050-document segment) affected on 7.2.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2, the branch_10_6 head 4ae946e5a9b and main a9779ef3c193 (-da also on 7.2.0, 10.5.2, branch_10_6 and main), with the index-query-alone control correct on each; the candidate JUnit fails 3 of 3 on main (-ea and -da; 30 of 30 over 10 random seeds), branch_10_6 4ae946e5a9b (-ea and -da), 10.5.2, 10.0.0 and 9.12.3; zero configuration (plain new IndexSearcher, default LRUQueryCache and UsageTrackingQueryCachingPolicy, query repeated) is stale on 7.2.0, 8.11.4, 9.12.3, 10.5.2 and branch_10_6 and correct on main, which has had no default query cache since #14187 (unreleased). [read] the isCacheable line is present at all 62 release tags of the history clone (7.2.0-8.8.1, 9.0.0-10.5.2) and in the bytecode of the 8.11.4 jar (8.8.2-8.11.x were tagged in the separate lucene-solr repository). Not fixed upstream: CompositeVerifyQuery.java last changed by d0d2aa274fb (2024-06-06, #13440); upstream main head 645d4fe14a2 (2026-10-28) and branch_10_6 4ae946e5a9b still carry the line. Some branch_10_6 runs combined the branch's core jars with spatial-extras classes whose composite/, serialized/ and util/ sources are identical between 10.5.2 and the branch head (recorded by the independent reproduction and the finder). All runs on Linux aarch64 with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-947.html",
   "repro": "repro/LFV-947/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-829",
   "priority": "low",
   "priority_rank": 345,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / original Highlighter, QueryScorer and WeightedSpanTermExtractor (MultiPhraseQuery-to-span conversion)",
   "title": "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",
   "summary": "You search for the quoted phrase \"the dogs bark\" with an analyzer that removes the stop word 'the' and adds the synonym dog for dogs (QueryParser and QueryBuilder build a MultiPhraseQuery [dogs|dog] at position 1, bark at position 2, slop 0), and highlight the text 'dogs often bark but my dogs bark' with Highlighter and QueryScorer, expecting 'dogs often bark but my <B>dogs</B> <B>bark</B>' (Weight#matches reports only positions 5-6, and the same query starting at position 0, or a PhraseQuery at positions 1 and 2, is highlighted that way). Instead you get '<B>dogs</B> often <B>bark</B> but my <B>dogs</B> <B>bark</B>', with no error. WeightedSpanTermExtractor counts every empty slot from index 0 up to the last position as a position gap, including the unused slot 0 below the first position, so the phrase becomes an ordered SpanNearQuery with slop 1 instead of 0 (one extra unit per leading slot, also for sloppy phrases), while its PhraseQuery branch measures gaps from the first position.",
   "impact_class": "silent wrong results",
   "introduced_commit": "35c7eb36dfb07ff919147d7570158433e48cd092 (svn trunk r652164, 'Commit of LUCENE-794 patch - adding phrase/span query support to highlighter', committed by Mark Harwood; JIRA LUCENE-794 is now apache/lucene#1869) wrote the first MultiPhraseQuery-to-SpanNearQuery conversion, already with the slot loop that counts every null slot of disjunctLists[0..maxPosition] as a gap and 'new SpanNearQuery(clauses, slop + positionGaps, slop == 0)' [read]; the MultiPhraseQuery code came from 'MultiPhraseQueryExtraction.patch', attached to LUCENE-794 by Benjamin Keil on 2008-03-09 and folded into the main patch by Mark Miller on 2008-03-10, whose tests use only positions starting at 0. Later commits did not change the counted text: f32b5a56986 (LUCENE-1285, whole-file rewrite) and 3966f998214 (LUCENE-7417, 2016, one-clause special case) kept the loop [read]. The PhraseQuery branch never had this defect (relative since LUCENE-2003 in 2.9.1 and LUCENE-5503 in 5.4.0) and the MultiPhraseQuery branch was never aligned with it. Present since the code was written, not a regression; svn era, so no pull request",
   "introduced_date": "2008-04-29 (author and commit date of 35c7eb36dfb; the contributed MultiPhraseQuery patch is from 2008-03-09)",
   "first_affected_version": "2.4.0 [exec] (release 2008-10-08), through the opt-in SpanScorer that LUCENE-794 added; the default QueryScorer is position-aware from 2.9.0 (LUCENE-1685, 10b41d2dce2) [exec]; 2.3.2, the last release before the introducing commit, has no position-aware scorer and no WeightedSpanTermExtractor [exec]",
   "affected_versions": "every release from 2.4.0 through 10.5.2, 10.6.0 (by reading) and main a9779ef3c193; no version has a fix [exec]. UnifiedHighlighter (PhraseHelper reuses the extractor since 6.3.0): affected in its default configuration on 6.3.0, 7.7.3 and 8.11.4 [exec]; default exact from 9.0.0 (LUCENE-9431 made WEIGHT_MATCHES the default) [exec]; affected with Builder#withWeightMatches(false) from 9.1.0 [exec]. Releases between the executed ones are covered by blame and git log -L [read]. Upstream main 20ced71c1e6e, branch_10x 657014b3c579 and branch_10_6 4ae946e5a9b9 still have the loop; the newest commit touching the file is dbf0d1426f13 (author date 2026-05-14, toArray clean-up) [read]. 10.6.0 (released 2026-10-29) was read at 4ae946e5a9b9 (above), not executed. Every run used JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-829.html",
   "repro": "repro/LFV-829/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-268",
   "priority": "low",
   "priority_rank": 346,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter re-analysis offset source (MemoryIndexOffsetStrategy under WEIGHT_MATCHES)",
   "title": "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",
   "summary": "You index a field whose tokens carry payloads as a plain TextField (no offsets), search with SpanPayloadCheckQuery or with IntervalQuery(Intervals.term(term, payloadFilter)), which matches the document, and highlight the hit with the UnifiedHighlighter on its default flags. You expect the snippet the highlighter gives with offsets in postings or with WEIGHT_MATCHES off, 'both terms. only <b>terms</b>.' for a check on the second 'terms'. Instead re-analysis builds its one-document MemoryIndex without payloads (MemoryIndexOffsetStrategy stores payloads only when the span PhraseHelper is position-sensitive, and WEIGHT_MATCHES replaces that helper with PhraseHelper.NONE), so Weight#matches on that copy finds nothing and the snippet is 'both terms. only terms.', while the interval query makes highlight() throw IllegalArgumentException 'Cannot create a payload-filtered iterator over field body because it has no indexed payloads'.",
   "impact_class": "silent wrong results",
   "introduced_commit": "b19ae942f154 (LUCENE-8286 'UnifiedHighlighter: new HighlightFlag.WEIGHT_MATCHES for MatchesIterator API', closes apache/lucene-solr#409, JIRA now apache/lucene#9333; the branch_7x backport bf7d1078e4ef shipped in 7.5.0): it made getPhraseHelper return PhraseHelper.NONE under WEIGHT_MATCHES and evaluated the whole query with Weight#matches against the re-analysis MemoryIndex, but only renamed the accessor in the older storePayloads condition (written by LUCENE-7438 722e8271243 and moved into MemoryIndexOffsetStrategy by LUCENE-7526 7af454ad767 in 2016, correct then), so that condition is always false under the new flag [read]; default exposure: 2719cf6630eb (LUCENE-9431, apache/lucene#362) turned WEIGHT_MATCHES on by default for 9.0.0 without touching the defect [read]; the exception form needs payload-filtered intervals from LUCENE-8694 (13aac3becde on branch_8x, 8.1.0) [read]",
   "introduced_date": "2018-08-29 (b19ae942f154, LUCENE-8286); default exposure 2021-10-22 (2719cf6630eb, LUCENE-9431)",
   "first_affected_version": "7.5.0 (tagged 2018-09-22) when the application enables WEIGHT_MATCHES itself (overriding getFlags); 9.0.0 (tagged 2021-12-06) with the default configuration [exec]",
   "affected_versions": "with WEIGHT_MATCHES enabled by the application: 7.5.0 through 8.11.4 [exec]; with the default configuration: 9.0.0 through 10.5.2, 10.6.0 (by reading) and main ea57360912ed [exec]; the missing-highlight form exists from 7.5.0, the exception form from 8.1.0; releases before 9.1.0 ran ports of the canonical test (main() programs with StandardTokenizer, flags set by overriding the protected getFlags) because UnifiedHighlighter.Builder and the org.apache.lucene.tests packages first shipped in 9.1.0; not affected: 7.4.0 and earlier (no WEIGHT_MATCHES flag; exec on 7.4.0: re-analysis highlights correctly); the heads of branch_10x, branch_10_6 and branch_9_12 carry the same two lines [read]; 10.6.0 (released 2026-10-29) was not run; not fixed anywhere as of ea57360912ed",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-268.html",
   "repro": "repro/LFV-268/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-508",
   "priority": "low",
   "priority_rank": 347,
   "novelty": "new",
   "withheld": false,
   "area": "join / block join Weight#matches (ParentsChildrenBlockJoinQuery; consumers BooleanWeight#matches, UnifiedHighlighter, Monitor HighlightsMatch)",
   "title": "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",
   "summary": "You index parent/child blocks, build a ParentsChildrenBlockJoinQuery (children that match childQuery and whose parent matches parentQuery, at most childLimitPerParent per parent) and ask its Weight for Matches, directly, inside a BooleanQuery, through the default UnifiedHighlighter or through Lucene Monitor, and you expect non-null Matches exactly for the join's hits, as Weight#matches documents ('or null if the document does not match the parent query'). Instead matches() returns the union of the parent query's and the child query's Matches on the same document without checking the join, so it is non-null for the parent document itself, for children of parents that do not match and for children over the limit (in the finder's test the only hit is doc 0, but docs 0, 1, 2 and 3 get Matches). Searches stay correct, but a query such as +text:size -join loses the Matches and highlights of its real hits, and Monitor's HighlightsMatch matcher reports documents the stored query does not match.",
   "impact_class": "silent wrong results",
   "introduced_commit": "1584c05b27ac31fbccb0ab328bf9f8eb6a7de414 (main, squash merge of PR #14728 '[BlockJoin] Add ParentsChildrenBlockJoinQuery', issue #14565, author Jinny-Wang, merged by msfroh) and its branch_10x backport 61b32ff6d3772906b12b9e7f855b8607e9261371; matches() was added in its current union form together with the class and has never changed [read]",
   "introduced_date": "2025-06-13 (main squash merge); branch_10x backport committed 2025-09-04",
   "first_affected_version": "10.4.0 [exec] (the first release with the class; 10.3.2 and 9.12.3 do not have it and the repro does not compile there [exec]; the 10.3 branch split from branch_10x on 2025-08-30, before the backport [read])",
   "affected_versions": "10.4.0, 10.5.0, 10.5.1, 10.5.2, 10.6.0 (by reading) and main ea57360912ed [exec]; the matches() body is byte-identical in 1584c05b27a, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main [read]; not fixed upstream: upstream main a9779ef3c193 has ParentsChildrenBlockJoinQuery.java byte-identical to ea57360912ed, and branch_10x and branch_10_6 have the same matches() [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-508.html",
   "repro": "repro/LFV-508/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-266",
   "priority": "low",
   "priority_rank": 348,
   "novelty": "new",
   "withheld": false,
   "area": "queries / span queries Matches API (SpanWeight#matches takes offsets and sub-matches from ContainSpans#collect for SpanWithinQuery; seen through the UnifiedHighlighter and MatchRegionRetriever)",
   "title": "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",
   "summary": "You index 'ab ac bc' in a field with offsets and ask Weight#matches for SpanWithinQuery(big = SpanNear([ab, bc], slop 1, in order), little = ac); you expect one match, 'ac' at position 1 with offsets [3,5) and sub-matches only inside it, which is what the equivalent Intervals.containedBy(ac, ordered(ab, bc)) reports. Instead the match says positions [1,1] but offsets [0,8) and lists ab@0 and bc@2 as sub-matches, because the offsets and sub-matches come from Spans#collect, which for SpanWithinQuery also collects the enclosing span. So the default UnifiedHighlighter marks '<b>ab</b> <b>ac</b> <b>bc</b>' instead of 'ab <b>ac</b> bc', and MatchRegionRetriever returns [0,8) on a field with offsets but [3,5) on the same text indexed with positions only; hits and scores are unaffected.",
   "impact_class": "silent wrong results",
   "introduced_commit": "028c86b1fa70faeec4f7705698a59557f58bcbb0 (master, first main-line release 8.0.0) and its branch_7x copy 2376d7dded3c0c03fa3bb9c75cc7d8c58bfcb319 (the released one, 7.5.0), 'LUCENE-8306: Allow iteration over submatches. Also includes LUCENE-8404, adding match iteration to SpanQuery' by Alan Woodward (@romseygeek); JIRA patch workflow, no GitHub PR, issues migrated as apache/lucene#9353 and #9451, no CHANGES.txt entry [read]. That commit added SpanWeight#matches, which takes positions from the spans but offsets and sub-matches from Spans#collect. Contributing precondition, not the introducing commit: 8914ec5f75079d07233e4dbb4f93df7ac5c6f403 (LUCENE-6706, apache/lucene#7764, @romseygeek, 2015-08-03, first released in 5.3.0) changed ContainSpans#collect from sourceSpans.collect to collecting both bigSpans and littleSpans, for payload scoring; reverting only that method body makes the repro pass on 7.5.0 and on main [exec], so the bug is the 2018 Matches code consuming the 2015 collect behaviour. Not a regression: wrong since span queries have had Matches",
   "introduced_date": "2018-07-22",
   "first_affected_version": "7.5.0 [exec] (through the branch_7x copy; first main-line release 8.0.0 [exec]). 7.4.0 is not affected: Weight#matches exists there (LUCENE-8229) but span queries inherit the default, which reports no positions or offsets, so the repro and its control both fail for that unrelated reason [exec]; Weight#matches does not exist before 7.4.0 [read]",
   "affected_versions": "every release from 7.5.0 through 10.5.2, 10.6.0 (by reading), branch_10x and branch_10_6 [read] and main ea57360912ed; not fixed upstream. [exec] the finder's repro or its release-portable variant fails 1 of 2 (startOffset 0 instead of 3; the SpanContainingQuery or Intervals.containedBy control passes) on 7.5.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea), and on main also with -da; a behaviour fingerprint (pos=[1,1] off=[0,8), sub-matches at positions 0, 1 and 2) is identical on 7.5.0, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main; the independent reproduction's own test fails 2 of 5 on main (-ea, -da), 10.5.2 and 9.12.3. On 9.0.0 the intervals control fails the same way, because the interval counterpart was fixed only in 9.1.0 (LUCENE-10229) [exec]. [read] a tag scan finds the three ingredients (ContainSpans#collect collects big and little, SpanWeight#matches takes offsets and sub-matches from collect, SpanWithin reports the little spans) in every release tag 7.5.0 to 10.5.2 of the history clone; 8.8.2 and 8.9.0 to 8.11.3 are not tagged there and are listed because 8.8.1 [read] and 8.11.4 [exec] are. Highlighter exposure [read]: UnifiedHighlighter WEIGHT_MATCHES since 7.5.0 (LUCENE-8286), on by default since 9.0.0 (LUCENE-9431); MatchRegionRetriever/MatchHighlighter since 9.0.0 (LUCENE-9463). Caveats: the history runs used -ea only, JDK 25 and seed DEADBEEF; 7.x ran with a JUnit 4 runner",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-266.html",
   "repro": "repro/LFV-266/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-872",
   "priority": "low",
   "priority_rank": 349,
   "novelty": "new",
   "withheld": false,
   "area": "search / IndriQuery (QueryVisitor traversal of Indri composite queries; consumers: QueryVisitor.termCollector, IndexSearcher's cumulative clause limit, RamUsageEstimator.sizeOf(Query), UnifiedHighlighter)",
   "title": "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",
   "summary": "You build an IndriAndQuery of ordinary TermQuery clauses, for example f:a and f:b, and inspect it with a QueryVisitor, as term extraction, highlighting, IndexSearcher's clause-count check and the query RAM estimate do. You expect the visitor to reach both clauses, as it does for a BooleanQuery over the same clauses, because Query#visit is documented to 'recurse through the query tree, visiting any child queries'. Instead IndriQuery.visit only calls visitor.visitLeaf(this), so termCollector returns [], with maxClauseCount=4 a 51-clause IndriAndQuery and BooleanQuery(IndriAndQuery(3), IndriAndQuery(3)) both run while the same nesting of BooleanQuery clauses throws TooManyClauses, and RamUsageEstimator.sizeOf gives 1,024 bytes for 1,000 clauses against 1,169,024 for the BooleanQuery.",
   "impact_class": "silent wrong results",
   "introduced_commit": "9cc5c9b7983cf181280e18819f8516dc16ccf1ef (LUCENE-9537 'Add initial Indri search engine functionality to Lucene', now issue apache/lucene#10577; PR apache/lucene-solr#2097 by GitHub cammiemw, squash-merged 2021-01-29), released through its branch_8x cherry-pick a6125fb93855 (CHANGES entry moved to 8.9.0 by 4d839225b147); the visitLeaf(this) body is already in the PR's first commit 087d9d2a07c (authored 2020-11-24) and was never discussed in review [read]; not a regression, so no bisect",
   "introduced_date": "2021-01-29 (lucene-solr#2097 squash-merged and cherry-picked to branch_8x the same day; the visitLeaf(this) line was authored 2020-11-24 in the PR's first commit)",
   "first_affected_version": "8.9.0 [exec] (the first release with the Indri classes; 8.8.2 has none and the repro does not compile there [exec]); on the main line 9.0.0 [exec]. The cumulative clause-limit effect starts at 9.0.0, where IndexSearcher's visitor-based limit first shipped (LUCENE-8811) [exec]",
   "affected_versions": "8.9.0 to 8.11.4 and every 9.x and 10.x release, 9.0.0 to 10.6.0 [exec]; the LRUQueryCache key under-count is main only (GITHUB#15124, e706267b893, CHANGES 11.0.0, in no release tag) [exec]; upstream main c5ab3e57b9ba, branch_10x and branch_10_6 still call visitLeaf(this) [read]; not fixed anywhere. All runs on aarch64 Linux with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-872.html",
   "repro": "repro/LFV-872/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-276",
   "priority": "low",
   "priority_rank": 350,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / matchhighlight (MatchRegionRetriever default offset strategy OffsetsFromTokens for fields indexed without positions; MatchHighlighter on top of it)",
   "title": "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",
   "summary": "You index a stored field without positions (one document 'foo bar', IndexOptions DOCS_AND_FREQS, or a StringField), run a PrefixQuery('ba') that matches it, and ask MatchRegionRetriever (or MatchHighlighter) with its default strategies for the hit regions; you expect the region [4,7) for 'bar', which a TermQuery('bar') on the same field, a FuzzyQuery('baz'~1) and the same PrefixQuery on a field with positions all give. Instead the field gets no hit regions at all ({}), although the document is a hit and Weight#matches reports a match on that field. The default strategy for such fields, OffsetsFromTokens, collects the query's terms only through QueryVisitor#consumeTerms, while constant-score multi-term queries report theirs through consumeTermsMatching, so its term set stays empty and no re-analysed token is kept.",
   "impact_class": "silent wrong results",
   "introduced_commit": "150a8dacb59712c731e66db1a56068326a0439f4 (LUCENE-9463 'Query match region retrieval component, passage scoring and formatting', apache/lucene-solr#1750, author dweiss, merged 2020-08-14) [read]. It added OffsetsFromTokens with a QueryVisitor that overrides only consumeTerms and made it the default for DOCS and DOCS_AND_FREQS fields; the visitor is unchanged on main apart from reformatting (6faa4f98e04) and refactors (2c1f9381390, 755de5aae33). The symptom also needs the companion commit 6244383e0d5 (LUCENE-9462, apache/lucene-solr#1749, same author, same day, an ancestor of 150a8dacb59), which made constant-score multi-term queries return real MatchesIterators on fields without positions; QueryVisitor#consumeTermsMatching predates both (bed694ec881, LUCENE-9062, 2019-11-27). The TermInSetQuery form starts with #12156 (3809106602a, backport fa1d050df1d, 9.6.0), which made TermInSetQuery a MultiTermQuery. Not a regression",
   "introduced_date": "2020-08-14",
   "first_affected_version": "9.0.0 [exec] (the first release with the matchhighlight package; 8.6.1 and 8.11.4 lack the API: compile error [exec]); the two-or-more-term TermInSetQuery form from 9.6.0 [exec]; DOCS_AND_CUSTOM_FREQS fields from 10.5.0 [read]",
   "affected_versions": "every 9.x and 10.x release, 9.0.0 through 10.6.0 (34 releases; 10.6.0 by reading), and main ea57360912ed [exec]; not affected: 8.x and older (no matchhighlight package); not fixed on main or branch_10x (OffsetsFromTokens.java last changed by #12881 on 2023-12-07, still consumeTerms-only; no open PR touches it); 10.6.0 (released 2026-10-29) not executed, affected by reading (branch_10_6 2763db11b0a has the same consumeTerms-only visitor; the matchhighlight package is unchanged from there to 4ae946e5a9b)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-276.html",
   "repro": "repro/LFV-276/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-595",
   "priority": "low",
   "priority_rank": 351,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / matchhighlight: MatchHighlighter multi-query highlighting (DocHit field values on top of MatchRegionRetriever's per-query stored-field loading)",
   "title": "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)",
   "summary": "You pass several queries to MatchHighlighter.highlight(topDocs, q1, q2), for example title:foo and body:bar for a document whose title is 'foo' and whose body is 'bar'; the class's own test passes the sub-clauses of the search query this way to give each query its own markers. You expect both fields to be highlighted, exactly as highlight(topDocs, title:foo OR body:bar) returns them: {title=[>foo<], body=[>bar<]}. Instead you get only {title=[>foo<]} (only {body=[>bar<]} with the queries swapped), with no error, because each document keeps only the stored fields that the first query's retriever loaded; 9.x returned both fields.",
   "impact_class": "silent wrong results",
   "introduced_commit": "755de5aae331301acf4c1acd3af6d7329998ee48 (#12881 'Performance improvements to MatchHighlighter and MatchRegionRetriever', author dweiss, merged into main only and never backported to 9.x). It removed DocHit's lazy document load, whose stored-field visitor accepted 'matchRanges.containsKey(field) || needsField.test(field)' (every field that any query matched; MatchHighlighter.java:191-197 at the parent b6999818474c), made DocHit copy the FieldValueProvider of the query that first reaches the document, and made each MatchRegionRetriever load only fieldsToLoadUnconditionally plus its own query's affected fields; both halves arrived in this one commit [read]",
   "introduced_date": "2023-12-07 (#12881 merged into main)",
   "first_affected_version": "10.0.0 [exec]; 9.12.3, the last 9.x release, passes [exec], as do 9.0.0 (the first release with MatchHighlighter), 9.9.0, 9.9.1 and 9.10.0 [exec]",
   "affected_versions": "every release from 10.0.0 through 10.6.0 (10.6.0 by reading) and main a9779ef3c193, never fixed. [exec] the finder's JUnit fails on 10.0.0, 10.1.0, 10.2.2, 10.3.2, 10.4.0 and 10.5.2 (-ea) and on main (-ea and -da); the independent reproduction's JUnit fails 4/4 on 10.0.0, 10.5.2 and main (-ea and -da); the intended-behaviour check re-ran the finder's JUnit on 10.5.2 (fail) and 9.12.3 (pass). [read] 10.2.0, 10.2.1, 10.3.0, 10.3.1, 10.5.0 and 10.5.1 contain the commit (git tag --contains) and no later commit touches the DocHit lines; branch_10_6 (2763db11b0a), and so 10.6.0 (released 2026-10-29), has the same DocHit code, not executed. Not affected: the whole 9.x line [exec]. Releases were run on JDK 25. No open upstream PR changes the DocHit field values (2026-10-26).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-595.html",
   "repro": "repro/LFV-595/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1044",
   "priority": "low",
   "priority_rank": 352,
   "novelty": "new",
   "withheld": false,
   "area": "search / BooleanQuery MUST_NOT bulk scoring (ReqExclBulkScorer)",
   "title": "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)",
   "summary": "You search +R -grp:old, where R matches every document and grp:old matches one run of consecutive doc IDs covering 9,000 of the 10,000 documents of a segment. You expect Lucene to jump over the excluded run, as 10.3.0 to 10.5.2 do in one docIDRunEnd step (on every release from 10.0.0 to 10.5.2 the required clause's iterator moves 1,001 times for the 1,000 hits). Instead, since #16669 ReqExclBulkScorer loads the exclusion into a bit mask per 4096-doc window and always runs the required clause over every window, even windows the exclusion covers completely, so the iterator moves 10,001 times; the 1,000 hits are still right, only the work now grows with the length of the excluded run.",
   "impact_class": "minor",
   "introduced_commit": "c5fa32ce49f6 (apache/lucene#16669 'Use intoBitSet to speed up ReqExclBulkScorer with dense exclusions', by kkewwei for their issue #16668; reviewed and merged by romseygeek on main 2026-09-24; branch_10_6 backport 92ce3eaf4bf the same day) [exec]. It replaced the leap-frog loop (LUCENE-6940, 5.5.0/6.0.0) that called the required bulk scorer only on the gaps between excluded docs, and removed both docIDRunEnd branches: the DocIdSetIterator one from #14976 (10.3.0; the released behaviour that regresses) and the two-phase one from #16307 (added in the same 10.6 cycle, never released).",
   "introduced_date": "2026-09-24 (author date of c5fa32ce49f, 2026-09-24T08:30:33Z, equal to the PR merge time; the branch_10_6 backport 92ce3eaf4bf has the same author date and was committed at 08:33:25Z the same day)",
   "first_affected_version": "10.6.0, released 2026-10-29 (the first affected release: 10.6.0 RC1 4ae946e5a9b reproduces it [exec] and is the commit released as 10.6.0; on the main line 11.0.0, unreleased; the last unaffected release is 10.5.2)",
   "affected_versions": "[exec] main 645d4fe14a20 (minimal repro, -ea and -da; seeds DEADBEEF, 5EED4351, 7A11E5ED, A11CE5ED and 0D055E17 each give 10,001 required-iterator moves for 1,000 hits), the introducing commit c5fa32ce49f (-ea and -da) and 10.6.0 RC1 4ae946e5a9b (official staged core, codecs and test-framework jars, SHA-512 checked, and a build of the RC1 commit; -ea and -da); [read] upstream main head 70a428b5ba9, branch_11x head 203699279f5 and branch_10_6 head 6dde6c73bd1 (the last commit on ReqExclBulkScorer.java is still #16669 on all three, checked 2026-10-29). Not affected [exec]: all 12 releases 10.0.0 to 10.5.2 (-da; 10.5.2 also -ea), 9.12.3 (with a two-hunk 9.x API port of the measuring clause only, -ea and -da) and the parent commit c80c9f53674; 9.0.0-9.12.3 have a byte-identical ReqExclBulkScorer.java [read]. 10.0-10.2 also kept R out of excluded runs but stepped the excluded iterator once per excluded doc, so the fair cost baseline is 10.3.0-10.5.2.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1044.html",
   "repro": "repro/LFV-1044/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b): the minimal repro fails 1 of 1 with -ea and -da on the official staged jars (10,001 required-iterator moves for 1,000 hits); 10.5.2 passes 1 of 1 with -ea and -da (1,001 moves)."
  },
  {
   "id": "LFV-1057",
   "priority": "low",
   "priority_rank": 353,
   "novelty": "new",
   "withheld": false,
   "area": "search / field sorting: TopFieldCollector + NumericComparator points-based sort pruning (competitive iterator)",
   "title": "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)",
   "summary": "You run searcher.search(new TermQuery(new Term(\"brand\", \"lux\")), 10, new Sort(new SortField(\"price\", SortField.Type.LONG))) over two segments: the first has 1,001 hits, so the default 1,000-hit threshold is crossed there, and in the second the query matches one document that cannot compete. You expect the second segment not to read its points, because the comparator builds its competitive iterator from points only when that cuts the query's own cost at least 8x; 645d4fe, 10.6.0, 10.5.2 and 9.12.3 read 0 point doc IDs there. Instead, since #16857 the new leaf collector tells the comparator about the threshold before setScorer(), while its cost is still the -1 'no scorer yet' value (so the 8x limit becomes 2^61-1), and it intersects the whole competitive range, 1,001 doc IDs; the top 10 is still right, only the work is wasted.",
   "impact_class": "minor",
   "introduced_commit": "70a428b5ba90cdbcf3c8380e21b006a68b4dcb85 (apache/lucene#16857 'Consolidate Sort pruning logic', author romseygeek (Alan Woodward), squash-merged to main 2026-10-29; branch_11x backport 203699279f5 the same day; the constructor call is already in the PR's first commit 466a0384cb8 of 2026-10-16) [exec]. The other ingredients were harmless before, because setHitsThresholdReached() was only called from countHit(), after setScorer(): the leaf hook setHitsThresholdReached -> updateCompetitiveIterator and the 'iteratorCost >>> 3' check (99220677fe4, LUCENE-9449 era, 2020) and the iteratorCost == -1 sentinel (f431511cb71, LUCENE-10555 / #864, 2022).",
   "introduced_date": "2026-10-29 (author date of 70a428b5ba9, 2026-10-29, equal to the merge time; the branch_11x backport 203699279f5 has the same author date; the code was first written on the PR branch on 2026-10-16)",
   "first_affected_version": "unreleased (11.0.0 would be the first release; #16857's CHANGES entry is under Lucene 11.0.0); 10.6.0, released 2026-10-29 from 4ae946e5a9b, and every earlier release are not affected; the last unaffected main commit is e0fa3535ea5",
   "affected_versions": "[exec] upstream main at the introducing commit 70a428b5ba9 (-ea and -da) and at the head 716d6f216f5 (-ea and -da, both through the 13-file shadow over the 645d4fe jars and, at the registration check on 2026-10-30, through a javac build of the full lucene/core source tree at 716d6f216f5: 'expected:<0> but was:<1001>'), branch_11x head 603af870375 (-da). Not affected [exec]: main parent e0fa3535ea5 (-ea, -da), main 645d4fe14a20 (-ea, -da; it predates #16857), 10.6.0 = 4ae946e5a9b (-ea, -da), 10.5.2 (-ea, -da) and 9.12.3 (-ea, -da), all with the 10.x-signature port on releases; a non-vacuity control counts 512 point doc IDs on 10.6.0 and 9.12.3, so the 0 there is a real measurement. [read] branch_10_6 has no constructor call (setHitsThresholdReached only in countHit); TopFieldCollector.java and NumericComparator.java are byte-identical on main and branch_11x, and #16857 is the last commit on both files on both branches (checked 2026-10-30). [exec] upstream main e1faeba08bd, a native 12.0.0-SNAPSHOT build with no shadow, fails with -ea and -da ('expected:<0> but was:<1001>'); [read] branch_11x da3ea39fa59 has both files identical to main.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1057.html",
   "repro": "repro/LFV-1057/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-791",
   "priority": "low",
   "priority_rank": 354,
   "novelty": "new",
   "withheld": false,
   "area": "search / sorting (TopFieldCollector, relevance-first sort: minimum competitive score at the totalHitsThreshold crossing)",
   "title": "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)",
   "summary": "You run IndexSearcher#search(query, 10, Sort.RELEVANCE), or a searchAfter page sorted by Sort(SortField.FIELD_SCORE, tiebreak), on a query with many matches, and expect it to start skipping non-competitive documents once 1,000 hits are counted, as search(query, 10) does and as LUCENE-8507 made relevance-first TopFieldCollector do from 8.0.0 to 8.6.3. Instead TopFieldCollector.countHit flips totalHitsRelation to GREATER_THAN_OR_EQUAL_TO on the hit that crosses the threshold, before thresholdCheck's EQUAL_TO-guarded updateMinCompetitiveScore call runs, so that call can never take effect and the minimum competitive score is set only when a later hit is competitive; with the best documents first, the relevance-sorted search scores all 10,011 matches where search(query, 10) stops at 1,024, with the same top 10. This is a regression from LUCENE-9449 (8.7.0); results are always correct.",
   "impact_class": "minor",
   "introduced_commit": "99220677fe409bab5c4206dc31f186d0c4335280 on master (apache/lucene-solr#1725 'LUCENE-9449 Skip docs with _doc sort and \"after\"', by mayya-sharipova, merged 2020-09-08; issue LUCENE-9449, migrated as apache/lucene#10489), backported to branch_8x as 754216821001772a0890d7245765e2ffb3f917f2 (apache/lucene-solr#1856, 2020-09-17), the commit that shipped in 8.7.0. In countHit it replaced the relation flip condition 'filteringLeafComparator != null && ...' (never true for a RelevanceComparator) with 'scoreMode.isExhaustive() == false && ...', which is true for TOP_SCORES, following a review suggestion on #1725 to set GREATER_THAN_OR_EQUAL_TO whenever a TOP_SCORES collection reaches the threshold; this made the EQUAL_TO-guarded updateMinCompetitiveScore call on the threshold-crossing non-competitive hit dead (that call came with LUCENE-8507, 947f82679af, 8.0.0, and was reworked in 93d135e79d7, LUCENE-8992, 8.4.0) [read] [exec]",
   "introduced_date": "2020-09-08 (master); 2020-09-17 (branch_8x backport, released in 8.7.0)",
   "first_affected_version": "8.7.0 [exec]. Not affected: 8.0.0 through 8.6.3 [exec]. Before 8.0.0 the feature did not exist [exec].",
   "affected_versions": "every release from 8.7.0 through 10.6.0 (10.6.0 by reading) and main a9779ef3c193. [exec] the finder's repro fails on 8.7.0, 8.8.2, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.1.0, 10.5.2 and main (-ea and -da; follow-up sweep, JDK 25, seed DEADBEEF), its Sort(FIELD_SCORE, id) variant on 8.7.0, 8.11.4, 9.12.3, 10.5.2 and main; the independent reproduction's searcher-level JUnit fails on 8.7.0, 9.12.3, 10.5.2 and main, its collector-level JUnit (needs TopFieldCollectorManager, 9.9+) on 9.12.3, 10.5.2 and main; the intended-behaviour check's static-rank probe on 10.5.2 and main. [read] git tag --contains: 99220677fe4 is in every tag 9.0.0-10.6.0 and 75421682100 in 8.7.0, 8.8.0 and 8.8.1 (the history clone has no 8.8.2-8.11.4 tags; 8.8.2 and 8.11.4 by execution). Main e1faeba08bd [exec], branch_11x da3ea39fa59 (same TopFieldCollector.java as main) and branch_10_6 91eaab4fb29 (same as 10.6.0) still have the flip and the guarded calls [read]. Not affected [exec]: 8.0.0, 8.5.2, 8.6.0, 8.6.3; 7.7.3 has no relevance-first propagation at all.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-791.html",
   "repro": "repro/LFV-791/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-334",
   "priority": "low",
   "priority_rank": 355,
   "novelty": "new",
   "withheld": false,
   "area": "core / search: DoubleValuesSourceRescorer.rescore and explain (score-dependent DoubleValuesSource)",
   "title": "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",
   "summary": "You subclass DoubleValuesSourceRescorer to re-rank first-pass hits with a source that uses the query score, for example DoubleValuesSource.SCORES or the expression '_score * 2' with _score bound to SCORES, and expect rescore() to work as it does for any other source: the constructor accepts any DoubleValuesSource and documents no restriction. Instead rescore() calls source.getValues(ctx, null) for every source (DoubleValuesSourceRescorer.java:73), although DoubleValuesSource#getValues allows a null scores argument only when needsScores() is false and the SCORES javadoc says callers must not pass null, so it throws on the first hit: an AssertionError with -ea, and with -da a NullPointerException at line 74 or, for the expression, RuntimeException 'Unrecognized variable (_score) referenced in expression (_score * 2).'. explain() for the same rescorer, source and document returns a normal explanation, because it passes a placeholder 'DoubleValuesSource was not initialized with query scores' explanation instead of scores.",
   "impact_class": "crash",
   "introduced_commit": "c8147c9e6fa19e12390f1b2f66e18c0af3654d44 on main and its branch_10x backport 02f5dc30e2fe (the commit the 10.3.0 tag contains), 'Add a rescorer that uses DoubleValuesSource values to re-score first pass hits', apache/lucene#14776 by vigyasharma [read]. Not a regression: the defect is in the first version of the class. The violated callee contract (getValues javadoc, SCORES 'assert scores != null') dates from LUCENE-5325 (3f24fd81c836, 2016) [read]",
   "introduced_date": "2025-06-15 (#14776 merged; author date 2025-06-14)",
   "first_affected_version": "10.3.0 [exec] (first release with DoubleValuesSourceRescorer; 10.2.2, all earlier 10.x and all 9.x releases do not have the class: compile_error on 10.2.2 and 9.12.3)",
   "affected_versions": "10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main ea57360912ed [exec]. Not applicable: 10.2.2 and every earlier release (class absent; compile_error on 10.2.2 and 9.12.3 [exec]). Not fixed: line 73 is unchanged on upstream main, branch_10x, branch_10_6 and branch_10_5 (the file's last change, #15826 on 2026-03-16, keeps the null), so the released 10.6.0 has it, and no open PR fixes it [read]. All runs on JDK 25, aarch64 Linux.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-334.html",
   "repro": "repro/LFV-334/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1101",
   "priority": "low",
   "priority_rank": 356,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / classic Highlighter (WeightedSpanTermExtractor internal reader FieldInfos)",
   "title": "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)",
   "summary": "You highlight new RescoreTopNQuery(body:fox, DoubleValuesSource.fromLongField(\"popularity\"), 10) with the classic Highlighter and QueryScorer(q, \"body\") and expect a fragment with fox marked, because the extractor ignores query parts it cannot use. Instead highlighting throws IllegalStateException 'unexpected docvalues type NONE for field popularity': the extractor rewrites the query on an internal one-document reader whose getFieldInfos() (added by GITHUB#15678 in 10.5.0) describes every field name as the highlighted text field, so the rescorer's doc-values check fails; a filtered kNN clause highlighted from term vectors fails the same way inside FieldExistsQuery.",
   "impact_class": "crash",
   "introduced_commit": "unknown (not bisected to one commit). [exec] the same queries threw UnsupportedOperationException on 10.3.0 and 10.4.0 (the internal DelegatingLeafReader did not implement getFieldInfos, the root reported in LUCENE-6390); GITHUB#15678 (fixing #15668, 10.5.0) added a getFieldInfos() that maps every name to the highlighted field, which turned the failure into IllegalStateException for these rewrites [read]. RescoreTopNQuery exists since 10.3.0.",
   "introduced_date": "unknown (not bisected); 10.3.0 (UnsupportedOperationException form) and 10.5.0 (IllegalStateException form) per the executed release runs",
   "first_affected_version": "10.5.0 [exec] for this row's IllegalStateException (GITHUB#15678's mapping; 2 of 3 tests); the same queries failed earlier with UnsupportedOperationException on 10.3.0 and 10.4.0 [exec] (3 of 3), the predecessor form of the same #7450 root",
   "affected_versions": "10.3.0 and 10.4.0 fail 3 of 3 (UnsupportedOperationException) [exec]; 10.5.0 and 10.5.2 fail 2 of 3 [exec]; branch_10_6 head 4ae946e5a9b [exec] and the released 10.6.0 [exec] fail 2 of 3; main e1faeba08bde fails 2 of 3 with -ea and -da [exec]. The third test (filtered kNN over re-analysed text) passes since 10.5.0.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/7450",
    "https://issues.apache.org/jira/browse/LUCENE-6390",
    "https://github.com/apache/lucene/issues/15668",
    "https://github.com/apache/lucene/issues/15678"
   ],
   "doc": "",
   "repro": "repro/LFV-1101/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-729",
   "priority": "low",
   "priority_rank": 357,
   "novelty": "new",
   "withheld": false,
   "area": "facet / FacetsConfig drill-down term indexing (DrillDownTermsIndexing.NONE in a shared indexFieldName) vs the core per-field schema check (IndexingChain FieldSchema, FieldInfo.verifySameIndexOptions)",
   "title": "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",
   "summary": "You call config.setDrillDownTermsIndexing(\"rating\", NONE), leave every dimension in the default index field $facets, and index one document with only FacetField(\"rating\", \"5\") and then one with FacetField(\"author\", \"Bob\"); you expect both to be indexed, as they are on Lucene 8.9 to 8.11 and as they are when rating gets its own index field. FacetsConfig.build gives the first document a doc-values-only $facets (NONE adds no drill-down terms) and the second a $facets with drill-down terms, and since 9.0 Lucene requires one schema per field, so the second addDocument throws IllegalArgumentException 'Inconsistency of field data structures across documents for field [$facets] of doc [1]. index options: expected 'NONE', but it has 'DOCS'' (with taxonomy facets the reverse order fails the same way). After a commit, a new IndexWriter keeps rejecting documents of the other kind ('cannot change field \"$facets\" from index options=NONE to inconsistent index options=DOCS') until the index is cleared or rebuilt.",
   "impact_class": "wrong error",
   "introduced_commit": "d03662c48bfc5bf2be4840a7f743f9cb64b17fee (apache/lucene#11, LUCENE-9334 'Consistency of field data structures', mayya-sharipova, merged to main 2021-04-14; issue #10374) is the first commit at which the repro fails [exec]. It is the second of two changes. The first, 3648a1020a8ab6b729ed53e0360499e624bb0cd1 (apache/lucene#25, LUCENE-9385 'Add option to skip indexing facet drill down terms', zacharymorn, merged 2021-03-27; 8.x backport e812a508590, apache/lucene-solr#2471), added DrillDownTermsIndexing with NONE and the still-unchanged indexDrillDownTerms, which adds no StringField for a NONE dimension while the dimension's doc values still go into the shared indexFieldName [read]; at 3648a1020a8 the repro passes [exec], because the core then silently upgraded a doc-values-only occurrence of a field (index options NONE) to DOCS (FieldInfo.update). LUCENE-9334 replaced that with an exact per-field schema check (IndexingChain FieldSchema.assertSameSchema, FieldInfo.verifySameIndexOptions); its rejection is intended (CHANGES 9.0.0, MIGRATE.md). Neither PR's discussion mentions the other, and #25's tests always put a term-indexing dimension in every document. An unnoticed interaction of two changes 18 days apart; the defect is in the facet layer",
   "introduced_date": "2021-04-14 (d03662c48bf, LUCENE-9334); the trigger API dates from 2021-03-27 (3648a1020a8, LUCENE-9385) and 2021-03-29 (8.x backport e812a508590, released in 8.9.0, where the bug does not occur)",
   "first_affected_version": "9.0.0 [exec]; 8.9.0 to 8.11.4 have the API and accept every document [exec]; 8.8.2 and older lack DrillDownTermsIndexing [exec]; LUCENE-9334 was never backported to 8.x",
   "affected_versions": "Every release from 9.0.0 through 10.5.2 (all 33 on Maven Central: 9.0.0 to 9.12.3 and 10.0.0 to 10.5.2) and main a9779ef3c193 [exec]; the finder's JUnit fails 3 of 5 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main [exec]. branch_10x and branch_10_6 (10.6.0, released 2026-10-29) carry the same FacetsConfig and IndexingChain code [read], so 10.6.0 is affected too; the two upstream main commits after a9779ef3c193 do not touch lucene/facet or the core check [read]. Not affected: 8.9.0, 8.10.0, 8.10.1 and 8.11.0 to 8.11.4 [exec]. One scenario differs from 10.5.0 on: with sorted-set facets, a term-indexing document followed by a NONE-only document in the same in-memory segment is (wrongly) accepted because of the registered core bug LFV-118 (frozen-FieldType validation cache, #15886); every other scenario, and every scenario after a commit and a new writer, still fails on 10.5.0 through main. All runs JDK 25, aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-729.html",
   "repro": "repro/LFV-729/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-967",
   "priority": "low",
   "priority_rank": 358,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / document (NRT) suggester: CompletionWeight#scorerSupplier vs the Weight/ScorerSupplier contract and IndexSearcher#searchLeaf",
   "title": "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)",
   "summary": "You index suggestions with SuggestField and run a PrefixCompletionQuery through IndexSearcher#search with a CollectorManager of TopSuggestDocsCollector, on an index where one segment has no document with the suggest field (or where the query's filter matches no document of a segment). You expect the same suggestions as SuggestIndexSearcher#suggest (3 in the repro), because Weight#scorerSupplier 'must return null if the scorer is null' and IndexSearcher then skips that segment, as 9.12.3 does. Instead CompletionWeight returns a non-null ScorerSupplier whose bulkScorer() returns null, and IndexSearcher#searchLeaf throws NullPointerException ('Cannot invoke BulkScorer.score(...) because \"scorer\" is null'; with a timeout set, Objects.requireNonNull in TimeLimitingBulkScorer throws it first).",
   "impact_class": "crash",
   "introduced_commit": "ddf538d43e94a814f783fcc40728ee45038a03a1 (apache/lucene#13408 'Move bulkScorer() from Weight to ScorerSupplier', by jpountz, approved by mikemccand; main only, milestone 10.0.0): it made Weight#bulkScorer a final helper, moved CompletionWeight's three 'return null' paths (no terms, no FST, MatchNoBits filter) from its overridden Weight#bulkScorer, which IndexSearcher null-checked, into ScorerSupplier#bulkScorer, and changed IndexSearcher to null-check only the supplier. Precondition: 838b23ebed1a (apache/lucene#13319 'Make Weight#scorerSupplier abstract, Weight#scorer final', by iamsanjay, merged by jpountz, 2024-05-14) added the 'It must return null if the scorer is null' rule and gave CompletionWeight its always-non-null supplier, harmless until #13408. [read]",
   "introduced_date": "2024-05-27 (author date = merge date of ddf538d43e9); precondition #13319 2024-05-14",
   "first_affected_version": "10.0.0 [exec] (tagged 2024-10-14); last unaffected release 9.12.3 [exec] (no 9.x release contains #13408). CompletionQuery/CompletionWeight exist since 5.3.0 (LUCENE-6459)",
   "affected_versions": "every 10.x release from 10.0.0 to 10.6.0 and main. [exec] fail: 10.0.0 (-ea and -da), 10.1.0, 10.2.2, 10.3.2, 10.4.0, 10.5.2 and the branch_10_6 head 4ae946e5a9b9 (-da), main a9779ef3c193 (-ea and -da); the finder's, the independent reproduction's, the intended-behaviour check's and the adjudication's repros agree on main, 10.0.0 and 10.5.2. [exec] pass (the same 3 suggestions as SuggestIndexSearcher#suggest): 9.12.3 (-ea and -da), 9.11.1, 9.11.0, 9.10.0, and 9.0.0 and 8.11.4 with a legacy copy that omits the timeout leg (no IndexSearcher#setTimeout there). [read] 10.2.0, 10.2.1, 10.3.0, 10.3.1, 10.5.0 and 10.5.1 by git tag --contains ddf538d43e9 and the unchanged CompletionWeight/IndexSearcher null handling. Triggers executed: a segment without the suggest field and a BitsProducer filter returning MatchNoBits for one segment (also on an index where every segment has the field); the no-FST trigger is by code reading only. Not fixed upstream: CompletionWeight.java last changed by b0ebaaed5650 (#14216, errorprone clean-up, 2025-02-12); upstream main head 645d4fe14a20 (2026-10-28) and branch_10_6 unchanged. All runs on Linux aarch64 with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-967.html",
   "repro": "repro/LFV-967/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-969",
   "priority": "low",
   "priority_rank": 359,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / document (NRT) suggester: CompletionScorer under IndexSearcher's windowed execution (setTimeout, intra-segment partitions)",
   "title": "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",
   "summary": "You run a CompletionQuery through IndexSearcher#search with a TopSuggestDocsCollector (for example suggestSearcher.search(query, collector)) on a searcher that has a timeout set, even one that never fires, or that splits a segment into intra-segment partitions. You expect the same top suggestions as SuggestIndexSearcher#suggest, or a loud error if this path is unsupported, because BulkScorer#score must score only the documents in [min, max) and a timeout that never fires must not change results. Instead CompletionScorer runs its whole-segment top-N lookup again on every window or partition, so the top suggestions come back several times and lower ones are dropped (500 suggestions, n=5: [499, 499, 498, 498, 497] instead of [499, 498, 497, 496, 495]; one suggestion returned 5 times; partitions: [499 x5]), while the total says EQUAL_TO and timedOut() is false.",
   "impact_class": "silent wrong results",
   "introduced_commit": "be4d58c7740bea4e797eb1acff6355eb260e7c93 (trunk, 'LUCENE-6459: add common suggest API for document based NRT suggester', patch by Areek Zillur, committed by mikemccand; JIRA LUCENE-6459, migrated as apache/lucene#7518; no PR, SVN era), released through the branch_5x backport 380bb29f39595de1c3947075296d1d0a36f02fd8 [read]. It added CompletionScorer.score ignoring min and max and returning max; the logic is unchanged on main (d671dd8d890 LUCENE-6553 changed only the signature, 813ca77250d and 2cbf261032d are header and formatting). Not a regression. It became reachable through IndexSearcher#search later, without touching the suggest module: #927 (LUCENE-10151, setTimeout, 9.3.0: loud CollectionTerminatedException), #996 (9.4.0: the exception is caught, so the duplicates turn silent) and #13542 (intra-segment partitions, 10.0.0)",
   "introduced_date": "2015-05-28 (author and commit date of be4d58c7740 and 380bb29f395); exposure through IndexSearcher#search: 2022-06-29 (#927), 2022-07-04 (#996), 2024-09-10 (#13542)",
   "first_affected_version": "5.3.0 [exec] for the root defect (a direct Weight#bulkScorer + BulkScorer#score call with a window); through IndexSearcher#search silently from 9.4.0 [exec] for the timeout leg (9.3.0 throws CollectionTerminatedException instead [exec]) and from 10.0.0 [exec] for the intra-segment partition leg",
   "affected_versions": "Root defect: every release from 5.3.0 to 10.6.0 and main [exec]. Silent wrong results under a timeout: 9.4.0 to 10.6.0 and main [exec]. Silent wrong results with intra-segment partitions: 10.0.0 to 10.6.0 and main [exec]. 9.3.0: the timeout leg throws CollectionTerminatedException [exec]. Before 9.3.0 IndexSearcher has no setTimeout and before 10.0.0 no partitions, so only a direct BulkScorer#score call shows it [exec]. Not fixed upstream: CompletionScorer.java unchanged since 2cbf261032dc (2021-01-05) on main 645d4fe14a20 (author date 2026-10-28), branch_11x, branch_10x and branch_10_6. All runs on Linux aarch64 with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-969.html",
   "repro": "repro/LFV-969/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-237",
   "priority": "low",
   "priority_rank": 360,
   "novelty": "new",
   "withheld": false,
   "area": "index / vector values iteration (KnnVectorValues.fromDISI) with backward-codecs / Lucene 9.4 sparse byte vector reader",
   "title": "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",
   "summary": "You open, on Lucene 10, an index whose segment was written by Lucene 9.4.2 with a byte vector field that only some documents have, move the field's iterator to a document with advance(doc) and read vectorValue(iterator.index()), which is what ByteKnnVectorFieldSource does, and expect that document's own vector, because DocIndexIterator.index() is documented as the ordinal of the current document and DocIdSetIterator.advance() must behave like repeated nextDoc() calls. Instead every document that has a vector reads as all zeros: the iterator that KnnVectorValues.fromDISI builds, which this one reader returns, counts the ordinal only in nextDoc(), and its advance() moves to the document without moving the ordinal, so index() stays at -1 (the reader then hands back its never-filled buffer); after earlier nextDoc() calls, index() is an earlier document's ordinal and the read returns that document's vector. Lucene 9.x reads the same index correctly; the defect came with the 10.0 vector-values API change #13779.",
   "impact_class": "silent wrong results",
   "introduced_commit": "6053e1e31378378f6d310a05ea6d7dcdfc45f48b (#13779 'First-class random access API for KnnVectorValues', msokolov, addresses #13778, merged 2024-09-28, milestone 10.0.0) [read]: it added fromDISI and switched the Lucene 9.4 sparse byte reader's iterator() to fromDISI(disi), while the Lucene 9.4 float reader got IndexedDISI.asDocIndexIterator(disi) in the same commit; before it, the 9.4 sparse reader was itself the iterator and read vectorValue(disi.index()), which is correct. Inside the PR, commit d43785d (2024-09-15, 'no default advance(); default cost() unsupported') replaced the inherited slowAdvance(target) default, which kept the ordinal right, with the forwarding advance() after a review comment called the default a possible performance trap [read]. Release-level execution on both sides: 9.12.0 passes (9.x-API variant), 10.0.0 fails",
   "introduced_date": "2024-09-28 (merge of #13779; the forwarding advance() was written in its commit d43785d on 2024-09-15)",
   "first_affected_version": "10.0.0 [exec] (the first release with #13779, tagged 2024-10-14); no 9.x release has KnnVectorValues, DocIndexIterator or fromDISI, and the 9.x reader reads the same 9.4.2 index correctly [exec]",
   "affected_versions": "every 10.x release through 10.5.2 (10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2) and main ea57360912ed [exec]; not affected: 9.x [exec]; the source of both defect lines is unchanged at all 12 10.x release tags through 10.5.2 [read]; branch_10x has the same fromDISI and lucene94 iterator(), and on branch_10_6 the two files changed after #13779 only through #15722 and #13837, which leave these lines alone [read], so 10.6.0 (released 2026-10-29) is very likely affected (not executed); not fixed on main. Only segments written by Lucene 9.4.0, 9.4.1 or 9.4.2 reach the defect on the stock read path (the only releases with the Lucene94 vector format; byte vectors first appeared in 9.4.0, LUCENE-10577); fixtures were written with 9.4.2 only [exec], 9.4.0 and 9.4.1 by format [read]. On unreleased main, MIN_SUPPORTED_MAJOR was 10 between #15012 (2025-09-18) and #16741 (2026-10-15), so main refused 9.x-created indexes by default in that window [read]; it is 9 at ea57360912ed",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-237.html",
   "repro": "repro/LFV-237/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-396",
   "priority": "low",
   "priority_rank": 361,
   "novelty": "new",
   "withheld": false,
   "area": "core / document: shape doc values (ShapeDocValues reader behind LatLonShapeDocValues / XYShapeDocValues relate and the slow doc-values shape queries; MemoryIndex shape doc-values fields)",
   "title": "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",
   "summary": "You build a LatLonShape or XYShape doc value from a BytesRef that points into the middle of a larger byte array (offset != 0), for example with LatLonShape.createLatLonShapeDocValues(BytesRef) or as a MemoryIndex field, and expect relate() and the doc-values shape queries to answer exactly as for the same bytes at offset 0. Instead, ShapeDocValues reads its header at the offset but then rewinds its ByteArrayDataInput to position 0 of the backing array, so relate() decodes whatever bytes sit at the start of that array: the relation is silently wrong in either direction (CROSSES or INSIDE becomes OUTSIDE, OUTSIDE becomes CROSSES), and on a MemoryIndex an overlapping shape is missed by an INTERSECTS box query and matched by a DISJOINT one. getBoundingBox() and getCentroid() stay correct, which hides the problem.",
   "impact_class": "silent wrong results",
   "introduced_commit": "d7fd48c9502c567e4760a011fa99b1a491fea2cb, apache/lucene#1017 LUCENE-10654 'Add new ShapeDocValuesField for LatLonShape and XYShape' (by nknize, merged to main 2022-08-09; 9.x backport ddf0d0acf4e4, #1064, the same day) [read]. The public relate() entry point createLatLonShapeDocValues / createXYShapeDocValues(BytesRef) came with e7253f112de (#11753, main) and a4ef70f0656 (#11890, 9.x) on 2022-10-28; ByteArrayDataInput.rewind() and its warning NOTE date from 2011 (b7846ffaa1f).",
   "introduced_date": "2022-08-09 (public relate() factories: 2022-10-28)",
   "first_affected_version": "9.4.0 (2022-09-30; MemoryIndex path [exec]; 9.3.0 lacks the API [exec]); public relate() factory path from 9.5.0 [exec]; first 10.x release 10.0.0 [exec]",
   "affected_versions": "Every release from 9.4.0 to 9.12.3 and from 10.0.0 to 10.6.0 (10.6.0 by reading), and main ea57360912ed. [exec] MemoryIndex path fails on 9.4.0 (-ea and -da), 9.4.2, 9.5.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main; the public factory relate() path fails on 9.5.0 (-ea and -da), 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da); the bulk BinaryDocValues#binaryValues path fails on main (API absent in 10.5.2: compile error; not executed on 10.6.0, the first release with it); the on-disk IndexWriter + IndexSearcher control passes on 9.4.0, 9.12.3, 10.5.2 and main. [read] every release tag from 9.4.0 on contains the buggy lines, ShapeDocValues.java is byte-identical in 10.0.0 to 10.5.2 and main, and upstream main cf398bfb142c (2026-10-26) and the branch_10_6 / branch_10x heads of 2026-10-24 still have them. Releases between those executed were checked by grep only; old releases ran on JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-396.html",
   "repro": "repro/LFV-396/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-405",
   "priority": "low",
   "priority_rank": 362,
   "novelty": "new",
   "withheld": false,
   "area": "facet / facet sets (MatchingFacetSetsCounts.count, a BinaryDocValues consumer; reached through MemoryIndex, custom readers and the backward-codecs Lucene80 BEST_COMPRESSION doc-values producer)",
   "title": "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)",
   "summary": "You count facet sets with MatchingFacetSetsCounts over a reader that hands back a document's facet-set binary doc value as a BytesRef slice of a larger array (offset != 0), for example a MemoryIndex holding a value that was packed into a shared buffer, and expect the same counts as for a compact copy of the same bytes. Instead count() reads the dimension count from bytes[0] and the dimension values from bytes[4..length) of the backing array, ignoring the offset, so the document is counted under whatever bytes start that array: a document whose set is (3,4), stored right after an encoding of (1,2), is counted as (1,2)=1 and (3,4)=0, with no error. When the leading bytes do not decode to a sane dimension count, the MatchingFacetSetsCounts constructor throws NegativeArraySizeException or ArrayIndexOutOfBoundsException instead, while the same value indexed through IndexWriter with the default codec is counted correctly.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f6bb9d218c0e8315d86d2aa2ac1f5c7313925a7a, apache/lucene#841 LUCENE-10274 'Add FacetSets faceting capabilities' (PR by mdmarshmallow, merged to main 2022-06-25; branch_9x backport 0e1502c12ba93ce42e608a93ab71314a6d671a13, #981, the same day) [read]. Present since the API was created, not a regression, so there is nothing earlier to bisect; the release pair 9.2.0 (API absent, compile error) / 9.3.0 (fails) brackets it [exec]",
   "introduced_date": "2022-06-25",
   "first_affected_version": "9.3.0 (tagged 2022-07-28; the first release with facet sets) [exec]; 9.2.0 lacks the API [exec]; first 10.x release 10.0.0 [exec]. the hunt's record, the independent reproduction and the hunt's record said 9.4.0; the history stage corrected that (the 9.x backport is an ancestor of the 9.3.0 tag)",
   "affected_versions": "All 30 release tags from 9.3.0 to 10.5.2, 10.6.0 (by reading) and main ea57360912ed; not fixed upstream (main cf398bfb142c, branch_10x and branch_10_6, read 2026-10-26). [exec] The finder repro fails the same 2 of 3 tests (its IndexWriter control passes) on 9.3.0 (-ea and -da), 9.4.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da); the independent reproduction's test fails on 9.4.0, 9.12.3 and 10.5.2 (-ea and -da each) and main; a separate test on 9.4.0, 10.5.2 and main; the intended-behaviour check's variants on 9.12.3, 10.5.2 and main; the security probe on 9.12.3, 10.5.2 and main. [read] The 30 tags come from git tag --contains on both introducing commits, and the decode lines are identical at 9.3.0, 9.12.3, 10.5.2 and main; releases between those executed were checked by tag scan only, and old releases ran on JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-405.html",
   "repro": "repro/LFV-405/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-227",
   "priority": "low",
   "priority_rank": 363,
   "novelty": "new",
   "withheld": false,
   "area": "join / JoinUtil query-time term join (TermsWithScoreCollector.SV and SV.Avg, ScoreMode Min/Avg)",
   "title": "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",
   "summary": "You build JoinUtil.createJoinQuery(\"join\", false, \"ref\", fromQuery, searcher, ScoreMode.Min) where two from-documents share the join value x and fromQuery scores them 0 and 2 (one matches only a FILTER clause), and expect the to-document with ref x to score min(0, 2) = 0, or (0 + 2) / 2 = 1 with ScoreMode.Avg, because the ScoreMode javadoc says 'the min of all child scores' and 'the average of all child scores' and the multi-valued join returns exactly that on the same documents. Instead both modes return 2: the single-valued collector uses an accumulated score of exactly 0 to mean 'this join value has not been seen yet', so after a from-document that scored 0, the next from-document with the same value overwrites the stored minimum (Min) or restarts the sum and count (Avg). Which documents match does not change; only scores and ranking are wrong, and they depend on collection order (scores [0, 2] go wrong, [2, 0] come out right).",
   "impact_class": "silent wrong results",
   "introduced_commit": "36acada76293302d83cab60c086a70f8c17e17e6 (trunk, svn r1343966, 'LUCENE-4043: Added scoring support via score mode for query time joining', JIRA era, migrated as apache/lucene#5115, no pull request; branch_4x backport 3b51274435e, svn r1343982, the same day) for ScoreMode.Avg: it added TermsWithScoreCollector with 'Float.compare(existing, 0.0f) == 0' as the first-occurrence test while the score arrays started zeroed. ScoreMode.Min since 07beb24d93cdc70d6c1f6934faf8387c5cd07ed7 (LUCENE-6389, #7449, 'Added ScoreMode.Min', 2015-04-19; branch_5x backport 87da9f4c64e), which pre-filled the Min slots with +Infinity but kept the 0.0 test in front of the switch [read]. Kept by d96acfdfc09 (#16378, 2026-07-09, float to double on the same two lines). The multi-valued collectors lost the same test as a side effect of the LUCENE-4765 SortedSetDocValues rewrite (f2798476cd1, merged to branch_4x as bb1f4d0c61b, 2013, first released in 4.2.0), which is why the two paths disagree today",
   "introduced_date": "2012-05-29 (ScoreMode.Avg, LUCENE-4043); 2015-04-19 (ScoreMode.Min, LUCENE-6389)",
   "first_affected_version": "4.0.0-ALPHA [exec] for ScoreMode.Avg (first GA release 4.0.0 [exec]); 5.2.0 [exec] for ScoreMode.Min, the first release that has it; the scoring join API does not exist in 3.6.2 or any 3.x release [exec]",
   "affected_versions": "ScoreMode.Avg: every release from 4.0.0-ALPHA to 10.5.2 (the last before 10.6.0) and main ea57360912ed; ScoreMode.Min: every release from 5.2.0 to 10.5.2 and main [exec]; in 4.0.0-ALPHA to 4.1.0 the multi-valued join's Avg was wrong too [exec]; branch_10x and branch_10_6 still have the test at lines 137 and 190 [read], so 10.6.0 (released 2026-10-29) is very likely affected (not executed); not fixed in any release or on main",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-227.html",
   "repro": "repro/LFV-227/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-584",
   "priority": "low",
   "priority_rank": 364,
   "novelty": "new",
   "withheld": false,
   "area": "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)",
   "title": "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",
   "summary": "You give a phrase a token boost, for example \"fast|0.5 car\" through DelimitedBoostTokenFilter, or use weighted synonyms such as 'cat, kitty|0.5', and expect the quoted phrase to keep the boost the way QueryBuilder's other paths do: \"fast|0.5 tiger\" becomes (body:\"fast tiger\")^0.5, and a multi-word weighted synonym gives one boosted phrase per path. But as soon as one word of the phrase has a single-word synonym ('car, automobile'), QueryBuilder builds a MultiPhraseQuery in analyzeMultiPhrase, which never reads BoostAttribute: \"fast|0.5 car\" becomes the unboosted body:\"fast (automobile car)\" (score 0.2615 instead of 0.1308), and the quoted \"cat food\" scores 'kitty food' the same as 'cat food' (0.7130 both), although the unquoted query ranks it lower. The matching documents are unchanged; only scores and ranking are wrong, and there is no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "663611c99c7d48dd31d53ea17644fcecd5e0fad7 '[SOLR-12238] Synonym Queries boost (#357)' (apache/lucene-solr#357; SOLR-12238 and LUCENE-9171 = apache/lucene#10211; branch_8x backport 2752d50dd1dc) [read]. The commit added BoostAttribute handling to analyzeTerm, analyzeBoolean, analyzeMultiBoolean, analyzePhrase (phrase boost = product of the token boosts), analyzeGraphBoolean and createSpanQuery, but not to analyzeMultiPhrase, which dates from LUCENE-5261 (57f38e67d65, 2013) and LUCENE-6401 (3b8ea7b2e78, 2015) and has had no boost-related change since",
   "introduced_date": "2020-02-24",
   "first_affected_version": "8.5.0 [exec] (8.0.0 through 8.4.1 are not affected [exec]: QueryBuilder ignored BoostAttribute on every path then, so nothing was inconsistent; earlier releases [read])",
   "affected_versions": "8.5.0 through 10.6.0 (10.6.0 by reading) and main [exec]. Upstream main a95c754ee00, branch_10_6 and branch_10x [read]. Not affected: 8.0.0 to 8.4.1 [exec]. All runs on JDK 25, not each release's own JDK.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-584.html",
   "repro": "repro/LFV-584/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1148",
   "priority": "low",
   "priority_rank": 365,
   "novelty": "new",
   "withheld": false,
   "area": "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)",
   "title": "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)",
   "summary": "You analyze query text with stop-word removal and a same-position synonym (dogs -> dog) and call createPhraseQuery(field, \"the dogs\"), or type the quoted phrase \"the dogs\" into the classic QueryParser. You expect the SynonymQuery(dogs, dog) that \"dogs\" and \"dogs the\" give, because the remaining terms sit at one position and QueryBuilder generates phrases only 'when terms occur at more than one position'; you get the one-position MultiPhraseQuery field:\"(dogs dog)\", which rewrites to a plain disjunction of the two terms. The same documents match, but BM25 scores them differently (doc 'dogs' rises from 0.2774 to 0.7135 and no longer ties with doc 'dog'), because createFieldQuery adds up position increments, so the hole left by 'the' counts as a second position.",
   "impact_class": "minor",
   "introduced_commit": "a944ab17a712f58e8417639763a0c7267fa11e61 (trunk r1703070), LUCENE-6789 'change IndexSearcher default similarity to BM25' (migrated as apache/lucene#7847; a JIRA patch from before GitHub PRs; author Robert Muir, GitHub rmuir): it added SynonymQuery and made QueryBuilder.analyzeBoolean, the positionCount == 1 branch, return a SynonymQuery instead of a coord-disabled BooleanQuery of SHOULD TermQuerys, while MultiPhraseQuery's one-position rewrite ('optimize one-term case') stayed a plain BooleanQuery of SHOULD TermQuerys, so from then on the leading hole changes the scoring model [read]. The increment sum itself is older and had no visible effect alone: 'positionCount += positionIncrement' came from the classic QueryParser (2ce046a7a6d, 2005-11-08, first released in 1.9), moved into QueryBuilder with LUCENE-5261 (57f38e67d65 on trunk and 3bd5beca408 on branch_4x, 2013-10-09, issue #6325, first released in 4.6.0) and was kept by LUCENE-6401 (3b8ea7b2e78, 2015-04-08) [read].",
   "introduced_date": "2015-09-14 (author and commit date 2015-09-14 22:03:35 +0000; LUCENE-6789 / #7847 opened 2015-09-09, closed 2015-09-14)",
   "first_affected_version": "6.0.0 [exec]",
   "affected_versions": "every release from 6.0.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT). Executed: the independent reproduction's one-test JUnit TestQuotedLeadingStopWordSynonym (shipped as TestQueryBuilderLeadingStopWordSynonym, the same test renamed) fails on main (-ea and -da; the independent reproduction, the adjudication and a separate re-run) and on 10.6.0, 10.5.2, 9.12.3 and 9.1.0 (-da); it cannot compile on 9.0.0 and earlier (test-framework package org.apache.lucene.tests.* from 9.1.0); the finder's test fails on main (-ea and -da), 10.6.0 and 9.12.3 (-da); the core-only history probe fails on 6.0.0, 7.7.3, 8.11.4, 9.12.3, 10.6.0 and main and passes on 5.5.5 (-ea) [exec]. By code identity, all 84 release tags from 6.0.0 to 10.6.0 in the history clone carry the increment sum, the SynonymQuery single-position branch and MultiPhraseQuery's one-position BooleanQuery rewrite; 8.8.2, 8.9.0, 8.10.x and 8.11.0-8.11.3 are not tagged there and are covered by inference between 8.8.1 and the executed 8.11.4 [read]. Not new in 10.6 (10.5.2 fails). Not fixed upstream: the newest commit on QueryBuilder.java is 1518164afa3 (author date 2026-04-01, a refactor), already in 5adff78; upstream main 1c2072f0284 (author date 2026-11-02, 3 commits past 5adff78, none in core) still has the sum at QueryBuilder.java:321, and none of the 21 open PRs updated since 2026-10-31 touches QueryBuilder, MultiPhraseQuery, SynonymQuery, StopFilter, QueryParserBase or SimpleQueryParser [read]. Executed on Linux aarch64 with JDK 25.0.3 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1148.html",
   "repro": "repro/LFV-1148/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-686",
   "priority": "low",
   "priority_rank": 366,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / surround (FieldsQuery field prefixes and ^ weights)",
   "title": "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",
   "summary": "You parse the surround query or(title: lucene^3, body: lucene), whose parser documents 'boosting (via ^)', and expect the title match to count three times, exactly like the same weight on the parenthesised field query or((title: lucene)^3, body: lucene). Instead the weight is kept on the parsed term (toString shows title:lucene^3.0), but FieldsQuery.makeLuceneQueryNoBoost builds its operand with makeLuceneQueryFieldNoBoost, so no BoostQuery is created: the title document scores 0.13076457 instead of 0.39229375, no more than the body-only match, which the weight was meant to outrank. Every weight on the direct operand of a field prefix is dropped (a term, an OR, a distance query, with one field or several); only scores and ranking change, never which documents match.",
   "impact_class": "silent wrong results",
   "introduced_commit": "9d70229506f88d3259ba0d24a824c0dbadc52c8e (trunk, '#34331 - Add Paul Elschot's Surround query language parser', svn r209183, the surround parser's first commit; contribution LUCENE-368 = #1446, no pull request): its FieldsQuery.makeLuceneQueryNoBoost already returns q.makeLuceneQueryFieldNoBoost(fieldNames.get(0), qf) for one field name, and the multi-field branch reaches that line through per-field FieldsQuery copies [read]; not a regression: the bug is as old as the parser",
   "introduced_date": "2005-07-05 (trunk 9d70229506f); first release 1.9 (2006-02-27)",
   "first_affected_version": "1.9 [read]; 1.9.1 [exec] is the first executed release; 1.4.3 and earlier have no surround parser [read]",
   "affected_versions": "every release that has the surround parser, 1.9 to 10.5.2, and main a9779ef3c193 (unreleased 11.0) [exec]; 1.9 [read]. From 5.4.0 on every weight on the direct operand of a field prefix is dropped. In 1.9.1-5.3.2 the defect shows for composite operands and two-field prefixes, while a single-term operand cannot show it, because a weight on a single surround term was lost anyway in those releases (a separate defect, fixed in 5.4.0 by LUCENE-6590 / LUCENE-6783) [exec]. Not fixed upstream: upstream main a95c754ee003 still calls makeLuceneQueryFieldNoBoost (2026-10-27) [read]. Executed on Linux aarch64 with JDK 25 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-686.html",
   "repro": "repro/LFV-686/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-852",
   "priority": "low",
   "priority_rank": 367,
   "novelty": "new",
   "withheld": false,
   "area": "monitor / query decomposition and match scoring (QueryDecomposer DisjunctionMaxQuery split, ScoringMatch/ExplainingMatch resolve)",
   "title": "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",
   "summary": "You register a DisjunctionMaxQuery such as (title:apple | body:apple) with tie-breaker 0 in a Monitor and match a document that has apple in both fields with ScoringMatch or ExplainingMatch, expecting the score the query itself gives that document: the best field's score plus tie times the others, which is what IndexSearcher returns (0.1798013 in an independent test). Instead the Monitor reports the sum of both field scores (0.3105659), because the default QueryDecomposer splits the DisjunctionMaxQuery into one query per disjunct and the scoring matchers add up the scores of the parts. In the 'albino elephant' example of DisjunctionMaxQuery's own javadoc, this makes the document with 'albino' in both fields tie with the document that matches both words, which the query is designed to rank higher.",
   "impact_class": "silent wrong results",
   "introduced_commit": "251dbe7cea8126cb7ecadc921ba444c63d06c618 on the main line and b8773d13ad8e249a045862249bf476c30a444461 on branch_8x (its files under test are byte-identical), both 'LUCENE-8766: Add monitor subproject' by romseygeek (JIRA LUCENE-8766, now GitHub #9811; PR apache/lucene-solr#648, closed without a GitHub merge, code committed directly) [read]. Not a regression: present since the module's first release. Origin outside Lucene [read]: the predecessor library Luwak already split DisjunctionMaxQuery (Luwak PR #112, 2016) but resolved matches of one query id by keeping the larger score; the import changed resolve to a sum, which made Boolean disjunctions right and DisjunctionMaxQuery with tie < 1 over-scored",
   "introduced_date": "2019-06-13 (251dbe7cea8 and b8773d13ad8, author date 2019-06-13T09:40:57+01:00); the Luwak DisjunctionMaxQuery split (Luwak PR #112) dates from 2016-12",
   "first_affected_version": "8.2.0 [exec] (first release with lucene-monitor; 8.1.1, the release before, has no lucene-monitor artifact on Maven Central (HTTP 404) and the repro does not compile against its core, so no earlier release is unaffected: the API did not exist)",
   "affected_versions": "every release that ships lucene-monitor: 8.2.0 to 8.11.4, 9.0.0 to 9.12.3, 10.0.0 to 10.5.2, plus the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193. [exec] the finder's JUnit fails 2 of 4 with identical values (tie 0: 0.26152915 instead of 0.13076457; tie 0.1: 0.26152915 instead of 0.14384103) on 8.2.0 (-ea and -da), 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da), branch_10_6 4ae946e5a9b (monitor jar compiled from the branch sources, the other jars from the hunt cache) and main (-ea and -da); the independent reproduction's JUnit fails 5 of 10 on main, 10.5.2 and 9.12.3 (-ea and -da); a separate test fails on main (-ea and -da) and 10.5.2; the intended-behaviour check ran the finder JUnit on main (-ea and -da), 10.5.2 and 9.12.3. [read] the other releases: a per-tag grep on every 8.2.0-8.8.1, 9.x and 10.x tag in the history clone finds the sum, 'sum of:' and the split in each, and QueryDecomposer never reads the tie-breaker (8.9.0-8.11.4 tags are not in the clone; 8.11.4 was executed). Not fixed: on upstream main 20ced71c1e6 the five files have the same blobs as a9779ef3c193, branch_10_6 and branch_10x differ only in cast style, and no open PR changes the split or resolve (2026-10-28).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-852.html",
   "repro": "repro/LFV-852/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-687",
   "priority": "low",
   "priority_rank": 368,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / surround (QueryParser.jj QUOTED token and SimpleTerm production, SrndTermQuery)",
   "title": "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",
   "summary": "You parse a surround query with a quoted term that escapes a double quote or a backslash, such as \"a\\\"b\" or \"c:\\\\temp dir\", and run it on a field that holds the untokenized value a\"b or c:\\temp dir. You expect a match, because the grammar comment on the QUOTED token says 'escape quoted quote or backslash by backslash' and the lexer accepts a backslash inside quotes only as such an escape. Instead the parser strips only the outer quotes, so SrndTermQuery searches for a\\\"b and c:\\\\temp dir with the backslashes kept: 0 hits, or a silent match on a different document that holds that escaped text, and no surround syntax matches those terms exactly.",
   "impact_class": "silent wrong results",
   "introduced_commit": "9d70229506f88d3259ba0d24a824c0dbadc52c8e (SVN r209183, the original contribution of the surround parser, ASF Bugzilla #34331 = LUCENE-368 = GitHub issue #1446; no pull request) [read] [exec]; the 2004 pre-contribution archive attached to LUCENE-368 already has the same rule and action",
   "introduced_date": "2005-07-05",
   "first_affected_version": "1.9 (2006-02-27; also 1.9-rc1 of 2006-02-21) [read]; 1.9.1, the first surround artifact on Maven Central, [exec]; there is no unaffected release: 1.4.3 and earlier have no surround parser",
   "affected_versions": "every release that ships the surround parser, 1.9 to 10.5.2, and main a9779ef3c193 [exec] [read]; not fixed upstream: upstream main a95c754ee003 (2026-10-26) has the same code [read]; branch_10_6 and branch_10x were not read in the hunt; the bug doc's read of 2026-10-28 finds the same token and action on branch_10_6 2763db11b0a7 (contained in 10.6.0, released 2026-10-29) and on branch_10x, so 10.6.0 is affected too [read]; a regression window does not exist (the code is unchanged since the contribution); executed on Linux aarch64 with JDK 25 only",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-687.html",
   "repro": "repro/LFV-687/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-747",
   "priority": "low",
   "priority_rank": 369,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / flexible StandardQueryParser interval functions (StandardSyntaxParser.jj IntervalText and IntervalFuzzyTerm, intervalfn AnalyzedText and FuzzyTerm)",
   "title": "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",
   "summary": "You parse fn:or(a\\:b) (or fn:ordered(a\\:b c), fn:fuzzyTerm(a\\:b 0), fn:or(\"a\\\"b\")) with StandardQueryParser and expect it to find the documents that hold a:b (or a\"b), because the parser's javadoc says 'any character can be quoted with a backslash' and the same escaped literal outside fn: is parsed as the term a:b. Instead the IntervalText and IntervalFuzzyTerm grammar productions pass the raw token text, backslashes included, to AnalyzedText and FuzzyTerm, so the interval query searches for the text a\\:b. With WhitespaceAnalyzer it misses the a:b document and matches a document that holds a\\:b; with StandardAnalyzer it becomes BLOCK(a,b) and matches 'a b c'; no error is raised.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f725b27e12a992f12aab12a8e8bfb9b31125bdae (main, 2021-11-11, by dweiss): 'LUCENE-10223: interval support in standard syntax parser (#429)' (issue LUCENE-10223 = GitHub #11259, PR apache/lucene#429), which added the fn: syntax with the IntervalText production; and f6cebac3337926ca871b922241976a4ba4799c70 (main, 2022-02-10, by dweiss): 'LUCENE-10414: Add fn:fuzzyTerm interval function to flexible query parser (#668)' (GitHub #11450, PR #668), whose IntervalFuzzyTerm production handles the term the same way; the branch_9x backports ff9ee28c603 and 9a293da5967 are the commits that shipped in 9.1.0 [read]. Not a regression: both productions passed the raw token image on without discardEscapeChar from their first version, and the block is token-identical at every release tag checked and on main.",
   "introduced_date": "2021-11-11 (IntervalText, main and branch_9x); 2022-02-10 (IntervalFuzzyTerm, main and branch_9x)",
   "first_affected_version": "9.1.0 (tagged 2022-03-21) [exec]; 9.0.0, the last release before, has no fn: interval syntax at all (fn:or(a\\:b) parses as a BooleanQuery there) [exec], so there is no unaffected release that has the feature",
   "affected_versions": "every release with the fn: interval syntax, 9.1.0 through 9.12.3 and 10.0.0 through 10.5.2 (the last release before 10.6.0), and main a9779ef3c193 (unreleased 11.0); never fixed. [exec] a portable main() repro reports the bug on 20 releases (9.1.0, 9.2.0, 9.3.0, 9.4.2, 9.5.0, 9.6.0, 9.7.0, 9.8.0, 9.9.2, 9.10.0, 9.11.1, 9.12.0, 9.12.3, 10.0.0, 10.1.0, 10.2.2, 10.3.2, 10.4.0, 10.5.0, 10.5.2) and on main (-ea and -da) with identical output, and reports the bug absent on main with the fix shadowed in; the finder's JUnit fails 4 of 4 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the independent reproduction's own test fails 5 of 6 on 9.1.0, 9.12.3, 10.5.2 (-ea and -da) and main (-ea and -da) with byte-identical messages. [read] the 12 releases not run (9.4.0, 9.4.1, 9.9.0, 9.9.1, 9.11.0, 9.12.1, 9.12.2, 10.2.0, 10.2.1, 10.3.0, 10.3.1, 10.5.1) have token-identical IntervalFuzzyTerm and IntervalText productions; upstream main f7bcc0abd816 (2026-10-27) and branch_10x have them unchanged. Not affected: 9.0.0 and earlier (no fn: syntax). All runs with JDK 25 on aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-747.html",
   "repro": "repro/LFV-747/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-714",
   "priority": "low",
   "priority_rank": 370,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / complexPhrase: ComplexPhraseQueryParser (ComplexPhraseQuery.parsePhraseElements second-pass parse, read by ComplexPhraseQuery.rewrite)",
   "title": "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",
   "summary": "You parse \"(john OR jonathan)\" or \"(jo* -john)\" with ComplexPhraseQueryParser and search; inside a complex phrase a bracketed group is one position with alternatives (class javadoc example \"(john jon jonathan~) peters*\", upstream tests \"(john OR johathon) smith\" and \"(jo* -john) smith\") and one-element phrases are supported, so you expect the documents that contain john or jonathan, or a jo* term other than john. Instead the classic grammar drops parentheses around the whole input (QueryParser.jj:289-293 and :311), so the second pass gets the same BooleanQuery as for \"john OR jonathan\", and ComplexPhraseQuery.rewrite makes each member a consecutive position: \"(john OR jonathan)\" becomes spanNear([john, jonathan], 0, true) and matches only documents that contain the sequence 'john jonathan', and \"(jo* -john)\" becomes spanNot(spanOr(jo*), spanNear([spanOr(jo*), john])) and also matches 'john smith', whose only jo* term is john.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f7fa57997191026f3bef51cb3c13edd031b5d781 (LUCENE-1486 = apache/lucene#2560 'Wildcards, ORs etc inside Phrase queries', svn r791579 'Initial commit of LUCENE-1486'; Subversion era, no pull request; author Mark Harwood (@markharwood), CHANGES.txt 2.9 credits 'Mark Harwood via Mark Miller'): the class's first commit already passed the raw phrase text to QueryParser.parse in parsePhraseElements and made every top-level clause of the result one SpanNearQuery position in rewrite (with a MUST_NOT clause, SpanNotQuery(positives, SpanNearQuery(all clauses))); the classic parser's unwrapping of a lone clause predates it (ae45d392f8d, 2002-01-17, 'don't wrap queries with BooleanQuery in query parser unless necessary'). Not a regression [read]",
   "introduced_date": "2009-07-06 (f7fa5799719); moved from core to contrib/misc by 5aaf5b01672 on 2009-08-03, before the 2.9.0 release",
   "first_affected_version": "2.9.0 [exec] (the first release with ComplexPhraseQueryParser); 2.4.1 has no such API [exec]",
   "affected_versions": "Every release that has ComplexPhraseQueryParser, 2.9.0 through 10.5.2, and main a9779ef3c193 (unreleased 11.0) [exec]; the releases between executed ones are affected by reading (blame shows the code path unchanged). Not fixed: upstream main a95c754ee003 (2026-10-26) changes neither ComplexPhraseQueryParser.java nor QueryParser.jj, and no open PR touches complexPhrase/ or QueryParser.jj [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-714.html",
   "repro": "repro/LFV-714/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-479",
   "priority": "low",
   "priority_rank": 371,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / FST completion suggester (FSTCompletionLookup.build weight bucketing)",
   "title": "FSTCompletionLookup sorts weights as unsigned bytes, so negative weights get the highest buckets and are suggested before positive ones",
   "summary": "You build an FSTCompletionLookup from two suggestions, apple with weight 10 and apricot with weight -10, and ask lookup(\"ap\", true, 2) for the best completions first. You expect apple first, because the class javadoc says buckets come from 'sorting the input by weight', InputIterator says 'higher numbers mean better suggestions', and encodeWeight accepts every int. Instead you get [apricot/5, apple/0], with no error: build() sorts the weights by their unsigned big-endian bytes, where every negative int (first byte 0x80 or above) comes after every non-negative int, so all negative weights land in the highest buckets and are suggested first.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f303bcd4650ac96d88b84dade253fbf4cb407158 (trunk, SVN r1296268, 2012-03-02) and its branch_3x backport 71bd966a92e6abe6aefa929d07194ab1ce95ca0e (SVN r1297946, 2012-03-07; the backport shipped first, in 3.6.0), LUCENE-3807 'Cleanup Suggest / Lookup API' (now GitHub issue #4880; an SVN commit, no pull request): build() changed output.writeInt(FloatMagic.toSortable(weight)) to output.writeInt(encodeWeight(weight)) with encodeWeight = (int) value over the whole int range, and deleted FloatMagic, whose mapping (negatives to ~v, non-negatives to v ^ 0x80000000) had made unsigned byte order equal numeric order [read] [exec]. Later rewrites of the same line (b84e0c272b6 LUCENE-9047, 0e1f9fcf31b LUCENE-10193, both 9.0.0) keep the same bytes. FSTCompletionLookup itself came with SOLR-2888 (92de7e88486, 2011-12-01), which ordered negative weights correctly but was never released",
   "introduced_date": "2012-03-02 (trunk); 2012-03-07 (branch_3x backport)",
   "first_affected_version": "3.6.0 [exec], the first release that contains FSTCompletionLookup at all. No earlier release has the class (3.5.0: compile error [exec]); the released predecessor FSTLookup (3.5.0, deprecated in 3.6.x, removed in 4.0) orders negative weights correctly [exec]",
   "affected_versions": "every release that ships FSTCompletionLookup: 3.6.0-3.6.2 and 4.0.0-alpha through 10.6.0 (including 8.8.2-8.11.4 from branch_8x; 10.6.0 by reading), plus main ea57360912ed; never fixed. Executed (all fail, controls pass): 3.6.0, 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main (-ea and -da on main) [exec]; the other releases by code reading [read]. Upstream main f4cc6ac2097 (2026-10-26): the commits since ea57360912ed do not touch lucene/suggest, and no branch (main, branch_10x, branch_10_6, branch_9x) has changed the weight encoding since 2021 [read]. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-479.html",
   "repro": "repro/LFV-479/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-689",
   "priority": "low",
   "priority_rank": 372,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / document (NRT) suggester (FuzzyCompletionQuery: FuzzyCompletionWeight.setNextMatch prefix-similarity boost in unicodeAware mode, also inside ContextQuery)",
   "title": "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",
   "summary": "You build a FuzzyCompletionQuery with unicodeAware=true, the documented option that measures the query 'in Unicode code points (actual letters) instead of bytes', and expect a suggestion that shares more leading letters with the typed prefix to get a larger boost, exactly as for ASCII text. Instead FuzzyCompletionWeight.setNextMatch compares the query's code points with the UTF-8 byte labels of the matched suggestion, so the count stops at the first non-ASCII letter: for the query 'aéc' over aécd (weight 3) and the typo axcd (weight 4) both get boost 1 and the exact prefix ranks second, [axcd/4.0, aécd/3.0], while the same data in ASCII ('abc' over abcd and axcd) gives [abcd/6.0, axcd/4.0]; for an all-CJK or all-Cyrillic query every suggestion gets boost 0, so the exact prefix only ties with typos and the weight alone decides. Only scores and ranking are wrong (the suggestions found are right), for the plain query and inside a ContextQuery.",
   "impact_class": "silent wrong results",
   "introduced_commit": "be4d58c7740bea4e797eb1acff6355eb260e7c93 (trunk, LUCENE-6459 '[suggest] Query Interface for suggest API', now apache/lucene#7518; patch by @areek, committed by @mikemccand; svn era, no pull request), branch_5x backport 380bb29f39595de1c3947075296d1d0a36f02fd8 the same day: the commit that created FuzzyCompletionQuery already kept the boost references as code-point strings from stream.toAutomaton(unicodeAware), converted only the match automaton with UTF32ToUTF8, and had NRTSuggester pass the FST byte-label path to setNextMatch [read]; not a regression: the bug is as old as the class",
   "introduced_date": "2015-05-28 (trunk be4d58c7740 07:53Z; branch_5x backport 380bb29f395 08:31Z)",
   "first_affected_version": "5.3.0 [exec]; 5.2.1 and older have no FuzzyCompletionQuery or CompletionQuery, so the probe does not compile [exec].",
   "affected_versions": "every release from 5.3.0 through 10.5.2 and main a9779ef3c193 (unreleased 11.0) [exec]; the releases in between [read]. Not fixed upstream: no commit under lucene/suggest/document since 2026-09-01 on upstream main a95c754ee003 and no open PR touches FuzzyCompletionQuery.java (2026-10-27) [read]. Executed on Linux aarch64 with JDK 25 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-689.html",
   "repro": "repro/LFV-689/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-706",
   "priority": "low",
   "priority_rank": 373,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / FST completion suggester (FSTCompletionLookup build/load exactMatchFirst wiring)",
   "title": "FSTCompletionLookup ignores exactMatchFirst=false for by-weight lookups after build() and load(), so an exact match is always ranked first",
   "summary": "You build an FSTCompletionLookup(dir, \"fst\", 10, false) from star (weight 1), star wars (100) and start (50) and ask lookup(\"star\", true, 3) for the most popular completions first. You expect [star wars/6, start/3, star/0], because the constructor javadoc says that with exactMatchFirst=false exact matches 'appear in the order of discretized weight and alphabetical within the bucket'. Instead you get [star/0, star wars/6, start/3], with no error, after build() and equally after store() and load(): both paths create the internal by-weight FSTCompletion with its exact-first default, and the flag reaches only the alphabetical completion, where it changes nothing.",
   "impact_class": "silent wrong results",
   "introduced_commit": "92de7e884868f91b42689aa344c51b1b8aa8fdbb (trunk, svn r1209265, 2011-12-01) and its branch_3x backport d3e380f824a59857c3cd72e7f789e6f5682e7853 (svn r1232289, 2012-01-17; the backport shipped first, in 3.6.0), SOLR-2888 'FSTSuggester refactoring: utf8 storage, external sorts (OOM prevention), code cleanups' (an svn-era JIRA change, no pull request; its 21 comments never mention exact-match handling). The commit created FSTCompletionLookup with build() keeping higherWeightsCompletion = builder.build() and load() using the one-argument new FSTCompletion(fst), both exact-first by default, while only normalCompletion received exactMatchFirst; the pre-built-completion constructor of the same commit passes the flag to both [read] [exec]. The exactMatchFirst=false javadoc followed three days later in 3408defc8db (2011-12-04, 'JavaDoc clarifications'), so no release has the code without the contract",
   "introduced_date": "2011-12-01 (trunk); 2012-01-17 (branch_3x backport)",
   "first_affected_version": "3.6.0 [exec], the first release that contains FSTCompletionLookup at all (3.5.0: class absent, compile error [exec]); the class it replaced, FSTLookup (deprecated in 3.6, removed in 4.0), honours exactMatchFirst=false on the same input [exec], so this is a regression of the refactoring, and no release of FSTCompletionLookup ever honoured the flag on this path",
   "affected_versions": "every release that ships FSTCompletionLookup: 3.6.0-3.6.2 and 4.0.0-alpha through 10.5.2 (135 releases, including 8.8.2-8.11.4 from branch_8x), plus main a9779ef3c193; never fixed. Executed, all failing with the control passing: 3.6.0, 3.6.1, 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.0.0, 6.6.6, 7.7.3, 8.8.2, 8.9.0, 8.10.0, 8.10.1, 8.11.0-8.11.4, 9.0.0, 9.12.3, 10.0.0 and 10.5.2 (follow-up main() repros, 10.5.2 also -da), 9.1.0 (the intended-behaviour check, before the 9.2 stream rewrite of FSTCompletion), main with -ea and -da [exec]; the other releases by reading every release tag of the history clone [read]. FSTCompletionLookup.java is byte-identical on upstream origin/main a95c754ee003, branch_10x and branch_10_6 (fetched 2026-10-26) [read], so 10.6.0 (released 2026-10-29 from branch_10_6) is affected too. Executed only on aarch64 Linux with JDK 25.0.3; the defect is pure-Java wiring, so the platform does not matter",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-706.html",
   "repro": "repro/LFV-706/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-649",
   "priority": "low",
   "priority_rank": 374,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / minhash (MinHashFilter.FixedSizeTreeSet bottom-k set; MinHashFilterFactory 'minHash')",
   "title": "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)",
   "summary": "You analyse 'b a a' with MinHashFilter(hashCount 1, bucketCount 1, hashSetSize 2) and expect the same two min hashes as for 'b a', because the filter keeps 'the N lowest values' of the tokens' hashes (MinHashFilter.java:38-40; hashSetSize is 'the no. of min hashes to keep') and the lowest values of a token set do not change when a token repeats. Instead, FixedSizeTreeSet.add removes the full set's largest value (pollLast) before TreeSet.add finds that the repeated value is already there, so 'b a a' gives one value; a later new token, however large its hash, then fills the free slot ('c a c b' keeps the hashes of c and b, not the true lowest two, c and a), and the same tokens in another order ('c a b c') give yet another signature. In the javadoc's '1 hash and keep the 100 lowest values' setting with 5-word shingles, a 150-word text read twice has the same shingle set as the text read once but a signature of 99 values that misses one of the 100 lowest.",
   "impact_class": "silent wrong results",
   "introduced_commit": "82a9244193ba948142b834ec08e2de0d98cfba9f (LUCENE-6968 'MinHash filter, thanks to Andy Hind and Cao Manh Dat for patches', committed by GitHub tteofili; JIRA patch workflow, no pull request; the issue is now apache/lucene#8025 'LSH Filter'), backported to branch_6x as 96a5595fffd4a4a1c553a987382697cb8a92b354, which shipped in 6.2.0 [read]. Which of the credited patch authors wrote FixedSizeTreeSet cannot be told from the commit.",
   "introduced_date": "2016-06-14 (main line; branch_6x backport committed 2016-06-24)",
   "first_affected_version": "6.2.0 [exec] (the first release with org.apache.lucene.analysis.minhash; on 6.1.0 the repro does not compile because the package does not exist [exec]). In 6.2.0 hashSetSize is reachable through the factory only; the public constructor came with LUCENE-7436 in 6.2.1 / 6.3.0 / 7.0.0.",
   "affected_versions": "Every release from 6.2.0 through 10.5.2 (the last release before 10.6.0; the latest 9.x is 9.12.3) and main a9779ef3c193, whenever hashSetSize >= 2. [exec] the follow-up's version-independent main() probe (factory API, 1 hash, 1 bucket, hashSetSize 2: 'b a' gives 2 values, 'b a a' gives 1) fails with byte-identical output on 6.2.0, 6.6.6, 7.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main, and the finder's run on 7.7.3; the finder's JUnit fails 3/3 on main -ea/-da, 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 6/6 on main, 10.5.2 and 9.12.3, each with -ea and -da; the intended-behaviour check's probe and the cross-model intended review's test fail on 10.5.2 as on main. [read] the FixedSizeTreeSet.add body (after normalising '> -1' to '>= 0'), LongPair.compareTo and the insert line are identical in all 80 release tags 6.2.0..10.5.2 of the release-tag clone (8.8.2..8.11.4 are not in that clone; 8.11.4 was executed), and upstream main head a95c754ee003 has the same add() (2026-10-26). Not affected: hashSetSize = 1 (the default; 0 mismatches in every exhaustive check) and releases before 6.2.0 (no API).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-649.html",
   "repro": "repro/LFV-649/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-867",
   "priority": "low",
   "priority_rank": 375,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / synonym.word2vec (Word2VecModel.addTermAndVector term-to-vector mapping; Dl4jModelReader; Word2VecSynonymProvider and Word2VecSynonymFilter as consumers)",
   "title": "Word2VecModel: a term added twice silently shifts the vector of every later term, so Word2VecSynonymFilter returns synonyms computed from other terms' vectors",
   "summary": "You build a Word2VecModel in which one term appears twice, through the public addTermAndVector or by loading a Deeplearning4j-format zip with Dl4jModelReader or Word2VecSynonymFilterFactory, and you expect every term to keep its own vector, as the class javadoc ('containing the vectors for each word in dictionary') and the upstream test of vectorValue(term) say. addTermAndVector stores each entry at the next array slot but ignores that BytesRefHash.add gives no new id to a term it already holds, while vectorValue(term) looks the vector up by that id, so after the first repeat every later distinct term reads the slot of the term before it. For the model [a(1,0), a(1,0), b(0,1), c(-1,0)] vectorValue(b) returns a's vector and vectorValue(c) returns b's, and with the model [car, car, auto, banana, fruit] and the factory defaults 'banana' is expanded with the neighbours of 'auto' ([auto, car, car]) instead of [fruit], with no error or warning.",
   "impact_class": "silent wrong results",
   "introduced_commit": "1f4f2bf50957ad1a13c32d5351c7de77154953f1 on main (apache/lucene#12169 'Introduced the Word2VecSynonymFilter', feature issue #12168; author dantuzi, co-author Alessandro Benedetti; squash-merged 2023-04-24; first in 10.0.0) and its branch_9x re-apply 64b48b89b501 (committed 2023-05-30, author date 2023-04-24; first in 9.7.0; an earlier cherry-pick 53709ccaecc was reverted by 7e15a390688 on 2023-04-25, before 9.6.0). Inside the PR the defect arrived with PR commit bf712b90215 (author date 2023-04-05), which replaced the first revision's HashMap<BytesRef,TermAndVector> put/get (2abb1ea6de1, correct per term) with BytesRefHash ids used as array slots while ignoring the return value of add() [read]",
   "introduced_date": "2023-04-24 (main 1f4f2bf5095); 2023-05-30 (branch_9x re-apply 64b48b89b50, author date 2023-04-24); PR-internal change bf712b90215 authored 2023-04-05",
   "first_affected_version": "9.7.0 [exec] (the first release with the word2vec package; 9.6.0 has no word2vec classes and the repro does not compile there [exec], although CHANGES.txt lists GITHUB#12169 under 9.6.0); first on the main line: 10.0.0 [exec]",
   "affected_versions": "Every release that has the API: 9.7.0 to 9.12.3 and 10.0.0 to 10.5.2 [exec], the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) [exec], branch_10x 1309534296e3 [read] and main a9779ef3c193 [exec]. Not fixed upstream: the last commit on Word2VecModel.java on upstream main is 6053e1e3137 (#13779, 2024-09-28, no logic change) [read]. All runs on aarch64 Linux with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-867.html",
   "repro": "repro/LFV-867/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-504",
   "priority": "low",
   "priority_rank": 376,
   "novelty": "new",
   "withheld": false,
   "area": "misc / store: DirectIODirectory (DirectIOIndexInput.fill and seek)",
   "title": "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)",
   "summary": "You read a file through the misc DirectIODirectory, one read on an input throws (an EOFException because it asked for more bytes than are left, or an IOException from a transient storage error), and you then seek back to a legal position, or simply read again, on the same input. You expect the bytes at the file pointer, or another exception (after the same read-past-EOF sequences MMapDirectory returns the right bytes). Instead fill() had already moved its window position (filePos) to the next block, and on the read path cleared the buffer, before it threw, so the next reads silently return bytes of a different position of the same file (or throw EOFException at a legal position) while getFilePointer() reports the requested one.",
   "impact_class": "silent wrong results",
   "introduced_commit": "a7747b63b4ac649837469ee189b8aef10e4ce867 on main (then 'master'), 'LUCENE-8982: Make NativeUnixDirectory pure java with FileChannel direct IO flag, and rename to DirectIODirectory (#2052)', 2021-01-17. It added DirectIOIndexInput with refill() (renamed fill() by #16619 in 2026) doing 'filePos += buffer.capacity()' before the EOF check and 'buffer.clear()' before 'channel.read(buffer, filePos)'; git blame at 7cecf795236 (same file as ea57360912ed) still attributes those lines to this commit. From this commit a failed channel read leaves the previous window's bytes under the next window's address (trigger [A], executed: fails at a7747b63b4a). The EOF-check form named by the key became observable 16 days later with 3835cb4e95ce6ba93ab5e3d5caa35001c90db30a ('LUCENE-9686: Fix read past EOF handling in DirectIODirectory (#2258)', 2021-02-02), which added the clause 'channel.size() - filePos < bytesToRead': that clause throws on a first fill after filePos was already moved to 0, so seek(0) becomes a no-op and the next read returns the next window (triggers [B] and [C], executed: pass at a7747b63b4a, fail at 3835cb4e95c). Both commits are in 9.0.0, the first release of the class. 10.2.0 widened the bug: #14103 (main 1cd77c2ca2a, branch_10x bd12e07b114, 2025-01-25) replaced channel.size() in the EOF check by the cached length, so a closed channel no longer throws before buffer.clear() (triggers [E] clone-after-close and [F] interrupt, executed: pass before, fail at bd12e07b114); #14320 (main f8fac44b321, branch_10x 212924e5000, 2025-03-03) added seek()'s in-buffer shortcut, which serves the stale window after a read past EOF (triggers [D] and [D-slice], executed: pass at bd12e07b114, fail at 212924e5000 = the 10.2.0 file). PRs: apache/lucene-solr#2052 (LUCENE-8982; author zacharymorn, merged by uschindler 2021-01-17, base master) introduced the class and the ordering. apache/lucene-solr#2258 (LUCENE-9686; author zacharymorn, merged by dweiss 2021-02-02, base master) added the bytesToRead EOF clause that exposes the EOF variant. Widened in 10.2.0 by apache/lucene#14103 (author and merger ChrisHegarty, 2025-01-25) and apache/lucene#14320 (author and merger ChrisHegarty, 2025-03-03). apache/lucene#16619 (author john-mlika, merged by thecoop 2026-09-03, main only) renamed refill to fill and kept the ordering.",
   "introduced_date": "2021-01-17 (LUCENE-8982, read-failure trigger); 2021-02-02 (LUCENE-9686, EOF triggers [B]/[C]); 2025-01-25 and 2025-03-03 (#14103 and #14320, triggers [E]/[F] and [D], first released in 10.2.0)",
   "first_affected_version": "9.0.0 [exec], the first release that has DirectIODirectory: triggers [A] (transient read error), [B] (oversized first read, then seek(0)) and [C] (spurious EOFException on a 1-byte file) fail. Triggers [D]/[D-slice] (legal seek after a read past EOF) and [E]/[F] (closed channel) first fail in 10.2.0 [exec]. The API does not exist before 9.0.0: 8.11.0 and 8.11.4 fail to compile the repro only because DirectIODirectory is missing [exec].",
   "affected_versions": "Every release from 9.0.0 to 10.6.0 (10.6.0 [exec] on the RC1 snapshot jars). 9.0.0 to 10.1.x: triggers [A] [B] [C] [exec]. 10.2.0 to 10.5.2: all seven triggers [exec]. 10.6.0 (released 2026-10-29; branch_10_6 RC1 4ae946e5a9b) and the unreleased branch_10x at 657014b3c57 have the same fill and seek code [read]; #16883 (branch_10x 1309534296e, branch_10_6 2763db11b0a, main ea57360912e) had merges re-open vector and stored-field data with the reader's own sequential context, so the stock policy stopped using direct I/O for them; #16905 (branch_10x 657014b3c57, branch_10_6 940768fb0cd, main 49483e82b35) opens them with IOContext.merge() again. main from a7747b63b4a to 645d4fe14a2 [exec]. Not affected: 8.x and earlier (no DirectIODirectory).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-504.html",
   "repro": "repro/LFV-504/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-646",
   "priority": "low",
   "priority_rank": 377,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / analyzing infix suggester (AnalyzingInfixSuggester.build() failure path; inherited unchanged by BlendedInfixSuggester)",
   "title": "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)",
   "summary": "You rebuild an AnalyzingInfixSuggester with default settings, build() throws an IOException, you call refresh() and keep using the instance, and you expect it to serve what its index holds, so that a later add() adds exactly one suggestion. Instead build() has already committed the new index (closeIndexWriterOnBuild defaults to true) before it opens the SearcherManager on it; when that open fails, the catch block rolls back (which cannot undo the commit), sets writer = null and keeps the old SearcherManager, so refresh() is a no-op, lookups serve the old suggestions ([old apple]) while the directory holds the failed build ([new avocado]), and after the next add() lookups return [another apricot, new avocado], with the old suggestion gone. A second trigger needs no I/O fault: build() first closes, and so commits, a writer that holds an add() or update() not yet refreshed, and if the rebuild's input then throws, refresh() never shows that committed change.",
   "impact_class": "silent wrong results",
   "introduced_commit": "5015dc6dbb89a2d3f9c2cd0eb1674f6f146d09b4 on main (first released in 10.0.0) and its branch_9x cherry-pick b11b0714297ab5f8005aa01001824acc6ef488e7 (first released in 9.2.0): LUCENE-10292 (now GitHub issue #11328, 'AnalyzingInfixSuggester thread safety: lookup() fails during (re)build()', by hossman; reviewed as JIRA patches, no GitHub PR). It stopped closing and nulling searcherMgr at the start of build(), so that lookups keep working during a rebuild, and installs the new manager only after the commit (setAndCloseOldSearcherManager, main :361); the failure path (rollback; writer = null) stayed as it was, so a build that throws after its commit now leaves the old manager installed and refresh() inert [read]. Older ingredients: commit() before new SearcherManager in build() (LUCENE-5889, 4a485d68771 on trunk, e4731cf8a36, 5.0.0) and the default commit when closeIndexWriterOnBuild=true plus refresh()'s writer == null no-op (LUCENE-7564, f9a0693bf98 on main, branch_6x 4fedb640ab6, 6.4.0). #15134 (b85f030c6cc, main only) rewrote the success flag as catch (Throwable) without changing behaviour",
   "introduced_date": "2022-04-08 (main 5015dc6dbb8 and the branch_9x cherry-pick b11b0714297)",
   "first_affected_version": "9.2.0 [exec] (10.0.0 on the 10.x line [exec]). 9.1.0 is the last release without the silent form [exec]: a failed build is committed there too with default settings, but the instance is left with no searcher, so refresh() and lookup() throw IllegalStateException 'suggester was not built' (loud). The same loud behaviour on 9.0.0, 8.11.4 and 6.4.0 [exec]; 6.3.0 does not commit inside build() with default settings [exec]",
   "affected_versions": "All 31 releases from 9.2.0 through 9.12.3 and 10.0.0 through 10.5.2, and main a9779ef3c193; not fixed upstream. [exec] The finder's JUnit fails 4 of 4 on main (-ea and -da), 10.5.2, 10.0.0, 9.12.3 and 9.2.0 (-ea and -da); the version probe shows the served-versus-committed split on every one of the 31 releases and on main, and the loud form on 9.1.0, 9.0.0, 8.11.4, 6.4.0 and 6.3.0; the independent reproduction's JUnit fails 6 of 9 (its 3 controls pass) on main (-ea and -da), 10.5.2, 9.12.3 and 9.2.0; the intended-behaviour check's over-long-entry test fails on main (-ea and -da) and 9.2.0; the re-runs on main (fresh seeds) fail the same way. Not affected, loud instead: 9.1.0 and older [exec]. BlendedInfixSuggester inherits build() unchanged [exec]. All runs on aarch64 with JDK 25 (releases before 10.x with API ports of the probe)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-646.html",
   "repro": "repro/LFV-646/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-394",
   "priority": "low",
   "priority_rank": 378,
   "novelty": "new",
   "withheld": false,
   "area": "index / merge policy (LogMergePolicy.findMerges level window; LogDocMergePolicy, LogByteSizeMergePolicy)",
   "title": "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)",
   "summary": "You configure LogDocMergePolicy (or LogByteSizeMergePolicy) with setMergeFactor(Integer.MAX_VALUE), which the setter accepts (it rejects only values below 2, and its javadoc recommends large values for batch indexing), bulk-load one large segment, add one document and commit, and expect the commit to succeed with no merge, as it does with Integer.MAX_VALUE - 1. Instead findMerges computes the end of each merge window as 'int end = start + mergeFactor', which wraps negative for every size level that does not start at segment 0, and its minimum-size packing step then calls levels.get(-2147483648), so commit() throws IndexOutOfBoundsException (OutOfMemoryError 'Requested array size exceeds VM limit' before 10.2.0). Every later commit and flush of new documents fails the same way until the factor is lowered; on main a 20,000,000-document segment followed by a 1-document flush is enough.",
   "impact_class": "crash",
   "introduced_commit": "299d6357dd296f87a099fadd0764292b28dbde47 (SVN r576798, by GitHub mikemccand): 'LUCENE-845, LUCENE-847, LUCENE-870: factor MergePolicy & MergeScheduler out of IndexWriter' (JIRA LUCENE-847 'Factor merge policy out of IndexWriter', GitHub issue #1922, with LUCENE-845 #1920 and LUCENE-870 #1945); SVN era, no PR. It created LogMergePolicy with both wrapping sites ('int end = start + mergeFactor' and 'end = start + mergeFactor', today LogMergePolicy.java:596 and :680) and the '< 2'-only check in setMergeFactor [read] [exec]. Not a regression: later commits changed only the symptom (LUCENE-3084 in 3.2, LUCENE-6892 in 5.4.0, #14166 in 10.2.0) and the reachability (#12113 in 9.6.0)",
   "introduced_date": "2007-09-18",
   "first_affected_version": "2.3.0 [exec] (2.2.0 has no MergePolicy/LogMergePolicy classes; its IndexWriter checks numSegments < mergeFactor before any window arithmetic, and the same probe passes on 2.2.0 [exec])",
   "affected_versions": "every release from 2.3.0 to 10.6.0 (10.6.0 by reading) and main ea57360912ed. [exec]: 2.3.0, 2.3.2, 2.4.1, 2.9.4, 3.0.3, 3.1.0, 3.2.0, 3.6.2, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.5.0, 9.6.0, 9.12.3, 10.1.0, 10.2.0, 10.5.2 and main (-ea and -da); controls pass (2.2.0 with the same probe; Integer.MAX_VALUE - 1 on 2.3.0 and main). [read]: both wrapping sites and the '< 2'-only validation are unchanged in all 141 release tags 2.3.0-10.5.2 of the history clone, and on upstream main, branch_10x and branch_10_6 (2026-10-26). Symptom by era [exec]: 2.3.0-3.1 IllegalArgumentException 'fromIndex(1) > toIndex(-2147483648)'; from 3.2 (LUCENE-3084) RuntimeException 'segments must include at least one segment'; from 5.4.0 (LUCENE-6892) OutOfMemoryError 'Requested array size exceeds VM limit' (writer stays open through 8.11.4, tragic in 9.5.0-10.1.0; the change in between was not bisected); from 10.2.0 (#14166) IndexOutOfBoundsException. Trigger [exec]: up to 9.5.0 any segment at or above the level floor followed by a smaller one (2000 + 1 docs); from 9.6.0 (#12113) a size ratio of about 1e7 (2000 + 1 passes, 20,000,000 + 1 fails). Not executed: 5.0-5.4, 10.0.0, LogByteSizeMergePolicy end to end after 2.x (direct findMerges call only), x86",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-394.html",
   "repro": "repro/LFV-394/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-454",
   "priority": "low",
   "priority_rank": 379,
   "novelty": "new",
   "withheld": false,
   "area": "search / kNN vector queries (per-segment collector sizing: AbstractKnnVectorQuery, TopKnnCollectorManager, TopKnnCollector; join DiversifyingNearestChildrenKnnCollectorManager)",
   "title": "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)",
   "summary": "You run a KnnFloatVectorQuery with a k larger than the index, for example k = Integer.MAX_VALUE to mean 'all vectors', and expect every vector back, as k = 1000 over 3 vectors gives, and as 9.9.2 gives for any k. Instead each segment's collector is built with a heap sized from k (k + 1 longs on a single-segment index) before the segment's vector count is looked at: k = Integer.MAX_VALUE throws IllegalArgumentException('initialCapacity must be > 0 and < 2147483630; got: 2147483647') from TernaryLongHeap, and k = 2^28 over a 3-document index throws OutOfMemoryError with a 2 GiB heap. Lucene used to cap k at the segment's vector count ('bound k by total number of vectors to prevent oversizing data structures'); a search speed-up change dropped that cap in 9.10.0, and the join DiversifyingChildren*KnnVectorQuery never had it.",
   "impact_class": "crash",
   "introduced_commit": "d095ed02a2a7742235e73320fa992eabfeecbecc on main (GITHUB#12962 'Speedup concurrent multi-segment HNWS graph search' by mayya-sharipova, merged 2024-02-06) and its branch_9x backport a6c45ebe4321cacfac27380d41125ed6ae7a8dee (PR #13086, merged 2024-02-07), which first shipped in 9.10.0 [read]: approximateSearch stopped calling LeafReader.searchNearestVectors(field, target, int k, ...), which caps k at the vector count, and instead builds the per-segment collector from k through the new TopKnnCollectorManager; the old cap survives only as the emptiness check 'Math.min(knnCollector.k(), size()) == 0', evaluated after the heap is allocated. Join DiversifyingChildren{Float,Byte}KnnVectorQuery: unbounded since the API was added (#12434, branch_9x 1f25c68cf03, 2023-08-07, first released in 9.8.0) [read]",
   "introduced_date": "2024-02-06 (main, d095ed02a2a); 2024-02-07 (branch_9x backport a6c45ebe432); join path 2023-08-07 (1f25c68cf03)",
   "first_affected_version": "9.10.0 [exec] for the core KnnFloat/KnnByteVectorQuery (tag 2024-02-11, from the branch_9x backport; 9.5.0, 9.8.0 and 9.9.2 pass [exec]; the first main-line release containing d095ed02a2a is 10.0.0); 9.8.0 [exec] for the join DiversifyingChildren*KnnVectorQuery (since the API was added; 9.7.0 has no such class [exec])",
   "affected_versions": "core KnnFloatVectorQuery/KnnByteVectorQuery without a filter (the approximate path): 9.10.0, 9.11.0, 9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2, 10.6.0 (by reading: same collector-manager code as main) and main ea57360912ed [exec]; join DiversifyingChildren{Float,Byte}KnnVectorQuery: 9.8.0 through main [exec]; not affected: core 9.0.0-9.9.2 [exec]; before 9.0.0 there is no kNN query; KnnFloat16VectorQuery (main only, unreleased) has the same approximateSearch shape [read]; a filtered search that routes to exact search is bounded by Math.min(k, cost) from 9.11.0 (#13184); up to 9.10.0 that exact path also failed (HitQueue(k)) [exec], a separate history already fixed; not fixed upstream (no change to the 9 affected files on upstream main 49483e82b357, 2026-10-26, and no open PR bounds k) [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-454.html",
   "repro": "repro/LFV-454/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-997",
   "priority": "low",
   "priority_rank": 380,
   "novelty": "new",
   "withheld": false,
   "area": "search / rescoring (SortRescorer; expressions ExpressionRescorer inherits rescore())",
   "title": "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",
   "summary": "You run a first-pass search that returns 5 hits and re-sort them with new SortRescorer(sort).rescore(searcher, firstPass, Integer.MAX_VALUE), meaning 're-sort all of them'; you expect the 5 hits back in sort order, as topN = 5 or 10 give and as QueryRescorer and DoubleValuesSourceRescorer give for any topN. Instead the call throws OutOfMemoryError 'Requested array size exceeds VM limit' on main (IllegalArgumentException 'maxSize must be >= 0 and < 2147483631' in 10.x and 9.x), because SortRescorer sizes its TopFieldCollector, which pre-allocates its arrays, by topN instead of by the number of hits it was given. Smaller large values succeed but cost memory in proportion to topN (about 120 MB for 4 hits at topN = 10^7), and Expression#getRescorer inherits the same code.",
   "impact_class": "wrong error",
   "introduced_commit": "cbd8cacc50c9 (LUCENE-5545 'add SortRescorer and Expression.getRescorer', migrated as GitHub issue #6608; Michael McCandless; svn r1580490 on trunk, shipped through the branch_4x port 6970ada1746a, r1580491, same day; Subversion-era patch, no PR) [read]",
   "introduced_date": "2014-03-23",
   "first_affected_version": "4.8.0 [exec] (the release that introduced the Rescorer API; 4.7.2 does not have it: the portable check does not compile there [exec])",
   "affected_versions": "every release from 4.8.0 through 10.5.2, 10.6.0 (released 2026-10-29; branch_10_6 head 4ae946e5a9b9) and main a9779ef3c193; executed on 4.8.0, 4.9.1, 4.10.0, 4.10.4, 5.5.5, 6.6.6, 7.4.0, 7.5.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2, branch_10_6 and main (all fail) [exec], the releases in between by reading (every revision of SortRescorer.java passes topN unchanged) [read]. Only the error at topN = Integer.MAX_VALUE changed over time: IllegalArgumentException 'maxSize must be <= 2147483391' in 4.8.0, NegativeArraySizeException in 4.9.1-7.4.0, IllegalArgumentException 'maxSize must be >= 0 and < 2147483631' in 7.5.0-10.5.2 and 10.6.0 (branch_10_6), OutOfMemoryError 'Requested array size exceeds VM limit' on main only (#14873, unreleased); a heap OutOfMemoryError at MAX_ARRAY_LENGTH - 1 (-Xmx1g) and about 120 MB per call at topN = 10^7 in every executed version [exec]. Not fixed upstream: SortRescorer.java:48-49 unchanged on upstream main (checked 2026-10-29, newest commit on the file e5eb7e763ac, author date 2025-06-30) and on branch_11x, branch_10x and branch_10_6 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-997.html",
   "repro": "repro/LFV-997/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-442",
   "priority": "low",
   "priority_rank": 381,
   "novelty": "new",
   "withheld": false,
   "area": "index / TieredMergePolicy merge selection (doFindMerges candidate loop; setMaxMergedSegmentMB validation)",
   "title": "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",
   "summary": "You configure the default TieredMergePolicy with setMaxMergedSegmentMB(0), which the setter accepts (it rejects only negative values, with the message 'must be >=0'), delete some documents, and expect commit(), close() and forceMergeDeletes() to succeed, either with no merge or with the singleton merge the class javadoc promises for segments over the maximum ('down to 1 at once, if that one has deletions'), as they do with a 1-byte maximum and as they did on 7.4.0. Instead the candidate loop in doFindMerges requires 'bytesThisMerge < maxMergedSegmentBytes', which is 0 < 0 before the first segment is added, so no segment is ever admitted and the candidate list stays empty. 'assert candidate.size() > 0' then fails with -ea, and candidate.get(0) throws IndexOutOfBoundsException ('Index 0 out of bounds for length 0') with -da, out of the writer call.",
   "impact_class": "crash",
   "introduced_commit": "2519025fdafe55494448854c87e094b14f434b41 on master and its branch_7x cherry-pick 9c4e315c1cb3495f400c179159836f568cd2989d (the copy that shipped in 7.5.0), 'LUCENE-7976: Make TieredMergePolicy respect maxSegmentSizeMB and allow singleton merges of very large segments' (JIRA LUCENE-7976, now GitHub issue #9025; patches on the issue, no pull request). It moved findMerges and findForcedDeletesMerges onto one shared doFindMerges and added '&& bytesThisMerge < maxMergedSegmentBytes' to its candidate loop header [read]. The commit()/close() path in the repro's form fails from LUCENE-8263 (8093c450c1fd22e2bfd5b2a4a1e45c6f95f16189 on master, 8875402694b42791e18da2d3cf44a4353c676e26 on branch_7x, 2018-07-17, #9310), which lets segments with more than deletesPctAllowed deletes reach the loop [exec]; both first shipped in 7.5.0.",
   "introduced_date": "2018-06-15 (LUCENE-7976); widened 2018-07-17 (LUCENE-8263)",
   "first_affected_version": "7.5.0 [exec] (both trigger paths); 7.4.0 is not affected [exec]",
   "affected_versions": "every release from 7.5.0: 7.5.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2, 10.6.0 (by reading), and main ea57360912ed [exec] [read]; unchanged on upstream main c50bc9523db3, branch_10x and branch_10_6 (the prior-report record). With -da the exception comes from score() in 7.5.0-9.0.0 and from doFindMerges' candidate.get(0) from 9.3.0 on (LUCENE-10574 moved the first use); the outcome is the same.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-442.html",
   "repro": "repro/LFV-442/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-908",
   "priority": "low",
   "priority_rank": 382,
   "novelty": "new",
   "withheld": false,
   "area": "search / CachingCollector first-pass caching (CachingCollector, CachingCollectorManager) x grouping GroupingSearch two-pass caching",
   "title": "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)",
   "summary": "You enable caching for a grouped search (or wrap a first-pass collector in CachingCollector or CachingCollectorManager) with a negative limit, for example setCaching(-1, true) meant as 'no limit', and expect either an IllegalArgumentException or the documented fallback for a cache over its limit: isCached() false and the query re-run. Instead the limit is accepted and nothing is cached (a negative count is the collector's own internal 'purged' marker), but isCached() stays true, so replay() delivers none of the collected documents and GroupingSearch returns its top groups with no documents and totalHitCount 0 instead of 20 in the repro, with no error. From 5.0.0 to 9.7.0 the same input failed at replay with an AssertionError (-ea) or IndexOutOfBoundsException (-da).",
   "impact_class": "silent wrong results",
   "introduced_commit": "85642f59ddf00c469b502f46fbc39944e076190e (trunk, LUCENE-5527 'Make the Collector API work per-segment', GitHub mirror #6590, committed by jpountz, svn r1584747; reached branch_5x through the LUCENE-5944 bulk backport 55594bad9b0) [read]. The symptom turned silent with 8811f31b9ca (main) / de07bdd88dd (branch_9x), apache/lucene#12380 'Add a post-collection hook to LeafCollector' by jpountz, which moved contexts.add(context) under the maxDocsToCache >= 0 check [exec]. CachingCollectorManager (#16247 by gaobinlong, 3afffeef5a8 / d60e550b47f, first released in 10.6.0) inherits it: its constructor checks only that exactly one limit is set.",
   "introduced_date": "2014-04-04 (LUCENE-5527 trunk commit; branch_5x backport 2014-09-18); silent form 2023-06-30 (#12380, author date of both commits); CachingCollectorManager leg 2026-07-08 (#16247)",
   "first_affected_version": "5.0.0 [exec] (replay throws AssertionError with -ea, IndexOutOfBoundsException with -da); silent wrong results from 9.8.0 [exec]; 4.10.4 and earlier are not affected [exec]",
   "affected_versions": "[exec] every Maven Central release from 5.0.0 to 9.7.0 (84 releases) fails at replay (isCached() true, then AssertionError with -ea or IndexOutOfBoundsException with -da); every release from 9.8.0 to 10.5.2 (23 releases) returns silently wrong results (isCached() true, 0 documents replayed, GroupingSearch totalHitCount 0); 10.6.0 (the branch_10_6 head 4ae946e5a9b, the RC1 revision; finder JUnit 4 of 5 fail, also through CachingCollectorManager) and main a9779ef3c193 (4 of 5 fail with -ea and -da, re-run at the registration check 2026-10-28) fail the same way; 3.2.0-4.10.4 (28 releases) pass. The release sweep ran with -da on every release and with -ea on a subset, all with JDK 25 on aarch64 Linux rather than the JDK each release shipped for. Not a 10.6.0 regression. Not fixed upstream: no commit touches CachingCollector.java, CachingCollectorManager.java or GroupingSearch.java after #16247 on main (head c5ab3e57b9ba) or branch_10_6 (head 4ae946e5a9b9) [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-908.html",
   "repro": "repro/LFV-908/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-966",
   "priority": "low",
   "priority_rank": 383,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / flexible core: QueryNodeProcessorPipeline (java.util.List views and default methods)",
   "title": "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",
   "summary": "You customise a flexible query parser pipeline, for example StandardQueryParser's, by inserting or replacing a processor through the pipeline's java.util.List API: pipeline.listIterator() then add or set, subList(..).set, pipeline.replaceAll or Collections.replaceAll. You expect the processor to receive the pipeline's QueryConfigHandler, as it does with add(k, p) or set(k, p), because the class says it 'takes care of setting this QueryConfigHandler on all processor on pipeline'. Instead those paths write through the private ArrayList's own views and leave the processor with a null handler, so a replaced PointQueryNodeProcessor turns n:5 into a TermQuery that finds 0 of 1 matching documents, a replaced BoostQueryNodeProcessor drops field boosts, and most other stock processors throw NullPointerException at parse.",
   "impact_class": "silent wrong results",
   "introduced_commit": "6f66858572c0aa9528e5b1e6999c945db5712fce (trunk r1024402, 'LUCENE-1937: add methods to manipulate QueryNodeProcessorPipeline elements', patch by Adriano Crestani, committed by Robert Muir; JIRA patch workflow, no GitHub PR; migrated as apache/lucene#3012); branch_3x backport 2ab3fc4ba40bcdd239d49bbac1b4d2539198170c (r1024405), the commit released in 3.1.0. It made the pipeline implement java.util.List, with add/add(int)/addAll/addAll(int)/set setting the handler and iterator/listIterator/listIterator(int)/subList returning the backing list's raw views [read]. 7335eb0ad96 (#15704, author date 2026-02-26, main only) swapped the backing LinkedList for an ArrayList and kept the raw views (not a regression, not a fix)",
   "introduced_date": "2010-10-19 (author and commit date of both commits; the patch was attached to the issue on 2009-10-13)",
   "first_affected_version": "3.1.0 [exec] (first release with the commit; 2.9.4 and 3.0.3 have no List API on the pipeline [exec])",
   "affected_versions": "every release from 3.1.0 to 10.6.0 and main. [exec] the version-portable history probe fails on 3.1.0, 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2, branch_10_6 4ae946e5a9b and main a9779ef3c193 (6 of 6 view paths drop the field boost and leave the handler null; the 2 reference paths are correct) and passes on main with the fix shadowed; the candidate JUnit fails 2 of 2 on 9.1.0, 9.12.3, 10.0.0, 10.5.2, branch_10_6 and main (on main with -ea and -da); the independent reproduction's JUnit fails 7 of 9 on main (-ea and -da), 10.5.2 (-ea and -da) and 9.12.3. [read] the silent point-query symptom exists since 6.0.0 (PointQueryNodeProcessor, LUCENE-7089, with the same null guard) and was executed from 9.1.0; the silent boost drop exists since 3.1.0; List.replaceAll exists only on Java 8 and later JVMs. Not fixed upstream: QueryNodeProcessorPipeline.java last changed by 7335eb0ad96 (#15704); upstream main 645d4fe14a2 (2026-10-28) still returns the raw views. All runs on Linux aarch64 with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-966.html",
   "repro": "repro/LFV-966/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-210",
   "priority": "low",
   "priority_rank": 384,
   "novelty": "known",
   "withheld": false,
   "area": "geo / Tessellator hole elimination (polygon indexing for LatLonShape and XYShape)",
   "title": "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",
   "summary": "You index a polygon whose hole touches the outer boundary at one corner, which the Tessellator javadoc allows ('Holes may only touch at one vertex'), for example the outer ring (2,0) (1,1) (0,2) (3,3) with the hole (1,1) (1,2) (2,2), and you expect a point inside the hole not to match. To cut the polygon into triangles Lucene first joins the hole to the outer ring with a bridge; when the hole's left-most corner lies on an outer edge, Tessellator.fetchHoleBridge links it to the vertex before that edge instead of the edge's own endpoint, so the bridge runs across the hole. The triangles then cover the hole and an INTERSECTS query for a point in it matches the document with no error, or, for other shapes such as a hole corner touching the middle of an outer edge, the valid polygon is rejected with 'Unable to Tessellate shape'.",
   "impact_class": "silent wrong results",
   "introduced_commit": "d494f6be13a585c273c6a3dabc76644f4d480c31 on master and its branch_7x twin f54639d4a18bbca98c8853f7e5065a0a3752292c (the commit 7.6.0 contains): LUCENE-8454 'Polygon tessellator can get into an infinite loop' (migrated as #9500, reported by iverase), by nknize, committed directly without a PR. It changed the guard in front of the existing 'return connection.previous;' from 'hx == connection.getX()' to 'hx == qx', so the branch fires whenever the hole's left-most vertex lies on an outer edge. The statement itself came with the original port, b5ef13330f1 (LUCENE-8396, #9443, 2018-07-14, released in 7.5.0, sandbox), where the trigger shapes did not reach it [exec]",
   "introduced_date": "2018-09-19 (LUCENE-8454 guard change); the statement itself dates from 2018-07-14 (LUCENE-8396)",
   "first_affected_version": "7.6.0 [exec] (lucene-sandbox at the time; the Tessellator moved to core in 8.5.0 [read]); 7.5.0 tessellates both trigger polygons correctly [exec]; 7.4.0 has no LatLonShape or Tessellator [exec]",
   "affected_versions": "Every release from 7.6.0 to 10.5.2 (the last release before 10.6.0) and main ea57360912ed. [exec] the follow-up history probe (LatLonShape, trigger polygons A and B) fails on the stock jars of all 65 releases from 7.6.0 to 10.5.2 (7.6.0, 7.7.0-7.7.3 and every 8.x, 9.x and 10.x release) and on main (-ea and -da); each release passes with only its own Tessellator.java one-line-fixed and gives the stock outcome with its unmodified source shadowed (219 runs, 0 inconsistencies). The finder's JUnit fails 4 of 4 on 9.1.0, 9.2.0, 9.12.3, 10.5.2 and main (-ea, -da); the independent reproduction's JUnit fails 9 of 9 on main (-ea, -da), 10.5.2 and 9.12.3. The symptom moves with later Tessellator changes: 7.6.0-8.1.1 polygon B silently keeps 1/7 of its area; 8.2.0 B rejected; 8.3.0-9.1.0 (including 8.11.0-8.11.2) A and B rejected; 8.11.3-8.11.4 and 9.2.0-10.5.2 and main A covers its hole and B is rejected. [read] upstream main and branch_10x still have 'return connection.previous;' at Tessellator.java:565; the 10.x branches and 10.6.0 (released 2026-10-29) were not run separately.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15731",
    "https://github.com/apache/lucene/issues/13841",
    "https://github.com/apache/lucene/issues/15554",
    "https://github.com/apache/lucene/issues/15695",
    "https://github.com/apache/lucene/issues/15205",
    "https://github.com/apache/lucene/issues/11506"
   ],
   "doc": "",
   "repro": "repro/LFV-210/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-757",
   "priority": "low",
   "priority_rank": 385,
   "novelty": "new",
   "withheld": false,
   "area": "geo / Tessellator hole elimination (polygon indexing for LatLonShape and XYShape)",
   "title": "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)",
   "summary": "You index a valid polygon with two holes, where hole A touches the outer ring at one corner (the Tessellator javadoc allows 'Holes may only touch at one vertex') and hole B touches nothing, for example the outer ring (0,0) (2,5) (0,10) (10,10) (10,0) with hole A (2,5) (5,6) (4,8) and hole B (6,5) (8,4) (8,6), and you expect a point inside hole A not to match. Since #15211 the Tessellator leaves several copies of the shared corner (2,5) next to each other while it joins the holes to the outer ring; when it then chooses the bridge for hole B, whose left-most corner (6,5) is level with (2,5), it rejects every copy and bridges to (0,10) instead, a line that cuts through hole A. The triangles then cover hole A, and an INTERSECTS query for a point in it matches the document with no error, while with checkSelfIntersections=true the same valid polygon is rejected with 'Polygon self-intersection'.",
   "impact_class": "silent wrong results",
   "introduced_commit": "d04c5e3530a2b0a0d02bc8db45adaa677ee58577 on main: #15211 '[Tessellator] Fix failure due to hole bridge being coplanar with polygon edge' (fixes #15205, by iverase). It removed the filterPoints(node, node.next) call after the bridge split and after the shared-vertex split and added one final filterPoints(outerNode, null) at the end of eliminateHoles. Backported the same way as 8af285735bea (branch_10x, released in 10.4.0) and 911b518aa8af (branch_9_12, released in 9.12.3) [exec]. The leftmost-shared-vertex split that #15657 (43792b9870e, 2026-02-02, in 10.4.0) added later never had a per-split filter, so on 10.4.0 and main reverting only #15211's three hunks still fails, while per-split filtering at every split site passes the repro [exec]",
   "introduced_date": "2025-09-23 (main and branch_10x); 2025-09-24 (branch_9_12)",
   "first_affected_version": "9.12.3 [exec] (tagged 2025-09-27; its only Tessellator.java change after 9.12.2 is the #15211 backport); on the 10.x line 10.4.0 [exec] (tagged 2026-02-25). 9.12.2 and 10.3.0 tessellate the repro polygon exactly [exec]; 10.3.1 and 10.3.2, released after the change, are not affected because branch_10_3 never got the backport [exec]",
   "affected_versions": "[exec] the finder's JUnit (seed DEADBEEF) fails 4 of 4 on 9.12.3 (-ea and -da), 10.4.0, 10.5.0, 10.5.1, 10.5.2 (-ea and -da) and main a9779ef3c193 (-ea and -da); the independent reproduction's JUnit fails 7 of 7 on main, 10.5.2, 10.4.0 and 9.12.3. [exec] not affected (4 of 4 pass): 9.11.1, 9.12.0, 9.12.1, 9.12.2, 10.0.0, 10.1.0, 10.2.0, 10.2.2, 10.3.0, 10.3.1, 10.3.2. [read] 8.5.0-9.11.0 and 10.2.1 still filter after each split and have no final filter, so they are not affected; branch_10_6 (10.6.0, released 2026-10-29) and the unreleased branch_10x and branch_10_5 carry the post-#15211 code (read, not executed). Still unfixed on upstream main f7bcc0abd81 (no Tessellator.java logic change after #15739, 2026-02-24).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-757.html",
   "repro": "repro/LFV-757/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-796",
   "priority": "low",
   "priority_rank": 386,
   "novelty": "known",
   "withheld": false,
   "area": "geo / Tessellator hole elimination (polygon indexing for LatLonShape and XYShape)",
   "title": "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)",
   "summary": "You index a valid polygon with LatLonShape or XYShape whose clockwise outer ring (2,3) (2,5) (4,4) (5,0) (0,0) has a counter-clockwise hole A (2,3) (1,1) (2,1), which touches the ring only at V=(2,3) where the outer edge (2,5)-(2,3) and the hole edge (2,3)-(2,1) lie on the line x = 2, and a second hole B (3,3) (4,2) (4,3) that touches nothing, and you expect the triangles to cover the polygon minus both holes (area 12.5). After hole A is merged at V, the filterPoints pass that eliminateHoles runs after every hole (Tessellator.java:347) drops the copy of V on that straight run; hole B's leftward ray from (3,3) then hits two edges exactly at V, and fetchHoleBridge keeps whichever comes first in ring order (the strict 'x > qx' at :549), so with the ring written from (2,3) hole B is bridged to (0,0) straight across hole A. The triangles then cover hole A (total area 16.0), the point (1.75,1.5) inside hole A matches INTERSECTS and misses DISJOINT, and the strict path rejects the polygon as self-intersecting; the other four ring starts are exact on main (on 8.2.0-9.12.2 and 10.0.0-10.3.2 the failing start is (2,5) instead).",
   "impact_class": "silent wrong results",
   "introduced_commit": "b5ef13330f179ac6a2d98b9dfa4803811190e773 on master (LUCENE-8396 'Add Points Based Shape Indexing and Search that decomposes shapes into a triangular mesh ...', by nknize, committed directly on 2018-07-14 with no PR; issue migrated as apache/lucene#9443), shipped through its branch_7x copy bc29580378d in 7.5.0 together with LUCENE-8418 (50615fda9df) [read] [exec]. The confirmed polygon W1 needs LUCENE-8775 part 2 (master 88c5817c01a, branch_8x 9fc2beb0ab4, apache/lucene-solr#708, by iverase, 2019-06-11, first released in 8.2.0), which merges a hole at a shared vertex that is not its left-most vertex and so creates the copies of V [exec]. #15211 (main d04c5e3530a; 911b518aa8a in 9.12.3, 8af285735be in 10.4.0) moved W1's failing start from (2,5) to (2,3) and stopped W2 from reaching this bug [exec].",
   "introduced_date": "2018-07-14 (b5ef13330f1 / branch_7x bc29580378d); the confirmed polygon's trigger path since 2019-06-11 (88c5817c01a / branch_8x 9fc2beb0ab4)",
   "first_affected_version": "7.5.0 [exec]; the confirmed polygon W1 first fails in 8.2.0 [exec]; XYShape first appears in 8.2.0",
   "affected_versions": "[exec] every release from 7.5.0 to 10.5.2 (66 releases) and main a9779ef3c193, by the history stage's portable public-API main() (LatLonShape, and XYShape from 8.2.0): W1 (the confirmed polygon) is wrong on 8.2.0-10.5.2 and main, at start (2,5) on 8.2.0-9.12.2 and 10.0.0-10.3.2 and at start (2,3) on 9.12.3, 10.4.0-10.5.2 and main; W2 is wrong through this bug on 7.5.0-9.12.2 and 10.0.0-10.3.2 (from 9.12.3/10.4.0 W2 is still wrong, but through another defect that the tie rule does not change). Confirmed by other stages: main with -ea and -da (finder, the independent reproduction, the cross-model review stage, the intended-behaviour check, adjudication, registration check), 10.5.2 and 9.12.3 (finder, the independent reproduction, the intended-behaviour check), 10.4.0, 10.3.2, 10.0.0 and 9.12.2 (finder, the independent reproduction), 9.1.0 (finder's JUnit), 9.0.0, 8.11.4, 8.8.2, 8.5.0, 8.4.1 and 8.2.0 (finder's main() variant). The reach before 8.2.0 rests on the history stage's W2 (plus one re-run on 7.6.0), not on the independent reproduction/the intended-behaviour check. 7.x and 8.x ran on JDK 25, outside their supported JDKs (plain Java; the in-polygon controls pass). [read] unfixed on upstream main 20ced71c1e6e (2026-10-27), branch_10x and branch_10_6 (no Tessellator logic change since #15739, 2026-02-24), so 10.6.0 (4ae946e5a9b) is affected too.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/12036",
    "https://github.com/apache/lucene/issues/12295",
    "https://github.com/apache/lucene/issues/219",
    "https://github.com/apache/lucene/issues/220",
    "https://github.com/apache/lucene/issues/221",
    "https://github.com/apache/lucene/issues/756"
   ],
   "doc": "",
   "repro": "repro/LFV-796/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-794",
   "priority": "low",
   "priority_rank": 387,
   "novelty": "new",
   "withheld": false,
   "area": "geo / Tessellator hole-bridge edge flags (LatLonShape and XYShape CONTAINS queries)",
   "title": "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",
   "summary": "You index a valid polygon whose two holes each touch the same straight outer edge at one point, for example the triangle (0,0) (7,12) (12,0) with the holes (2,0) (5,1) (3,3) and (5,0) (8,1) (6,3), both touching the bottom edge y = 0, and you expect a CONTAINS box query to match only boxes that lie inside the polygon. While joining the second hole to the ring, Tessellator.eliminateHole draws a bridge from (5,0) to (2,0) that runs along the outer edge but marks it as an internal edge, because it only compares the bridge with the ring edges next to its two ends, so the indexed triangle loses its 'belongs to the polygon' flag on that piece of the boundary. LatLonShape and XYShape CONTAINS queries then match the box x [3,4], y [-0.5,0.3], which sticks out below the polygon, with no error, on every release executed since 8.4.0.",
   "impact_class": "silent wrong results",
   "introduced_commit": "62001b9b9651e54b54f73352801061d40da75168 on main and its branch_8x backport 252421bb77c (the commit 8.3.0 shipped): LUCENE-8620 'Update Tessellator logic to label if triangle edges belongs to the original polygon', apache/lucene-solr#771 by iverase, merged 2019-09-09. It added the triangle edge flags and set the bridge flag only from the ring edges adjacent to the bridge ends (two isPointInLine checks), although the same commit added the whole-ring isEdgeFromPolygon scan and used it for ear-clipping and split diagonals [read]. The user-visible symptom needs the CONTAINS relation, added by 2ef2ddd77c5 (apache/lucene-solr#872, LUCENE-8620 'Add CONTAINS support for LatLonShape and XYShape', 2019-12-11; branch_8x a06a2ea3da2, first released in 8.4.0). Later edits of the expression do not cover a bridge inside a non-adjacent ring edge: 2d6ad2fee6d (LUCENE-9570 reformat), 748570531e0 (#15700, rename to 'bridge') and faef795a460 (#15739, two to four adjacent-edge checks, first in 10.5.0)",
   "introduced_date": "2019-09-09 (edge flags, 62001b9b965 / 252421bb77c); 2019-12-11 (the CONTAINS relation that reads them, 2ef2ddd77c5 / a06a2ea3da2)",
   "first_affected_version": "8.4.0 [exec] for the wrong CONTAINS result (the first release with CONTAINS on LatLonShape and XYShape); the wrong flag itself is already in 8.3.0's Tessellator.tessellate output and stored triangle encoding [exec], where no query relation reads it; 8.2.0 has no edge flags and no CONTAINS [exec]",
   "affected_versions": "every release from 8.4.0 (the flag is wrong from 8.3.0) through 10.6.0 (10.6.0 by reading) and 9.12.3 (the latest 9.x), and main a9779ef3c193. [exec] the follow-up's version-independent main() check (flag oracle of upstream TestTessellator plus a LatLon CONTAINS box check, 16 cases) is wrong in 16 of 16 cases on 8.4.0, 8.4.1, 8.5.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da), flag only on 8.3.0 and 8.3.1 (no CONTAINS yet), and not applicable on 8.2.0; the finder's JUnit (XY and LatLon) fails 4 of 4 on main (-ea, -da), 10.5.2 (-ea, -da), 10.4.0, 10.3.2, 9.12.3, 9.12.2 and 9.1.0; the independent reproduction's JUnit fails 4 of 5 on main, 10.5.2 and 9.12.3 and its main() variant on 9.0.0 and 8.11.4; the intended-behaviour check's upstream-oracle probe mismatches 32 of 32 on main and 9.12.2. Before 9.1.0 only the LatLon box path was executed. Releases in between were not executed and are affected by inference (the expression never gained a non-adjacent check [read]). Not fixed upstream: main 20ced71c1e6e, branch_10x and branch_10_6 still carry the four-term expression [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-794.html",
   "repro": "repro/LFV-794/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-793",
   "priority": "low",
   "priority_rank": 388,
   "novelty": "known",
   "withheld": false,
   "area": "geo / Tessellator hole elimination (polygon indexing for LatLonShape and XYShape)",
   "title": "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)",
   "summary": "You index a valid polygon with LatLonShape or XYShape whose outer ring and two holes meet only at one vertex P, with an outer edge running straight into a hole edge through P, for example POLYGON((2 6, 2 7, 4 0, 0 0, 2 6), (2 6, 3 1, 3 2, 2 6), (2 6, 1 1, 2 1, 2 6)), and expect the triangles to cover the polygon minus both holes. After hole B (2,6) (1,1) (2,1) is merged at P, the filterPoints call that Tessellator.eliminateHoles runs after every hole (Tessellator.java:347) removes the copy of P that lies on the straight line (2,7)-(2,6)-(2,1); hole A, whose left-most vertex is P, is then merged at the only remaining copy of P, in the wrong wedge, and ear clipping emits triangles over hole B (twice the tessellation area is 25 instead of 20). A point inside hole B such as (1.8, 2) then matches an INTERSECTS point query and a box inside hole B is not DISJOINT; on 9.12.3, 10.4.0 and later this happens only when the outer ring is written starting at P, on 8.2.0 to 9.12.2 and 10.0.0 to 10.3.2 for every ring start tested.",
   "impact_class": "silent wrong results",
   "introduced_commit": "88c5817c01ad3c92380ef432212cae5571713a94 on master (LUCENE-8775 part 2, 'Compute properly the bridge between a polygon and a hole when sharing a vertex', apache/lucene-solr#708 'LUCENE-8775: Fix bug when selecting bridge and improve tests', by iverase, merged 2019-06-11; issue LUCENE-8775, migrated as apache/lucene#9819), shipped through its branch_8x copy 9fc2beb0ab4 (same day, byte-identical Tessellator.java) in 8.2.0. It made eliminateHole merge a hole at the first outer-ring node that equals one of its vertices; the filterPoints call that eliminateHoles has run after every hole since LUCENE-8396 (7.5.0) then removes the straight-run copy of that vertex [exec]. Part 1 (05ea0f2d54a / ca07f444c85, apache/lucene-solr#652, 2019-06-06) already fails the area check, but through a different, short-lived defect (hole B is dropped from the ring), which part 2 was written to fix; both first shipped in 8.2.0. On main the per-hole call reads 'outerNode = filterPoints(result, result.next)' (#15700, 748570531e0) and the collinear-removal condition dates from LUCENE-10470 (5d3ab09676a) [read].",
   "introduced_date": "2019-06-11 (master 88c5817c01a and branch_8x 9fc2beb0ab4)",
   "first_affected_version": "8.2.0 [exec] (8.1.1 is the last unaffected release [exec]; 8.1.2, whose branch_8_1 also got the change, was never released; LatLonShape shipped in lucene-sandbox until 8.5.0, and XYShape first appears in 8.2.0, so XYShape is affected in every release that has it)",
   "affected_versions": "[exec] the public-API history check (LatLon polygon in degrees, twice-area 25 instead of 20, an INTERSECTS box inside hole B matches, DISJOINT misses) covers hole B on 8.2.0, 8.3.0, 8.3.1, 8.4.0, 8.4.1, 8.5.0, 8.5.1, 8.5.2, 8.6.0, 8.6.3, 8.7.0, 8.8.0, 8.8.2, 8.9.0, 8.10.1, 8.11.0, 8.11.4, 9.0.0, 9.1.0, 9.2.0, 9.3.0, 9.4.0, 9.4.2, 9.5.0, 9.6.0, 9.7.0, 9.8.0, 9.9.0, 9.9.2, 9.10.0, 9.11.0, 9.11.1, 9.12.0, 9.12.1, 9.12.2, 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1 and 10.5.2, and on main a9779ef3c193 (-ea and -da; 8.2.0, 8.11.4, 9.12.3 and 10.5.2 also with -da); it is correct on 7.5.0, 7.6.0, 7.7.0, 7.7.3, 8.0.0, 8.1.0 and 8.1.1. The finder's JUnit fails 4 of 4 on main (-ea and -da), 10.5.2 (-ea and -da), 9.12.3, 9.4.0 and 9.1.0, and its earlier 3-test version 3 of 3 on 9.12.0 and 9.8.0; it does not compile on 9.0.0 and earlier (no org.apache.lucene.tests package). The independent reproduction's JUnit fails on main, 10.5.2, 9.12.3, 10.3.0 and 9.4.0. Trigger breadth: on 8.2.0-9.12.2 and 10.0.0-10.3.2 all 8 tested encodings (4 outer-ring starts x 2 hole orders) cover hole B; from 9.12.3 and 10.4.0 on (#15211) only the 2 whose outer ring starts at P (the intended-behaviour check: 144 of 576 encodings on main, exactly those). Not executed: 8.6.1, 8.6.2, 8.10.0, 8.11.1-8.11.3, 9.4.1 and 9.9.1 (between executed affected releases). [read] unfixed on upstream main 20ced71c1e6e (2026-10-27), branch_10x and branch_10_6, so 10.6.0 (4ae946e5a9b) is affected too.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/12036",
    "https://github.com/apache/lucene/issues/12295",
    "https://github.com/apache/lucene/issues/15205",
    "https://github.com/apache/lucene/issues/15211",
    "https://github.com/apache/lucene/issues/13980",
    "https://github.com/apache/lucene/issues/13841"
   ],
   "doc": "",
   "repro": "repro/LFV-793/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-764",
   "priority": "low",
   "priority_rank": 389,
   "novelty": "new",
   "withheld": false,
   "area": "geo / XYShape point queries (Component2D.pointInTriangle; ShapeField.encodeTriangle orientation for XY)",
   "title": "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)",
   "summary": "You index the clockwise triangle (0,1) (1,2) (3,3) as an XYPolygon with XYShape.createIndexableFields and run XYShape.newPointQuery at each of its corners; you expect every corner to match the polygon (INTERSECTS) and none to be DISJOINT from it, as happens for the same triangle moved by (8,8) and for every point of its edges. Instead the INTERSECTS query at (1,2) finds nothing and the DISJOINT query at (1,2) returns the document: ShapeField.encodeTriangle checks the winding on the sortable-int encodings of the floats, which are ordered like the floats but not evenly spaced, so the stored triangle decodes clockwise, and Component2D.pointInTriangle reports the second vertex of a clockwise triangle as outside. The same happens with projected metre-like coordinates, for example at vertex (518885,4395432) of a hexagon whose x range crosses 2^19.",
   "impact_class": "silent wrong results",
   "introduced_commit": "ff365a0abf23d89fd0eba3fbb707f0fc4f2316ce on master: LUCENE-8903 'Add LatLonShape point query' (apache/lucene-solr PR #762 by iverase, merged 2020-01-15), which added XYShape.newPointQuery (XYShapePointQuery, then Point2D.relateTriangle, then Component2D.pointInTriangle), the first public path that evaluates pointInTriangle at a stored vertex; branch_8x backport f56f51fc3ebc58bc69d8c381af9d6ef6671619b5 [read]. Older latent ingredients [read]: the pointInTriangle sign test, unchanged since b5ef13330f1 (LUCENE-8396, 2018-07-14, then Tessellator.pointInTriangle; copied into EdgeTree by 893f5cda574, LUCENE-8654, and moved into Component2D by 68a3886b977, LUCENE-8746); the counter-clockwise normalisation of encoded ints in encodeTriangle (d185ba99de0, LUCENE-8581, 2018-12-18, harmless for the linear LatLon encoding); and the non-affine XY sortable-float encoding that reached it with 0c09481374c (LUCENE-8632, 2019-07-08, sandbox in 8.2.0)",
   "introduced_date": "2020-01-15 (master ff365a0abf23 and branch_8x f56f51fc3ebc); latent ingredients 2018-07-14 (pointInTriangle), 2018-12-18 and 2019-07-08 (encoded-space orientation, XY encoding)",
   "first_affected_version": "8.5.0 [exec] (tag commit 2020-03-12; the same release moved XYShape from sandbox to core, LUCENE-8621). 8.4.1 has no XYShape point query: the repro does not compile against 8.4.1 core or 8.4.1 sandbox [exec]; a limited probe found no earlier public path (line, polygon and box queries touching the triangle only at the vertex answer correctly on 8.4.1 sandbox, 8.5.0 and main) [exec]",
   "affected_versions": "[exec] the finder's JUnit (seed DEADBEEF, -ea) fails 3 of 3 with the same three messages on all 52 releases from 8.5.0 to 10.5.2 (8.5.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2) and on main a9779ef3c193, and also with -da on 8.5.0 and main; the independent reproduction's own JUnit fails 3 of 3 on main (-ea, -da), 10.5.2 and 9.12.3; the intended-behaviour check's replay fails on 10.5.2. Not applicable: 8.4.1 and earlier (no XYShape point query; 8.3.1 and 8.4.1 are compile errors) [exec]. [read] main a9779ef3c193 has no geo or shape change since the history base 7cecf795236, upstream main a95c754ee00 (2 commits ahead) touches no geo or shape file, and no open PR touches Component2D.java, ShapeField.java, Point2D.java, XYShapeQuery.java or XYEncodingUtils.java. branch_10_6 (10.6.0, released 2026-10-29) and the unreleased branch_10x were not executed.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-764.html",
   "repro": "repro/LFV-764/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-795",
   "priority": "low",
   "priority_rank": 390,
   "novelty": "known",
   "withheld": false,
   "area": "geo / Tessellator hole bridges (fetchHoleBridge, isLocallyInside) behind LatLonShape and XYShape polygon indexing",
   "title": "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)",
   "summary": "You index a valid polygon with two holes that touch nothing, for example the clockwise outer ring (4,5) (5,1) (0,0) (1,1) with the counter-clockwise holes (2,2) (4,3) (3,3) and (3,2) (3,1) (4,1), and you expect XYShape or LatLonShape.createIndexableFields to return its triangles whichever vertex the outer ring starts at. The first hole is joined to the ring by a bridge from (2,2) to (1,1) that continues the outer edge (0,0)-(1,1) in a straight line; the second hole's bridge search then lands on (1,1), and the only copy of (1,1) whose angle contains that hole has a straight angle, which Tessellator.isLocallyInside always rejects ('area == 0 -> return false'). When the outer ring starts at (5,1) or (0,0) the search keeps the other copy, the bridge crosses the ring and indexing throws 'Unable to Tessellate shape. Possible malformed shape detected.', while the starts (4,5) and (1,1) give the exact area 9; 8.1.1 accepts every start, 8.2.0 to main reject two of them.",
   "impact_class": "crash",
   "introduced_commit": "05ea0f2d54afd91b10b845c7b01e6738f0de4a78 on main (then 'master'; first in 9.0.0) and its same-day branch_8x backport ca07f444c85da5dc45cd794c0410a90be251d29c (identical Tessellator.java, git blob 195e4a6c4d3; the commit 8.2.0 shipped): apache/lucene-solr#652, LUCENE-8775 (apache/lucene#9819) 'Tessellator: Improve the election of diagonals when splitting the polygon' by iverase, merged 2019-06-06. It added 'if (area == 0) { // parallel return false; }' to isLocallyInside; before it a straight angle fell into the ccw branch, a strict half-plane test, as in earcut's locallyInside [read]. The same commit's fetchLeftmost tie-break (lowest y on equal x) is also needed for the exact repro polygon, whose second hole has two left-most vertices; a variant with a unique left-most vertex fails with the straight-angle hunk alone on 8.1.1 [exec], so the tie-break is not the defect. A branch_8_1 backport (336eff705a9, 2019-06-25) shipped in no release.",
   "introduced_date": "2019-06-06 (05ea0f2d54a on main and ca07f444c85 on branch_8x, the same day)",
   "first_affected_version": "8.2.0 [exec]; the last release before it, 8.1.1, accepts the polygon for every outer-ring start [exec] (8.1.2 was never released)",
   "affected_versions": "every release from 8.2.0 through 10.5.2 (57 releases) and main a9779ef3c193 [exec]: the follow-up's version-independent main() (LatLonShape.createIndexableFields and Tessellator.tessellate, exact area and hole-point check, all 4 outer-ring starts) fails on all 57 releases and on main; the finder's public-API JUnit (XY and LatLon, both checkSelfIntersections values, point queries) fails 2 of 2 on main (-ea and -da), 10.5.2, 10.4.0, 10.3.2, 10.0.0, 9.12.3, 9.12.2 and 9.1.0; the independent reproduction's own JUnit fails on main (-ea, -da), 10.5.2 and 9.12.3 and its main() on 8.2.0. Not affected [exec]: the 9 releases 7.5.0 to 8.1.1 (7.5.0 is the first with LatLonShape and the Tessellator). XYShape exists from 8.2.0; before 9.1.0 only the LatLonShape path was executed. The five polygons published in mapbox/earcut #219 and #221 are rejected by main, 10.5.2 and 9.12.2 in 18 of 74 start-vertex/hole-order configurations, by 8.2.0 in 10 and by 8.1.1 in none [exec]. Not fixed upstream: no logic change to Tessellator.java after #15739 on main 20ced71c1e6, branch_10x, branch_10_5 and branch_9_12, and isLocallyInside still has the straight-angle branch [read].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/219",
    "https://github.com/apache/lucene/issues/221",
    "https://github.com/apache/lucene/issues/220",
    "https://github.com/apache/lucene/issues/12036",
    "https://github.com/apache/lucene/issues/12295",
    "https://issues.apache.org/jira/browse/LUCENE-8775"
   ],
   "doc": "",
   "repro": "repro/LFV-795/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-762",
   "priority": "low",
   "priority_rank": 391,
   "novelty": "new",
   "withheld": false,
   "area": "geo / Tessellator hole elimination (polygon indexing for LatLonShape and XYShape)",
   "title": "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)",
   "summary": "You index a valid polygon whose three holes meet only at one corner P, for example the triangle (0,0) (7,12) (12,2) with the holes A (8,8) (6,7) (7,6), B (9,3) (10,4) (7,6) and C (6,6) (6,4) (7,4) (7,6), which all touch at P=(7,6) (the Tessellator javadoc allows 'Holes may only touch at one vertex'), and you expect XYShape.createIndexableFields or LatLonShape.createIndexableFields to return its triangles, as 10.3.x does for every hole order. Since #15700 (first released in 10.4.0), once the first holes are joined at P the ring holds several copies of P, each bounding a different wedge around P, and when hole B (whose left-most vertex is P) is joined, the Tessellator takes the first copy of P in ring order, through an index comparison that depends on the input order of the holes, without checking that B lies in that copy's wedge. For the hole orders ABC, ACB and BAC this picks a wrong copy and both calls throw IllegalArgumentException 'Unable to Tessellate shape', and upstream's own LUCENE-9400 regression polygon (TestTessellator.testComplexPolygon41) is likewise rejected in 3 of its 6 hole orders.",
   "impact_class": "crash",
   "introduced_commit": "748570531e081efadb643a22075e47019304c475 on main: #15700 'Fix Tessellation error for holes that share the same leftmost vertex with an outer ring vertex' (fixes #15695; by roblburris, approved and merged by iverase), specifically its sub-change that replaced the getSharedInsideVertex angle tie-break among copies of the hole's left-most vertex by 'take first match only' in ring order from outerNode. Backports 8073c18bfd8 (10.4 release line, only in the 10.4.0 tag) and 8f62c009615 (branch_10x, in 10.5.0-10.5.2) [exec]. Prerequisite 43792b9870e (#15657, fixes #15554, 2026-02-02, also first in 10.4.0) added the left-most preference and the idx guard but kept the tie-break; the repro passes on that state [exec]. A plain revert is not a fix: with the tie-break restored, upstream TestTessellator.testComplexPolygon63 (the #15695 polygon) fails again [exec]",
   "introduced_date": "2026-02-17 (main 748570531e0, 10.4 release line 8073c18bfd8 and branch_10x 8f62c009615; PR opened 2026-02-11)",
   "first_affected_version": "10.4.0 [exec] (tagged 2026-02-25; the first release with the #15700 backport). 10.3.2 is the last unaffected release [exec]; no 9.x release is affected (no 9.x branch carries #15657 or #15700; 9.12.3 executed)",
   "affected_versions": "[exec] the finder's JUnit (seed DEADBEEF) fails 2 of 4 (both indexing methods; the two controls pass) on 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main a9779ef3c193 (-ea, and -da on main); the independent reproduction's JUnit fails 4 of 5 on main (-ea and -da), 10.5.2, 10.5.0 and 10.4.0; upstream's LUCENE-9400 polygon is rejected in the hole orders (1,2,0), (2,0,1) and (2,1,0) on 10.4.0, 10.5.2 and main. [exec] not affected: 9.11.1, 9.12.2, 9.12.3, 10.0.0, 10.1.0, 10.2.2, 10.3.0, 10.3.1, 10.3.2 (every hole order of both polygons accepted where tested). [read] older releases lack the introducing lines; branch_10_6 (2763db11b0a, contained in 10.6.0, released 2026-10-29) and the unreleased branch_10x (1309534296e) carry the 10.5.2 Tessellator.java (identical blob, not executed), so 10.6.0 has it by reading. Still unfixed on upstream main f7bcc0abd816 (2026-10-27; no geo/ change after a9779ef3c193) and branch_10x.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-762.html",
   "repro": "repro/LFV-762/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-755",
   "priority": "low",
   "priority_rank": 392,
   "novelty": "new",
   "withheld": false,
   "area": "geo / Tessellator hole elimination (polygon indexing for LatLonShape and XYShape)",
   "title": "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)",
   "summary": "You index a valid polygon with holes, for example an L-shaped outer ring (0,0) (0,12) (4,12) (4,4) (12,4) (12,0) with three small triangular holes that touch the ring and each other only at single shared corners, which the Tessellator javadoc allows ('Holes may only touch at one vertex'), and you expect XYShape.createIndexableFields or LatLonShape.createIndexableFields to return its triangles, as 10.4.0 does. Instead, since #15739 (first released in 10.5.0), both calls throw IllegalArgumentException 'Unable to Tessellate shape. Possible malformed shape detected.', so the document cannot be indexed, although every proper subset of the holes tessellates. The cause is that #15739 changed the reflex-vertex branch of Tessellator.isLocallyInside from '< 0' to '<= 0', which accepts a candidate exactly collinear with a neighbouring edge; reverting that comparison fixes this polygon but breaks the #15731 polygon #15739 was written for, so a correct fix has to be more selective.",
   "impact_class": "crash",
   "introduced_commit": "faef795a460d7cf8270cd9aa53dfd17ca74b76c3 (main, merged 2026-02-24): apache/lucene#15739 'Fix tessellator failure when a hole is touching another hole in the middle of a segment' by iverase (approved by craigtaverner; fixes #15731, reported by roblburris; milestone 10.5.0), backported the same day to branch_10x as 333e6f4e4d95 (identical Tessellator.java blob d0510543dbd). Of its two Tessellator.java hunks, the isLocallyInside ccw-branch change ('area(a, b, a.previous) < 0 || area(a, a.next, b) < 0' to '<= 0 || <= 0', strict since LUCENE-8396 b5ef13330f1, 2018) causes the failure; the eliminateHole bridge-flag hunk does not [exec].",
   "introduced_date": "2026-02-24",
   "first_affected_version": "10.5.0 [exec] (via the branch_10x backport 333e6f4e4d95); 10.4.0, the last release before it, passes [exec] because it was cut from branch_10_4, which never got the backport",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2 (the last release before 10.6.0), 10.6.0 (by reading) and main a9779ef3c193 (unreleased 11.0); not fixed upstream (main f7bcc0abd816, branch_10x, branch_10_6 and branch_10_5 still read '<= 0'). [exec] the finder's JUnit fails 2 of 3 (the two indexing methods; the subset control passes) on 10.5.0 (-ea, -da), 10.5.1 (-ea), 10.5.2 (-ea, -da) and main (-ea, -da), and passes 3 of 3 on 9.12.2, 9.12.3, 10.0.0, 10.2.2, 10.3.0, 10.3.2 and 10.4.0 (-ea; 10.4.0 also -da); the independent reproduction's JUnit fails on main, 10.5.2 and 10.5.0 and passes on 10.4.0, 10.3.0 and 9.12.3. [read] every release tag from 9.0.0 to 10.4.0 has the strict '< 0'; 8.x not checked by execution; branch_10_6 (10.6.0, released 2026-10-29) and the unreleased branch_10x and branch_10_5 carry the change (git blob) but were not run.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-755.html",
   "repro": "repro/LFV-755/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-215",
   "priority": "low",
   "priority_rank": 393,
   "novelty": "known",
   "withheld": false,
   "area": "geo / shape queries (GeoUtils.lineCrossesLineWithBoundary, EdgeTree.crossesTriangle, Polygon2D and Line2D intersectsTriangle; LatLonShape and XYShape polygon and line queries)",
   "title": "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",
   "summary": "You index a polygon with LatLonShape or XYShape and search with a polygon or line using INTERSECTS (or DISJOINT); you expect a match only when the two shapes share at least one point. When one of the indexed shape's triangles has an edge on exactly the same straight line as a query edge, but further along that line so the two segments do not overlap, and the triangle's third corner reaches back over the query edge, Lucene reports a crossing: GeoUtils.lineCrossesLineWithBoundary answers true for any two collinear segments, and EdgeTree.crossesTriangle only pre-filters by the triangle's bounding box. INTERSECTS then returns the disjoint document and DISJOINT drops it, with no error (repro: query square [0,2]x[0,2] and indexed triangle (3,0),(4,0),(1.5,4), separated by the line x + 0.375y = 3; a box query over the same square answers correctly).",
   "impact_class": "silent wrong results",
   "introduced_commit": "17ef175224a0314bfd24fa83645ddcdabc9aea40 (main; LUCENE-9055 'Fix the detection of lines crossing triangles through edge points', iverase, apache/lucene-solr#1020, migrated issue apache/lucene#10097, merged 2019-12-17; branch_8_4 backport 481259621367d8df12b43303d5cfc134a1e0f93c shipped in 8.4.0, branch_8x f08a830a6a4880cb397cf7d071460e37ea6f8e10) gave EdgeTree.crossesTriangle an includeBoundary mode that calls GeoUtils.lineCrossesLineWithBoundary behind the triangle-bounding-box pre-filter and made Line2D pass true (line queries); c98229948a0bfdd9fd4b845c4110be0a5246e09e (main; LUCENE-9152 'Improve line intersection detection for polygons', iverase, apache/lucene-solr#1187, migrated issue apache/lucene#10192, merged 2020-01-29; branch_8x 29542c7f59ee157a57415af2ccf2829c669c6e5e, 8.5.0) made Polygon2D pass true for triangles with no corner inside the polygon (polygon queries) [exec]. The predicate's '<= 0' body dates from 458205396ef (LUCENE-8712, lucene-solr#598, 2019-03-12) and was renamed lineCrossesLineWithBoundary by 55c241d87f4 (LUCENE-8736, 2019-04-11, 8.1.0), where only the safe crossesBox/crossesLine paths used it. An earlier occurrence of the same pattern in the original shape-query code (d85defbedc5 LUCENE-8435, 7.5.0; a00cc3be72b LUCENE-8554, 7.6.0) disappeared in 7.7.0, when be471ea91d5 (LUCENE-8669, the only GeoUtils change in that range; not bisected) rewrote the segment predicate.",
   "introduced_date": "2019-12-17 (LUCENE-9055, line queries); 2020-01-29 (LUCENE-9152, polygon queries); earlier occurrence from 2018-07-28 (LUCENE-8435) until 7.7.0",
   "first_affected_version": "8.4.0 [exec] for line queries; 8.5.0 [exec] for polygon queries (9.0.0 on the main line); an earlier occurrence affected 7.5.0 (polygon query) and 7.6.0 (polygon and line query) [exec]; 7.7.0 to 8.3.1 are not affected for the tested geometry [exec]",
   "affected_versions": "Line queries: 8.4.0 to 10.5.2, 10.6.0 (by reading) and main ea57360912ed; polygon queries: 8.5.0 to 10.5.2, 10.6.0 (by reading) and main; earlier occurrence 7.5.0 and 7.6.0. [exec] a query-level LatLonShape driver (two mirrored triangles in all 6 vertex orders, with positive controls) on all 66 releases from 7.5.0 to 10.5.2 plus main (-da; 8.3.1, 8.4.0, 8.5.0 and main also -ea): affected 7.5.0, 7.6.0 and all 54 releases from 8.4.0 to 10.5.2 (8.4.0 and 8.4.1 line queries only), not affected 7.7.0-7.7.3, 8.0.0, 8.1.0, 8.1.1, 8.2.0, 8.3.0 and 8.3.1; a component-level probe on 12 releases plus main agrees; the finder's JUnit fails 4 of 5 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) and does not compile on 9.0.0 (test-framework API); the independent reproduction's JUnit fails 5 of 6 on main (-ea, -da), 10.5.2 and 9.12.3; the intended-behaviour check's probe and the security probe fail on main (-ea, -da), 10.5.2 and 9.12.3. [read] XYShape on 8.x uses the same Polygon2D/Line2D code (XYShape executed only from 9.1.0); 'not affected' for 7.7.0-8.3.1 is shown for the tested geometry, not proven for all inputs. Not fixed upstream: lineCrossesLineWithBoundary and EdgeTree.crossesTriangle have no functional change on main, branch_10x or branch_10_6 (GitHub API, 2026-10-26). All runs on aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/12036",
    "https://github.com/apache/lucene/issues/10097",
    "https://issues.apache.org/jira/browse/LUCENE-9055",
    "https://github.com/apache/lucene/issues/10192",
    "https://issues.apache.org/jira/browse/LUCENE-9152",
    "https://github.com/apache/lucene/issues/9782"
   ],
   "doc": "",
   "repro": "repro/LFV-215/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-206",
   "priority": "low",
   "priority_rank": 394,
   "novelty": "known",
   "withheld": false,
   "area": "geo / shape queries (Polygon2D containsLine/containsTriangle, LatLonShape and XYShape WITHIN)",
   "title": "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",
   "summary": "You index a line or polygon whose corner points lie exactly on the boundary of a non-convex (dented) query polygon, for example a road between two corners of a district, and search for shapes WITHIN that polygon; you expect only shapes that lie inside it. Polygon2D.containsLine/containsTriangle accept a segment or triangle when every vertex is contained, with boundary points counting as inside, and no polygon edge crosses it strictly; that shortcut is only valid for convex polygons, so a segment that cuts across a dent between two boundary points, or a triangle that fills the dent and lies completely outside, is reported as contained. The WITHIN query returns those documents with no error (repro: for the polygon (0,0),(4,0),(4,4),(2,1),(0,4), WITHIN returns the indexed segment (0,4)-(4,4) and the indexed notch triangle (0,4),(4,4),(2,1) although (2,4) and (2,3) are outside the polygon).",
   "impact_class": "silent wrong results",
   "introduced_commit": "edb05314b315acf9abc4f9fdb3d30e17aff7feba (LUCENE-8669 'Fix LatLonShape WITHIN queries that fail with Multiple search Polygons that share the dateline', nknize, direct commit on the main line, JIRA = apache/lucene#9715; backports be471ea91d53 branch_7x (7.7.0), fd92d54b38a7 (8.0.0), fade1a091bfa branch_8x): it made the triangle WITHIN shortcut ('all vertices contained and no crossing => INSIDE', present since 7.5.0 and safe while a touch counted as a crossing) ignore touching contacts, the narrow form [exec]. LUCENE-8712 (458205396efa / c70a404d070b, apache/lucene-solr#598, 2019-03-12) removed that form on main and branch_8x before any 8.x release. Today's wide form: 55c241d87f42e568d0d40d7599d56e725d4d3b92 (LUCENE-8736, nknize, 2019-04-11, direct commit, JIRA = apache/lucene#9782, still open; branch_8x b518bed8b3ba, 8.1.0) made Polygon2D.contains boundary-inclusive and GeoUtils.lineCrossesLine strict, so every boundary-vertex triangle passes [exec]; c98229948a0bfdd9fd4b845c4110be0a5246e09e (LUCENE-9152, iverase, apache/lucene-solr#1187, 2020-01-29; branch_8x 29542c7f59ee, 8.5.0) extended it to segments by switching the both-endpoints-contained line case to crossesLine(..., false) [exec]; f914e08b3647 (LUCENE-9273, apache/lucene-solr#1341, 8.6.0) split the code into today's containsLine/containsTriangle with no behaviour change [exec].",
   "introduced_date": "2019-01-31 (LUCENE-8669, narrow form); 2019-04-11 (LUCENE-8736, the wide triangle form every maintained release has); 2020-01-29 (LUCENE-9152, segments)",
   "first_affected_version": "7.7.0 [exec] (and 8.0.0 on the 8.x line) in a narrow form that only fails when the old half-open point-in-polygon rule counts every shape vertex as inside; 8.1.0 [exec] for the wide form on triangles and polygons; 8.5.0 [exec] for segments and lines; 7.5.0 and 7.6.0 (the first releases with shape WITHIN, in lucene-sandbox) are not affected [exec]",
   "affected_versions": "Every release from 7.7.0 to 10.5.2, 10.6.0 (by reading) and main ea57360912ed. [exec] a version-sweep main() with the repro geometry (A) and a second geometry from the grid search (B) on all 66 releases from 7.5.0 to 10.5.2 and on main (-da; pivotal releases also -ea): triangle/polygon WITHIN wrong in every release from 7.7.0 (7.7.0-8.0.0 geometry B only), segment WITHIN wrong in 7.7.0-8.0.0 (B only) and 8.5.0 on, correct in 8.1.0-8.4.1; 7.5.0 and 7.6.0 clean; the finder's JUnit fails 4 of 4 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) and does not compile before 9.1.0; the independent reproduction's JUnit fails 5 of 5 on main (-ea, -da), 10.5.2 and 9.12.3 and its main() port fails on 8.11.4; the intended-behaviour check's and separate tests fail on main and 10.5.2. XYShape exists from 8.2.0 (sandbox; core from 8.5.0). Not fixed upstream: Polygon2D.java is identical on main, branch_10x and branch_10_6 (read 2026-10-26). All runs on aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9782",
    "https://issues.apache.org/jira/browse/LUCENE-8736",
    "https://github.com/apache/lucene/issues/10192",
    "https://issues.apache.org/jira/browse/LUCENE-9152",
    "https://issues.apache.org/jira/browse/LUCENE-8649",
    "https://github.com/apache/lucene/issues/9695"
   ],
   "doc": "",
   "repro": "repro/LFV-206/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-711",
   "priority": "low",
   "priority_rank": 395,
   "novelty": "new",
   "withheld": false,
   "area": "geo / shape queries (Polygon2D.withinTriangle; LatLonShape and XYShape CONTAINS with a query polygon that has holes)",
   "title": "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",
   "summary": "You index polygons with LatLonShape or XYShape and ask which of them CONTAIN a query polygon that has holes, for example a region with two lakes cut out; an indexed polygon whose own hole runs across the land between the two lakes does not cover that land, so it must not match. Polygon2D.withinTriangle rejects an indexed triangle only when one of its vertices is inside the query or one of its real (original-shape) edges crosses the query's outer ring; it never tests the query's hole edges, so an edge that starts and ends inside query holes and crosses the land between them goes unnoticed and the shape is returned as CONTAINS, with no error. Repro: query = the square [0,10]^2 with holes [1,3]x[4,6] and [7,9]x[4,6]; doc 0 = the square [-1,11]^2 with a hole [2,8]x[4.5,5.5] (it does not cover the query point (5,5)), doc 1 = the same square without a hole; CONTAINS returns [0, 1] instead of [1] for XYShape and LatLonShape, while a point query at (5,5) correctly returns only doc 1.",
   "impact_class": "silent wrong results",
   "introduced_commit": "a06a2ea3da28457429b297ca178eaecb1c6c4a58 (branch_8x, shipped in 8.4.0) and 2ef2ddd77c59bceb4704e1e091653a8ae42e4139 (the same change on the then-master branch, identical Polygon2D.java, first released in 9.0.0): LUCENE-8620 'Add CONTAINS support for LatLonShape and XYShape', apache/lucene-solr#872 (supersedes #608; issue now apache/lucene#9666), author iverase [read]. The method was written together with the CONTAINS relation and has tested original-shape edges only against the outer-ring EdgeTree ('tree') from its first version; it never consults the 'holes' component, so this is not a regression and there is no earlier correct state to bisect against (8.3.1 has no CONTAINS relation [exec]). Later edits never touched hole handling: LUCENE-9152 (29542c7f59e, 8.5.0: includeBoundary=true), LUCENE-9273 (f914e08b364 / a001f135f22, 8.6.0: parameter renames, degenerate triangles moved to withinLine/withinPoint), LUCENE-9570 (2d6ad2fee6d, reformatting); LUCENE-10514 (9.2.0) changed withinLine, not withinTriangle [read].",
   "introduced_date": "2019-12-11",
   "first_affected_version": "8.4.0 [exec] (in 8.4.x the LatLonShape/XYShape/QueryRelation API was in the lucene-sandbox module while Polygon2D was in lucene-core; LUCENE-8621 moved the shape API to core in 8.5.0); 8.3.1 cannot express the query (no CONTAINS relation, no Component2D) [exec]",
   "affected_versions": "Every release from 8.4.0 to 10.5.2 (54 releases) and main a9779ef3c193; no earlier release has CONTAINS. [exec] the follow-up's history probe (public API: an INTERSECTS sanity check at (5,5), a CONTAINS control with the hole-less square [4,6]^2, which is a subset of the query, and the two-hole CONTAINS query) and the finder's main() port on all 54 SHA-1-checked release jars from 8.4.0 to 10.5.2 (-ea) and on main (-ea and -da): every run returns CONTAINS=[0, 1] (expected [1]) for XYShape and LatLonShape while the sanity check and the control are correct; 8.3.1 fails to compile on QueryRelation.CONTAINS; with the fix shadowed main returns [1]. The finder's JUnit fails 2 of 2 on main (-ea and -da), 10.5.2, 10.0.0, 9.12.3 and 9.1.0; the independent reproduction's test fails 3 of 3 on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's probe fails 4 of 5 on main (-ea and -da) and 10.5.2. Not fixed upstream: Polygon2D.java last changed on upstream main on 2023-10-10 (de3b294be44, formatting only) and none of the 409 open apache/lucene PRs touches it (checked 2026-10-27). Release branches after 10.5.2 were not checked in the hunt; the bug doc's check of 2026-10-28 finds Polygon2D.java byte-identical on branch_10_6, from which 10.6.0 was released on 2026-10-29, so 10.6.0 is affected too [read]. All runs with JDK 25 on aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-711.html",
   "repro": "repro/LFV-711/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-573",
   "priority": "low",
   "priority_rank": 396,
   "novelty": "new",
   "withheld": false,
   "area": "core / geo distance queries (GeoUtils.distanceQuerySortKey, shared by LatLonPoint, LatLonDocValuesField and LatLonShape circle queries)",
   "title": "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)",
   "summary": "You index points with LatLonPoint (or LatLonDocValuesField or LatLonShape) and run a distance query whose radius is exactly a point's distance from the center as Lucene computes it (SloppyMath.haversinMeters, the same value a distance sort or LatLonPoint.nearest reports), and expect that point to match, because the query matches 'points within the specified distance' and Lucene's own test oracle is haversinMeters(center, point) <= radius; with the radius one ulp smaller you expect it not to match. Instead the point is often missing in the first case and often still matches in the second (each in roughly a fifth to a third of random cases, depending on the points): for example, two points that both the distance sort and haversinMeters put 8154434.476304402 m apart are not matched by any of the three distance queries with exactly that radius. The cause is GeoUtils.distanceQuerySortKey, which turns the radius into a sort-key threshold by binary search: it returns the first key it meets whose distance equals the radius, not the largest such key, so a point on a larger key of the same distance fails 'key <= threshold', and when no key has exactly that distance it returns the smallest key whose distance exceeds the radius.",
   "impact_class": "silent wrong results",
   "introduced_commit": "2335a458d8340bbb8e4fe8133a74763bd2d37fd1 (master, 2016-04-13, LUCENE-7215 'don't invoke full haversin for LatLonPoint.newDistanceQuery' by @rmuir, migrated as apache/lucene#8270; JIRA patch era, no pull request; CHANGES 'Optimizations') and its branch_6x backport 87069500fb2e56b4ceabadb8bb866be39e4269fb (the one that shipped first, in 6.1.0). It replaced the exact per-document check SloppyMath.haversinMeters(...) <= radiusMeters with haversinSortKey(...) <= sortKey(radiusMeters), where sortKey is the binary search that is still GeoUtils.distanceQuerySortKey. Later commits changed no logic: fb3480b8071 / fc68bd90e6fa (LUCENE-7343, 6.2.0) moved it into core GeoUtils, 2d6ad2fee6d (LUCENE-9570) reformatted the javadoc [read]",
   "introduced_date": "2016-04-13",
   "first_affected_version": "6.1.0 [exec] (last unaffected 6.0.1 [exec]; the 6.0.x maintenance branch never received LUCENE-7215). LatLonPoint was in lucene-sandbox until 7.4.x and is in core since 7.5.0; the LatLonDocValuesField distance query is affected from its first release (6.5.0) and the LatLonShape circle query from its first release (8.5.0) [exec]",
   "affected_versions": "every release from 6.1.0 through 10.6.0 (10.6.0 by reading), and main ea57360912ed. [exec] version-independent main() program (10 centers x 400 points quantized by each version's own encoder, radius d and nextDown(d), 8,000 queries per factory, -da, seed DEADBEEF): 6.0.0 and 6.0.1 pass 0 of 8,000; 6.1.0, 6.4.2, 6.5.0, 6.6.6, 7.4.0, 7.5.0, 7.7.3, 8.4.1, 8.5.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main fail with 1023 false negatives and 897 false positives for every factory the version has (8.5.0 shape circles: 81 and 26 of 686 run, because Circle rejected radii above 3,185,504 m until 8.8.0), every mismatch explained by the version's own threshold function; 0 and 0 with the fix on 6.1.0 and main. The finder's JUnit fails 2 of 2 on main (-ea and -da), 10.5.2 and 9.12.3; its reduced LatLonPoint-only JUnit fails 2 of 2 on 9.0.0, 8.11.2, 8.11.4, 7.7.3, 6.6.6 and 6.1.0 and passes on 6.0.1 (6.x with the junitcore runner); the independent reproduction's JUnit fails 3 of 3 on main, 10.5.2 and 9.12.3 (-ea and -da). On main the finder's harness also executed IndexOrDocValuesQuery, LatLonShape WITHIN and DISJOINT, LatLonPoint.newGeometryQuery with circles and LatLonDocValuesField.newSlowGeometryQuery with a circle (all affected; in releases only the three main factories were run). [read] the lucene-spatial GeoPointDistanceQuery of 6.2-6.6 used the same method (not executed). Not fixed upstream: the method body is unchanged since 2016 and no open PR touches it. Executed on aarch64 with JDK 25 only (pure Java double arithmetic)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-573.html",
   "repro": "repro/LFV-573/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-767",
   "priority": "low",
   "priority_rank": 397,
   "novelty": "known",
   "withheld": false,
   "area": "geo / XYShape circle queries (XYRectangle.fromPointDistance, Circle2D.CartesianDistance)",
   "title": "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",
   "summary": "You index an XYShape line that passes just inside a circle and search with XYShape.newDistanceQuery (INTERSECTS) for an XYCircle whose centre coordinate is large compared with the radius, for example centre (2^23, 2^23+1), radius 1.3 and the segment (2^23+1, 2^23)-(2^23+2, 2^23+3), which passes 1.265 from the centre, expecting the hit you get for the same shapes moved exactly to the origin. Instead INTERSECTS finds nothing and DISJOINT matches the document, because XYRectangle.fromPointDistance builds the circle's bounding box as x + nextUp(r) in float, which rounds to nearest (2^23 + 1.3 becomes 2^23 + 1), and since 8.6.0 Circle2D's Cartesian contains() rejects every point outside that too-small box before its exact distance test, including the segment's closest point to the centre. The same box makes CONTAINS report that a polygon contains a circle that sticks out of it.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f914e08b3647ad91eb97ada6ebefe1e96ebd5a89 (main; LUCENE-9273 'Speed up geometry queries by specialising Component2D spatial operations', Ignacio Vera, apache/lucene-solr#1341, migrated issue apache/lucene#10313, 2020-04-20; branch_8x a001f135f229, CHANGES 8.6.0 'Optimizations') added the rectangle pre-check to Circle2D.CartesianDistance.contains, which turned the inward-rounded box into wrong query results; the box itself comes from c653c04bb1717f9813e50d2fd2cef1d323ee6036 (main; LUCENE-9243 'Add fudge factor when creating a bounding box of a xycircle', same author, apache/lucene-solr#1278, migrated issue apache/lucene#10283, 2020-03-02; branch_8x d9787406f895, CHANGES 8.5.0 'Bug Fixes'), which added XYRectangle.fromPointDistance (float x +/- Math.nextUp(radius), rounded to nearest) and made CartesianDistance use it instead of its own double box from LUCENE-8707 (d48bafb2999, 8.5.0) [exec]",
   "introduced_date": "2020-04-20 (LUCENE-9273, the pre-check that makes the box decisive for shape queries); the inward-rounding box 2020-03-02 (LUCENE-9243)",
   "first_affected_version": "8.6.0 [exec] (8.5.0, 8.5.1 and 8.5.2 pass the finder's query tests [exec]: they already have the inward box, visible only through the circle's Component2D bounds (the independent reproduction's box test fails on 8.5.0 and 8.5.2 [exec]), but not the contains() pre-check; 8.6.0 with only that pre-check reverted passes [exec]; XYCircle and XYShape.newDistanceQuery do not exist before 8.5.0, 8.4.1 does not compile the repro [exec])",
   "affected_versions": "Every release from 8.6.0 to 10.5.2 (49 releases: 8.6.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2) and main a9779ef3c193; never fixed. [exec] the finder's JUnit fails the same 4 of 6 tests on all 49 releases (-ea; the 8.x port repro/src-8x for 8.x and 9.0.0) and on main with -ea and -da, the two origin controls passing everywhere; the independent reproduction's independent JUnit fails 4 of 6 on main (-ea, -da), 10.5.2, 9.12.3, 8.6.3 and 8.6.0. Latent only on 8.5.0-8.5.2 (the box is smaller than the circle through the Component2D bounds, no wrong query result found). [read] XYRectangle.fromPointDistance and CartesianDistance.contains are unchanged on upstream main f7bcc0abd816, branch_10x and branch_10_5 (not executed), and no open apache/lucene PR touches XYRectangle.java or Circle2D.java. All runs on aarch64 with JDK 25.0.3; pure Java float arithmetic.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/10283",
    "https://issues.apache.org/jira/browse/LUCENE-9243",
    "https://github.com/apache/lucene-solr/pull/1278",
    "https://github.com/apache/lucene/issues/10313",
    "https://issues.apache.org/jira/browse/LUCENE-9273",
    "https://github.com/apache/lucene/issues/10909"
   ],
   "doc": "",
   "repro": "repro/LFV-767/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-274",
   "priority": "low",
   "priority_rank": 398,
   "novelty": "new",
   "withheld": false,
   "area": "spatial3d / geom outside distance (Plane.arcDistance and Plane.linearDistance behind GeoStandardCircle and GeoExactCircle computeOutsideDistance; user-facing Geo3DDocValuesField.newOutsideDistanceSort via Geo3DPointOutsideDistanceComparator)",
   "title": "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",
   "summary": "You build a 1 km circle on the default WGS84 planet model (GeoCircleFactory.makeGeoCircle, or Geo3DDocValuesField.newOutsideDistanceSort with maxRadiusMeters 1000) and ask for the outside distance of points 3 km from the centre, expecting about 2 km in every direction (0.0 inside, distance to the edge outside). Instead computeOutsideDistance returns +Infinity at 10 of 12 bearings (only due north and due south are right), and the sort gives most documents outside the circle +Infinity, the value the javadoc reserves for documents missing the field, so they sort last. The cause: Plane.arcDistance and Plane.linearDistance look for the nearest edge point on the line where the circle's plane meets a plane through the origin, the plane normal and the point; on a sphere that line passes through the circle's centre, but on an ellipsoid the circle plane's normal is tilted, the line passes about 21 km from the circle at latitude 40, and for a smaller circle it finds no edge point at all, so the minimum keeps its +Infinity start value.",
   "impact_class": "silent wrong results",
   "introduced_commit": "688c67f8ff22b72b9df4ed2f92d26b909563b2b1 (lucene/dev/trunk svn r1688545, 2015-07-01, 'LUCENE-6578: Geo3D: compute the distance from a point to a shape.', patch by DaddyWri, committed by dsmiley; JIRA patch, no pull request; LUCENE-6578 is apache/lucene#7636) added GeoOutsideDistance, DistanceStyle, GeoCircle.outsideDistance and Plane.arcDistance/linearDistance with perpPlane = (n x p, D=0) and a minimum initialised to the sentinel; 5.3.0 shipped its branch_5x backport 780e4040238713c2ff85c4b981cbc6b80aa4094f (svn r1688546, same day); precondition LUCENE-6544 (#7602, trunk 03408382767770c8 / branch_5x 226f69dd68b, 2015-06-18, also first in 5.3.0) builds the circle's cut plane through the meridian points at latitude +/- radius, which tilts its normal on an ellipsoid; later: LUCENE-7288 (#8343, 2016-05-18, 6.1.0) changed the sentinel from Double.MAX_VALUE to +Infinity, LUCENE-7212 (#8267, cc263413457 / branch_6x aa339a2f075, 2016-05-18, 6.1.0) added newOutsideDistanceSort, LUCENE-7970 (#9019, 2c79710618e, 2017-09-25, 7.1.0) added GeoExactCircle, whose outsideDistance reuses Plane.arcDistance per slice; not a regression: present since the API was created [read]",
   "introduced_date": "2015-07-01 (LUCENE-6578: outside distance and Plane.arcDistance); 2016-05-18 (LUCENE-7212: Geo3DDocValuesField.newOutsideDistanceSort)",
   "first_affected_version": "5.3.0 [exec] (release tag 2015-08-20; the first release with GeoOutsideDistance and Plane.arcDistance; fails with -ea and -da: 10 of 12 bearings return the then-sentinel Double.MAX_VALUE, bearings 0 and 180 give 2000.0 m; the SPHERE and 500 km controls pass); 6.1.0 [exec] for the user-facing Geo3DDocValuesField.newOutsideDistanceSort (10 of 12 documents 21 km out sort with +Infinity); 5.2.1 and earlier have no outside-distance API [exec]",
   "affected_versions": "every release from 5.3.0 through 10.5.2 (the last 10.x release before 10.6.0, which was not checked; 9.12.3 is the latest 9.x) and main ea57360912ed. [exec] a version-portable geometry main() (WGS84 1 km circle at 40N 74W, 12 points 3 km out) fails with 10 of 12 bearings wrong on 5.3.0 (-ea and -da), 5.3.2, 5.4.0, 5.5.5, 6.0.0, 6.1.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); an end-to-end sort main() (12 documents 21 km out) fails with 10 of 12 +Infinity on 6.1.0, 6.6.6, 7.7.3, 8.4.1, 8.5.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main; the finder's JUnit fails on main (-ea, -da), 10.5.2, 9.12.3 and 9.4.2; the independent reproduction's JUnit on main (-ea, -da, two seeds), 10.5.2 and 9.12.3; the intended-behaviour check's probe on main (-ea, -da) and 10.5.2. [read] git log -L on Plane.arcDistance shows only LUCENE-6578, LUCENE-7288 (sentinel) and LUCENE-9570 (reformatting), and the cut-plane construction has gone through the meridian points since LUCENE-6544; unexecuted intermediate releases are inferred. Symptom value: Double.MAX_VALUE in 5.3.0-6.0.x, +Infinity from 6.1.0. GeoExactCircle (7.1.0 on) fails on main and 10.5.2 [exec]; its history was not executed. Not fixed on main; no open PR touches the fix site. All runs with JDK 25.0.3 on an aarch64 host.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-274.html",
   "repro": "repro/LFV-274/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-735",
   "priority": "low",
   "priority_rank": 399,
   "novelty": "new",
   "withheld": false,
   "area": "spatial3d / geom path outside distance (GeoStandardPath segment endpoints; Geo3DDocValuesField.newOutsidePathSort)",
   "title": "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",
   "summary": "You build a path with a width (GeoPathFactory.makeGeoPath, or the pathWidthMeters of Geo3DDocValuesField.newOutsidePathSort) and ask for the outside distance of a point beyond one of its ends, expecting 'the distance from a point to the closest outside edge' (GeoOutsideDistance), which is how the same path measures points beside its segments and how GeoCircle measures a circle. Instead you get the distance to the path's end point, i.e. the gap plus up to the half-width: on the unit sphere a point 0.001 rad beyond the end of a path of half-width 0.01 gets 0.011, a one-point path reports 0.011 where the same-size GeoCircle reports 0.001, the value jumps from 0 to about the half-width as a point crosses the end cap's edge, and on WGS84 the outside-path sort ranks a document 1 km beyond the end of a path of half-width 5 km (5992 m) after one 3 km beside it (3067 m). The cause is BaseSegmentEndpoint.outsideDistance, which every endpoint with a width inherits: it measures to the end point itself, which is the edge only for a zero-width path.",
   "impact_class": "silent wrong results",
   "introduced_commit": "688c67f8ff22b72b9df4ed2f92d26b909563b2b1 on trunk (svn r1688545) and its branch_5x backport 780e4040238713c2ff85c4b981cbc6b80aa4094f (svn r1688546), 'LUCENE-6578: Geo3D: compute the distance from a point to a shape.' (JIRA LUCENE-6578, now apache/lucene#7636, opened by DaddyWri (Karl Wright), who wrote the patches, with a revision by and committed by dsmiley (David Smiley); svn era, no pull request). The commit created GeoOutsideDistance and DistanceStyle and gave GeoPath an outside distance in which SegmentEndpoint.outsideDistance returned computeDistance(this.point, x, y, z), the distance to the end point, while PathSegment and GeoCircle in the same commit measured to their edges. Later commits changed the line's form, not its value (LUCENE-7942 added toAggregationForm in 7.1.0; LUCENE-8696, #9742, moved it into BaseSegmentEndpoint, from which the circle endpoint classes inherit it, in 7.7.2 and 8.1.0; the #11965 refactor kept it in 9.5.0). [read]",
   "introduced_date": "2015-07-01 (trunk 02:03:43Z, branch_5x backport 02:16:55Z)",
   "first_affected_version": "5.3.0 [exec] (tag dated 2015-08-20), the first release with the outside-distance API; 5.2.1, the last release before, has no such API [exec]. The user-facing Geo3DDocValuesField.newOutsidePathSort (LUCENE-7212, apache/lucene#8267) is wrong from its first release, 6.1.0 [exec]; 6.0.1 has no Geo3DDocValuesField [exec]",
   "affected_versions": "every release from 5.3.0 through 10.5.2 (the last release before 10.6.0), 10.6.0 (by reading) and main [read]. Executed with version-specific public-API main() probes (-ea), all failing with identical values while their beside-the-segment control passes: 5.3.0, 5.4.0, 5.5.5, 6.0.0, 6.1.0, 6.6.6, 7.7.1, 7.7.2, 7.7.3, 8.0.0, 8.1.0, 8.11.4, 9.0.0, 9.4.2, 9.5.0, 9.12.3, 10.0.0, 10.5.2 and main a9779ef3c193; the outside-path sort probe misorders on 6.1.0 and 7.7.3; the finder's JUnit fails 3 of 3 on 9.12.3, 10.5.2 and main (-ea and -da on main). branch_10_6 (10.6.0, released 2026-10-29), the unreleased branch_10x and upstream origin/main a95c754ee00 have the same code [read]. Not affected: releases before 5.3.0 (no API). Never fixed and never a regression: no version measured end caps to their edge. All runs on JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-735.html",
   "repro": "repro/LFV-735/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-782",
   "priority": "low",
   "priority_rank": 400,
   "novelty": "new",
   "withheld": false,
   "area": "spatial3d / geom polar rectangles outside distance (GeoNorthRectangle, GeoSouthRectangle) and the Geo3DDocValuesField outside-box sort",
   "title": "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",
   "summary": "You sort documents by their outside distance from a lat/lon box that reaches the North Pole, for example latitude 60..90 x longitude -10..10, with Geo3DDocValuesField.newOutsideBoxSort. A document at (80, 180) is only 10 degrees (about 1,112 km) from that box, because the box contains the pole, so it should sort before a document at (35, 0), which is 25 degrees south of the box. Instead GeoNorthRectangle.outsideDistance never considers the pole, where both side edges of the box end, and returns the distance to a far corner (39.88 degrees on the sphere; 4,434,716 m against 2,779,879 m in the WGS84 sort), so the nearer document sorts last; GeoSouthRectangle has the mirror bug at the South Pole.",
   "impact_class": "silent wrong results",
   "introduced_commit": "688c67f8ff22b72b9df4ed2f92d26b909563b2b1 (trunk, svn r1688545, 2015-07-01, 'LUCENE-6578: Geo3D: compute the distance from a point to a shape.', committed by GitHub dsmiley; issue LUCENE-6578, now apache/lucene#7636; SVN/JIRA era, no PR), released through the branch_5x backport 780e4040238713c2ff85c4b981cbc6b80aa4094f (svn r1688546, in 5.3.0) [read] [exec]. Not a regression. The user-facing sort came later with the bug from its first release: Geo3DDocValuesField.newOutsideBoxSort, LUCENE-7212 (trunk cc263413457, branch_6x aa339a2f075, 2016-05-18, apache/lucene#8267)",
   "introduced_date": "2015-07-01 (trunk 688c67f8ff2 and branch_5x backport 780e4040238); the outside-box sort API on 2016-05-18 (LUCENE-7212)",
   "first_affected_version": "5.3.0 [exec] for the geom API (GeoBBoxFactory.makeGeoBBox(...).computeOutsideDistance); 5.2.1, the release before, has no outside-distance API [exec]. 6.1.0 [exec] for Geo3DDocValuesField.newOutsideBoxSort (6.0.1 has no Geo3DDocValuesField [exec])",
   "affected_versions": "Every release from 5.3.0 to 10.5.2 and main a9779ef3c193; not fixed upstream. [exec] the shape test (SPHERE 39.882280145867114 degrees instead of 10, north and south) fails 3 of 3 on 5.3.0, 5.3.2, 5.5.5, 6.0.0, 6.0.1, 6.1.0, 9.12.3, 10.5.2 and main; the sort test fails 3 of 3 on 6.1.0, 6.6.6, 7.7.3, 8.5.0, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main (-ea and -da); with the pole term shadowed in, 5.3.0 and main pass; the independent reproduction's own JUnit fails 5 of 7 (its 2 controls pass) on main (-ea, -da), 10.5.2 and 9.12.3. [read] git tag --contains: 780e4040238 is in all 11 releases 5.3.0-5.5.5 and 688c67f8ff2 in the 83 release tags 6.0.0-10.5.2; GeoNorthRectangle.java and GeoSouthRectangle.java at a9779ef3c193 are byte-identical to the study base 7cecf795236, and lucene/spatial3d is unchanged between ea57360912ed and a9779ef3c193 (git diff --stat empty). All runs on JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-782.html",
   "repro": "repro/LFV-782/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-378",
   "priority": "low",
   "priority_rank": 401,
   "novelty": "known",
   "withheld": false,
   "area": "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)",
   "title": "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",
   "summary": "You create a circle and a box (or a second circle) that touch at exactly one point, for example with the Geo3d spatial context a 20-degree circle centred at latitude 55 and a box whose southern edge is latitude 75, and expect relate() to report INTERSECTS (shapes that share a point intersect, and spatial3d may only weaken WITHIN to OVERLAPS, never the reverse). Instead it reports WITHIN or CONTAINS, as if one shape were inside the other: GeoBaseAreaShape.getRelationship infers nesting from sampled edge points plus a plane-intersection test, a standard circle has a single edge point, and when that point lies on the other shape's boundary the 1e-12 membership test counts it as inside while Plane.intersects' one-solution test misses the touch. So SerializedDVStrategy's IsWithin(box) returns the circle although its centre is 20 degrees outside the box, while radius 19.9 or 20.1 degrees gives the correct DISJOINT or INTERSECTS.",
   "impact_class": "silent wrong results",
   "introduced_commit": "1242bf1519ca7dd630164f6586f6e2307ad04fe5 (lucene6196 feature branch, svn r1675374, 'LUCENE-6196: committing Karl's latest patch', review r/33353 diff #9; patch by GitHub DaddyWri, committed by GitHub dsmiley; no pull request (JIRA era; LUCENE-6196 is apache/lucene#7258)) [exec]. The commit moved the circle's single edge point onto the centre's meridian ('Move from center only in latitude'), the point that round-number tangency hits; the nesting rule (all edge points inside and no plane intersection gives WITHIN) came two days earlier in c3a4ee1c3b1 (GeoBBoxBase.isShapeInsideBBox), when the edge point was still a rotated sample point, and the initial check-in bde056c7632 decided WITHIN from an interior point. The paths of the finder's repro came later [read]: LUCENE-7906 (#8955; 39d6be4ecc4 on master, df220799ce8 on branch_7x, 2017-08-03; the commit message says LUCENE-7606 by mistake) put the same rule into GeoBaseAreaShape.getRelationship for any pair of shapes (circle vs circle), and LUCENE-7951 (#9000; 035523ba7a8 / 85491401d54, 2017-09-20) added the Geo3d spatial4j context and the binary codec SerializedDVStrategy needs; both first released in 7.1.0. Present since Geo3d first shipped, so not a regression",
   "introduced_date": "2015-04-22 (feature-branch commit 1242bf1519c); merged 2015-05-06 into branch_5x (536ae683ff6, svn r1678007, released in 5.2.0) and trunk (f760a51f80d, svn r1678005, released in 6.0.0); the Geo3d-context paths 2017-08-03 (LUCENE-7906) and 2017-09-20 (LUCENE-7951)",
   "first_affected_version": "5.2.0 [exec] (the first release with Geo3d: spatial3d GeoBBox.getRelationship and the then spatial-extras Geo3dShape adapter against a spatial4j Rectangle give WITHIN at the tangent radius; 5.1.0 has no Geo3d, the probe does not compile); for the paths of the finder's repro (Geo3d spatial context, circle vs circle, SerializedDVStrategy IsWithin) 7.1.0 [exec]",
   "affected_versions": "Every release from 5.2.0 to 10.6.0 (10.6.0 by reading) and main ea57360912ed, by sampling plus blame; not fixed upstream. [exec] spatial3d probe with a dateline-crossing polar box: 5.2.0, 5.3.0, 5.4.0, 5.5.5, 6.0.0, 6.6.6, 7.0.1, 7.1.0, 9.12.3, 10.5.2 and main fail (radius 19.9 / 20.0 / 20.1 degrees: DISJOINT / WITHIN / OVERLAPS), 5.1.0 has no such API; the same with an ordinary box: 5.2.0, 7.0.1, 7.1.0, 9.12.3, 10.5.2 and main fail; the pre-7.1 spatial-extras adapter against a spatial4j Rectangle: 5.2.0, 6.0.0, 6.6.6 and 7.0.1 fail (DISJOINT / WITHIN / INTERSECTS); the finder's JUnit: 7.1.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) fail 3 of 3, 7.0.1 does not compile; the independent reproduction's JUnit fails 4 of 5 (its control passes) on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's JUnit fails 2 of 2 on main (-ea and -da), 10.5.2 and 9.12.3; the security probe fails its 3 fail-open tests (of 7) on main (-ea and -da), 10.5.2 and 9.12.3. [read] The decisive lines are unchanged except for reformatting: GeoBaseAreaShape.getRelationship from 39d6be4ecc4 (2017) plus the later planet-model check 94b695e672b, Plane's tangency branch from 9dcef8c8c3d3 (2015), GeoStandardCircle's single edge point (2015 code); no change to the involved files on upstream main cf398bfb142c, branch_10x or branch_10_6 (read 2026-10-26), and no open PR changes them. Before 7.1 only box vs circle was reachable (a circle was not a GeoArea); index-level effects on releases before 7.1 were not tested",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/8990",
    "https://issues.apache.org/jira/browse/LUCENE-7941",
    "https://github.com/apache/lucene/issues/8955",
    "https://issues.apache.org/jira/browse/LUCENE-7906",
    "https://github.com/apache/lucene/issues/12295",
    "https://issues.apache.org/jira/browse/LUCENE-8056"
   ],
   "doc": "",
   "repro": "repro/LFV-378/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-611",
   "priority": "low",
   "priority_rank": 402,
   "novelty": "new",
   "withheld": false,
   "area": "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)",
   "title": "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",
   "summary": "You take a geo3d box whose east edge is near the dateline, for example longitudes [2.5, 3.0] radians, and call expand(0.3), or in a Geo3D spatial context you search 'Intersects(BUFFER(ENVELOPE(172, 178, 4, -4), 4))'. You expect each bound to move out by the angle, so the box now crosses the dateline and reaches -2.983 radians (-178 degrees), as the same code already does for a box that crosses the dateline and as spatial4j's own geo rectangle buffer does. Instead expand passes the unwrapped bound 3.3 to GeoBBoxFactory.makeGeoBBox, which clamps it to PI, so the box stops at 180 degrees and a document at (-179.5, 1) is not found (0 hits instead of 1); the west edge and all 13 GeoBBox classes with a longitude range behave the same way.",
   "impact_class": "silent wrong results",
   "introduced_commit": "bde056c763231cd4f35acbc708cfc07dc181b1fc ('LUCENE-6196: Geo3d initial checkin', svn r1673165 on the lucene6196 feature branch; patch by GitHub DaddyWri, committed by GitHub dsmiley; no pull request (JIRA era; LUCENE-6196 is apache/lucene#7258)). It already has both halves: GeoRectangle, GeoWideRectangle, GeoLongitudeSlice and GeoWideLongitudeSlice compute newLeftLon = leftLon - angle and newRightLon = rightLon + angle, special-case only the full-world span and pass the unwrapped values on, and GeoBBoxFactory.makeGeoBBox clamps leftLon < -PI to -PI and rightLon > PI to PI. The other 9 classes got the same pattern on the same branch (400c39bac77, 2015-04-15; 1242bf1519c, 2015-04-22); the branch was merged into trunk as f760a51f80d and into branch_5x as 536ae683ff6 (2015-05-06). [read] The spatial-extras path came with LUCENE-7951 (#9000; 035523ba7a8 on master, 85491401d54 on branch_7x, 2017-09-20), which added Geo3dRectangleShape.getBuffered = shape.expand(...) and did not change expand. Not a regression: the logic is unchanged since (later edits are reformatting only, 55d46dc6d37 and the LUCENE-9570 reformat 2cbf261032d).",
   "introduced_date": "2015-04-13 (lucene6196 feature branch); merged into trunk and branch_5x 2015-05-06; spatial-extras path 2017-09-20 (LUCENE-7951)",
   "first_affected_version": "5.2.0 [exec] (the first release with geo3d: a main() port in its package, unit sphere only, fails both dateline checks while its away-from-dateline control passes; 5.1.0 has no geo3d, the port does not compile). For the spatial-extras path (Geo3dRectangleShape.getBuffered, WKT BUFFER in a Geo3D context): 7.1.0 [exec]; 7.0.0 has no Geo3dSpatialContextFactory, and before 7.1.0 Geo3dShape.getBuffered returned the shape itself (5.2.x) or threw UnsupportedOperationException (5.3.0-7.0.0) [read]",
   "affected_versions": "Every release from 5.2.0 through 10.6.0 (10.6.0 by reading) and main a9779ef3c193; not fixed upstream (upstream main a95c754ee00 has no later commit touching spatial3d geom or Geo3dRectangleShape, and no open PR changes those files). [exec] the finder's checks fail on 5.2.0, 5.2.1, 5.3.0 and 5.5.5 (main() ports: 2 dateline checks fail, the control passes), 6.0.0, 6.6.6 and 7.0.0 (JUnit: 2 of 3 fail, no getBuffered test before 7.1.0), 7.1.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main with -ea and -da (3 of 4 fail; the away-from-dateline control passes); the independent reproduction's JUnit fails 7 of 12 (its 5 controls pass) on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's probes fail on main (-ea and -da) and 10.5.2; the security probe fails 7 of 10 on main (-ea and -da) and 10.5.2. [read] every release tag in the history clone from 5.2.0 to 8.8.1 and from 9.0.0 to 10.5.2 has the unwrapped bound and the clamp; the 8.9.0-8.11.x tags are not in the clone (8.11.4 was executed). branch_10x and branch_10_6 were not checked in this step; the doc's fact check (2026-10-28) read the same code on both, so 10.6.0 has it.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-611.html",
   "repro": "repro/LFV-611/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-614",
   "priority": "low",
   "priority_rank": 403,
   "novelty": "new",
   "withheld": false,
   "area": "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)",
   "title": "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",
   "summary": "You build a geo3d box whose top and bottom latitude are equal and which spans all longitudes, for example GeoBBoxFactory.makeGeoBBox(WGS84, 0.5, 0.5, -PI, PI), and expect it to contain exactly the points on that latitude, as the same line over [-179, 179] degrees does. Its isWithin compares a point's z with sin(latitude), the unit-sphere value, with a 1e-10 tolerance, instead of the planet-model plane that the class builds and uses everywhere else, so on WGS84 it rejects every point on its own latitude (and accepts a parallel about 1.2 km away). On any planet model, including the default sphere of the Geo3D spatial context, the 100x looser tolerance makes getRelationship report that the line CONTAINS a rectangle just below it, so a prefix-tree Intersects query for rect(-180, 180, 45.000000001, 45.000000001) matched 4 points at latitudes 10, 10, 30 and 44 degrees, while the [-179, 179] control matched none.",
   "impact_class": "silent wrong results",
   "introduced_commit": "1242bf1519ca (LUCENE-6196 'Include geo3d package, along with Lucene integration to make it useful', issue #7258; commit message 'committing Karl's latest patch ... r/33353 (diff #9)', a patch by DaddyWri committed by dsmiley on the svn branch lucene6196 r1675374; reached trunk through f760a51f80d and branch_5x through 536ae683ff6; svn era, no PR) wrote the isWithin line 'Math.abs(z - this.sinLatitude) < 1e-10', replacing the exact 'z == sinLatitude' from the class's creation 400c39bac77 on the same unreleased branch. The WGS84 half comes from 560f3a1a0104 (LUCENE-6487 'Add WGS84 capability to geo3d support', issue #7546; branch lucene6487 r1681907; trunk 77de0ed1cf8, branch_5x 8c3e6b0ed32), which moved the class's plane, interior point, bounds and intersects to the planet model but left isWithin on sin(latitude). [read]",
   "introduced_date": "2015-04-22 (isWithin line, branch commit; merged to trunk and branch_5x 2015-05-06); 2015-05-27 (WGS84 plane change, branch commit; merged 2015-06-02)",
   "first_affected_version": "5.2.0 [exec] (the first release with geo3d; 5.1.0 has no geo3d package, so the check does not compile there). On 5.2.x only the unit sphere exists, so the defect shows as the false CONTAINS and the prefix-tree false matches; the WGS84 false negatives start with 5.3.0 [exec] (planet models, LUCENE-6487)",
   "affected_versions": "5.2.0 to 10.6.0 (10.6.0 by reading) and main a9779ef3c193. [exec] fails on 5.2.0, 5.2.1, 5.3.0, 5.5.5, 6.0.0 and 7.0.1 (version-adapted main() checks with the finder's inputs: SPHERE CONTAINS, 4 prefix-tree false hits against 0 for the control, and from 5.3.0 the WGS84 on-latitude rejection), on 7.7.3 (geometry checks plus the finder's prefix-tree JUnit, 1 of 1), and on 8.11.4, 9.12.3, 10.5.2 and main (geometry checks plus the finder's JUnits, 3 of 3); the independent reproduction's JUnits fail 5 of 5 on main (-ea and -da), 10.5.2 and 9.12.3; the security-reach JUnit fails as expected on main (-ea and -da), 10.5.2 and 9.12.3. Every control passed, and the one-line fix shadowed passes on 5.2.0, 5.3.0 and main. [read] all 96 release tags 5.2.0..10.5.2 in the history clone contain the line (8.8.2..8.11.4 are untagged there; 8.11.4 was executed); branch_10x, branch_10_6 and upstream main a95c754ee003 (2026-10-26) carry the same line. Not fixed upstream.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-614.html",
   "repro": "repro/LFV-614/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-737",
   "priority": "low",
   "priority_rank": 404,
   "novelty": "new",
   "withheld": false,
   "area": "spatial3d / geom exact-circle outside distance (GeoExactCircle.outsideDistance, reached through GeoCircleFactory.makeExactGeoCircle and GeoOutsideDistance.computeOutsideDistance)",
   "title": "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",
   "summary": "You build an exact circle on the default WGS84 planet model (GeoCircleFactory.makeExactGeoCircle, centre latitude 0.3 and longitude 0.2, radius 0.1 rad, about 637 km, accuracy 1e-6) and ask computeOutsideDistance for a point 0.11 rad due north of the centre, expecting 'the distance from a point to the closest outside edge' (GeoOutsideDistance), about 0.0096. Instead you get +Infinity, and the same for every point due north or due south at any distance; on the unit sphere a point 0.001 rad due west of a 1e-4 rad exact circle gets 0.0012, the distance to the far side of the circle. The cause: GeoExactCircle.outsideDistance takes the minimum of each slice's plane distance bounded to that slice's sector and never measures the slice end points, so when the nearest edge point is a joint between two slices, the point's foot on each neighbouring plane falls just outside its sector, both return +Infinity, and the minimum is +Infinity or a foot on the far side.",
   "impact_class": "silent wrong results",
   "introduced_commit": "2c95fa4118c2a19fc385b23a90facc4bd0bf9006 on branch_7x (the same change as 2c79710618e7b6d8b7ecff5dc17cfe7abbd59434 on master, committed the same minute, identical geom package), 'LUCENE-7970: Add an exact version of a circle, which uses Vicenty logic to construct out of planes.' (LUCENE-7970 = apache/lucene#9019, opened by iverase, committed by DaddyWri; no pull request). It added GeoExactCircle with outsideDistance = the minimum of the bounded plane distances and no plane end points [read]. The candidate's own inputs fail only after two construction fixes moved its points onto slice joints [exec]: LUCENE-8054 a7e6df03fc0 (2017-11-21, first released in 7.2.0) for the WGS84 test and LUCENE-8080 f79baa044e4 (2017-12-08, 7.3.0) for the sphere test. Not the cause: the 7.2.0 sector-bounds rework LUCENE-8056 (183d6d67bce) and LUCENE-8066 (d4b7eccda30), which earlier readings of the code had named; they change no probe result [exec].",
   "introduced_date": "2017-09-25 (LUCENE-7970); the trigger commits for the candidate's exact inputs are dated 2017-11-21 (LUCENE-8054) and 2017-12-08 (LUCENE-8080)",
   "first_affected_version": "7.1.0 [exec], the first release with GeoExactCircle: the same WGS84 meridian test at accuracy 1e-4 gives +Infinity for 6 of 6 points with -ea and -da, and adding the stored end points to the 7.1.0 code removes it (the candidate's own inputs pass on 7.1.0, because its exact circle there is built from wrongly interpolated slices; they first fail on 7.2.0 for WGS84 and 7.3.0 for the sphere). 7.0.1 and earlier have no makeExactGeoCircle [exec]",
   "affected_versions": "every release from 7.1.0 through 10.5.2 (the last release before 10.6.0) and main a9779ef3c193. Executed (candidate JUnit, a history JUnit with the accuracy-1e-4 case, and a public-API main() probe): 7.1.0, 7.2.0, 7.2.1, 7.3.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea, and -da on 7.1.0 and main); from 7.3.0 to main the probe output is identical line for line. [read] the others: outsideDistance is unchanged since LUCENE-8071 (6c3869f8b19, 2017-12-01) apart from the LUCENE-9570 reformatting, and the release tags 7.1.0-7.7.3, 8.0.0-8.8.1, 9.0.0-9.12.3 and 10.0.0-10.5.2 contain the introducing commit (8.8.2-8.11.4 are not tags in the history clone; 8.11.4 executed). Upstream origin/main a95c754ee003 has the same code [read]. Not affected: 7.0.1 and earlier (no API). Never fixed. All runs on JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-737.html",
   "repro": "repro/LFV-737/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1014",
   "priority": "low",
   "priority_rank": 405,
   "novelty": "new",
   "withheld": false,
   "area": "core / geo Rectangle (LatLonShape box queries, newGeometryQuery(Rectangle), SimpleWKTShapeParser ENVELOPE)",
   "title": "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",
   "summary": "You build a lat/lon box with the minimum and maximum latitude swapped, for example LatLonShape.newBoxQuery(field, INTERSECTS, 10, 5, 0, 1) or the WKT text ENVELOPE(0, 1, 5, 10), and expect an IllegalArgumentException, as XYRectangle gives for the same mistake and as Rectangle itself gives for an out-of-range latitude. Rectangle's constructor checks the order only with 'assert maxLat >= minLat', so with assertions enabled you get a bare AssertionError, and with assertions disabled the inverted box is accepted. The shape query then matches only shapes that cross both latitude lines (INTERSECTS) or the complement of those (DISJOINT), which is neither the empty result that LatLonPoint.newBoxQuery gives for the same box nor the result of the swapped box.",
   "impact_class": "wrong error",
   "introduced_commit": "dad52a63ce07 (svn r1703879 on the LUCENE-6780 feature branch, by Michael McCandless: 'LUCENE-6780: move GeoBBox -> GeoRect'), which added 'assert maxLat >= minLat' as the only latitude-order check; it reached releases through the merges 09f89f60deb3 (branch_5x, by Nick Knize, 5.4.0) and d369057766ae + 91e6bef3c752 (trunk, by Nick Knize, 6.0.0); git blame of Rectangle.java:94 on main 645d4fe14a20 points to 91e6bef3c752; the constructor body is unchanged since 2016 [read]. No PR (Subversion era); JIRA LUCENE-6780 (apache/lucene#7838) never discusses the check",
   "introduced_date": "2015-09-18 (authored on the feature branch); landed 2015-10-21 on trunk and 2015-10-22 on branch_5x",
   "first_affected_version": "5.4.0, as org.apache.lucene.util.GeoRect in sandbox, already assert-only [exec]; first non-sandbox release 5.5.0 (lucene-spatial); the current core class org.apache.lucene.geo.Rectangle since 6.1.0 (LUCENE-7163), assert carried over unchanged [exec]. 5.3.2 and older have no public lat/lon rectangle class (API absent) [exec]",
   "affected_versions": "main 645d4fe14a20 [exec]; branch_10x 657014b3c579 [exec]; 10.6.0 RC1 4ae946e5a9b [exec]; all 100 releases from 5.4.0 to 10.5.2 on Maven Central [exec]; 10.5.2 and 9.12.3 also [exec]. Upstream main, branch_10x and branch_10_6 heads still have the assert [read]. Trigger paths by version: new GeoRect/Rectangle since 5.4.0; LatLonShape.newBoxQuery since 7.5.0 in sandbox (7.5.0-7.6.0 did not build a Rectangle, so even -ea accepted the box; builds one since 7.7.0, LUCENE-8605; core since 8.5.0); SimpleWKTShapeParser ENVELOPE since 7.6.0 in sandbox (core since 8.5.0). XYRectangle had the same assert-only check in 8.2.0-8.4.1 and throws IllegalArgumentException since 8.5.0 (LUCENE-9218). Not affected: 5.3.2 and older (API absent) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1014.html",
   "repro": "repro/LFV-1014/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-434",
   "priority": "low",
   "priority_rank": 406,
   "novelty": "new",
   "withheld": false,
   "area": "core / document: XYShape queries (XYShape.newLineQuery and newGeometryQuery, XYShapeQuery, Line2D)",
   "title": "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)",
   "summary": "You build XYShape.newLineQuery(field, QueryRelation.WITHIN, line) with a valid XYLine and expect the IllegalArgumentException that LatLonShape.newLineQuery throws for the same relation ('does not support WITHIN queries with line geometries'), and that XYShape itself threw up to 8.4.1 ('XYShapeLineQuery does not support WITHIN queries'). Instead the query is accepted, because the XYShapeQuery constructor has validated nothing since LUCENE-9194 (8.5.0) folded the old XY line query into it. The search then returns indexed points that lie on the line but no indexed line, not even one identical to the query line, because Line2D.containsLine and containsTriangle always return false.",
   "impact_class": "wrong error",
   "introduced_commit": "73dbf6d06108e9f18423521e339230bda37f8524 (master, now main), backported to branch_8x as 5c1f2ca22a756b16f0e35aa5dde221578fe1ce76; both 'LUCENE-9194: Simplify XYShapeXQuery API by adding a new abstract class called XYGeometry' (the commit subject reads 'UCENE-9194') by iverase, PR apache/lucene-solr#1224 (one approval by nknize, no line comments; issue now apache/lucene#10234) [read]. A regression, not born with the feature: XYShapeLineQuery (LUCENE-8632, 0c09481374c, 2019-07-08) documented 'QueryRelation.WITHIN queries are not yet supported' and threw, and one week before LUCENE-9194 the same author carried the identical check into the LatLon twin (LUCENE-9141, a9482911a82, 2020-01-30). The release boundary is executed (8.4.1 rejects, 8.5.0 accepts); no commit-level A/B build was made. LUCENE-9273 (f914e08b364, 2020-04-20, 8.6.0) later made Line2D.containsLine and containsTriangle return false; the observed result is the same before and after it, so it is not the introducing change",
   "introduced_date": "2020-02-07 (author and commit date of 73dbf6d0610 and 5c1f2ca22a7; PR #1224 merged the same day)",
   "first_affected_version": "8.5.0 [exec] (8.2.0 and 8.4.1, where XYShape still lived in the sandbox module, throw IllegalArgumentException 'XYShapeLineQuery does not support WITHIN queries' [exec]; the XYShape API did not exist before 8.2.0 [read]; the move to core, LUCENE-8621, also landed in 8.5.0, so XYShape has been affected for its whole time in core)",
   "affected_versions": "every release from 8.5.0 to 10.5.2, 52 releases (19 on 8.x: 8.5.0-8.11.4; 21 on 9.x: 9.0.0-9.12.3; 12 on 10.x: 10.0.0-10.5.2), 10.6.0 (by reading: branch_10_6 keeps the same XYShapeQuery constructor) and main ea57360912ed (unreleased 11.0) [exec]. Not affected: 8.2.0-8.4.1 (sandbox module, rejects) [exec]; before 8.2.0 the API is absent [read]. Not fixed upstream: upstream main and branch_10x last changed XYShapeQuery.java on 2022-08-09 (d7fd48c9502), and no open apache/lucene PR touches XYShapeQuery.java, XYShape.java, Line2D.java or LatLonShapeQuery.java [read]. All runs on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-434.html",
   "repro": "repro/LFV-434/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1203",
   "priority": "low",
   "priority_rank": 407,
   "novelty": "new",
   "withheld": false,
   "area": "core / document: LatLon point geometry query factories (LatLonPoint.newGeometryQuery CONTAINS shortcut, LatLonDocValuesField.newSlowGeometryQuery)",
   "title": "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)",
   "summary": "You call LatLonPoint.newGeometryQuery(\"f\", QueryRelation.CONTAINS) with no geometries (an empty array), or with an array that holds a null, and expect the IllegalArgumentException its javadoc promises ('if latLonGeometries is null, empty or contain a null'), which INTERSECTS and WITHIN and the doc-values twin LatLonDocValuesField.newSlowGeometryQuery(\"f\", CONTAINS) throw for the empty array ('geometries must not be empty'). Instead you get a query that matches no document: a ConstantScoreQuery over an empty BooleanQuery for the empty array, and MatchNoDocsQuery('Contains LatLonPoint.newGeometryQuery with non-point geometries') for a null element, which newSlowGeometryQuery also returns for a null element. The CONTAINS shortcut runs before any argument check: its loop never runs for an empty array, and a null element fails 'instanceof Point' and lands in the branch meant for valid non-point geometries.",
   "impact_class": "minor",
   "introduced_commit": "14009f4424d847ce84fa23a71d8066dfe6c70da0 'LUCENE-9641: Support for spatial relationships in LatLonPoint (#2155)' by Ignacio Vera (GitHub iverase), apache/lucene-solr#2155, issue LUCENE-9641 = #10680; branch_8x copy f73f6b11f0ed4bcbfce445152d813adb3327d249 (lucene-solr#2188), same day [read]. It added the queryRelation parameter and dispatched CONTAINS to new shortcuts before any validation, removed LatLonPointInGeometryQuery and LatLonDocValuesPointInGeometryQuery (whose constructors had rejected a null or empty array and null elements with IllegalArgumentException), and rewrote the @throws clause, keeping 'latLonGeometries is null, empty or contain a null'",
   "introduced_date": "2021-01-08 (author and commit date 2021-01-08T08:16:58+01:00; branch_8x copy the same day); first release 8.8.0 (tag 2021-01-29)",
   "first_affected_version": "8.8.0 [exec] (8.7.0 has no relation-taking newGeometryQuery, so the repro does not compile there [exec]; LUCENE-9552, which added newGeometryQuery itself, also first shipped in 8.8.0, so no release has the relation-taking factories without the defect)",
   "affected_versions": "Every release from 8.8.0 through 10.6.0 (4ae946e5a9b) and main. Executed and reproduced (the empty-array repro): 8.8.0, 8.8.1, 8.8.2, 8.9.0, 8.10.0, 8.10.1, 8.11.0, 8.11.1, 8.11.2, 8.11.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2, 10.6.0 (-ea and -da) and main 5adff78bb168 (-ea and -da) [exec]; all 34 main-line release tags 9.0.0-10.6.0 and 8.8.0/8.8.1 have the same validation-free newGeometryQuery and makeContainsGeometryQuery bodies, and newSlowGeometryQuery keeps the unchecked CONTAINS loop in every tag from 8.8.0 [read]. The null-element sub-case comes from the same commit [read] and was executed on main only (both factories). Not affected: 8.7.0 and older (no such API; 8.7.0 executed: compile error). Not fixed upstream: upstream main 1c2072f0284 (author date 2026-11-02) still dispatches CONTAINS to makeContainsGeometryQuery before any check [read]. Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1203.html",
   "repro": "repro/LFV-1203/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-316",
   "priority": "low",
   "priority_rank": 408,
   "novelty": "known",
   "withheld": false,
   "area": "spatial-extras / prefix trees (QuadPrefixTree, PackedQuadPrefixTree under RecursivePrefixTreeStrategy)",
   "title": "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)",
   "summary": "You index a point with RecursivePrefixTreeStrategy over a QuadPrefixTree (or PackedQuadPrefixTree) in a non-geo SpatialContext whose world bounds are not powers of two, such as Web Mercator's +/-pi*6378137, and the point lies exactly on a grid line (for example longitude 45 degrees projected, at y = 0) or on the world's east edge. You expect Intersects with that same point, or with a box whose edge passes through it, to find the document, because getCell is documented to return 'the cell containing point p' and the query error may only inflate a shape, never shrink it. Instead getCell chooses the cell by comparing the point with mid-points accumulated one way while QuadCell.makeShape rebuilds that cell's edges another way, the two floating-point results differ by one ulp, so the indexed cell's shape ends just short of the point, the query treats it as disjoint and returns 0 hits (and with the 50-level factory default a query for a point on the world's top edge throws InvalidShapeException).",
   "impact_class": "silent wrong results",
   "introduced_commit": "66a852234d4714bdba9da19b5e3adde2773e0030 (initial import of the spatial module, QuadPrefixTree included, from the lucene-spatial-playground project onto the LUCENE-3795 branch, by GitHub dsmiley; it reached trunk in the merge 2ac613aef9ba 'LUCENE-3795: Replace contrib/spatial with modules/spatial'; Subversion era, no PR) [read]. The current form of getCell comes from 26628b2717a7 (master) / c09ddcb7180c (branch_8x), LUCENE-8755 (#9800), apache/lucene-solr#824 by GitHub chenkovsky, committed by dsmiley, first released in 8.3.0: it replaced one mid-point routing with another (removing the index-time IndexOutOfBoundsException that issue reported) and kept the disagreement with makeShape. Not a regression",
   "introduced_date": "2012-02-20 (66a852234d4, LUCENE-3795 branch); 2012-03-13 (trunk merge 2ac613aef9b); current getCell form 2019-08-07 (authored) / 2019-08-20 (branch_8x commit, LUCENE-8755)",
   "first_affected_version": "4.0.0 [exec]; 3.6.2 has no QuadPrefixTree or prefix-tree strategy [read]",
   "affected_versions": "Every release from 4.0.0 to 10.5.2 and main ea57360912ed (executed on 23 releases plus main). Current form (8.3.0 to main) [exec]: the finder's JUnit fails 6 of 6 on main (-ea and -da), 10.5.2, 10.0.0 and 9.12.3; a portable main() fails all 6 checks with the same 4 missed whole-degree longitudes (-135, 45, 90, 180) on 10.5.2, 10.0.0, 9.12.3, 9.0.0, 8.11.4 and 8.3.0; a 4,097-point grid-line scan gives 784 point-query misses and 664 west-edge-box misses on 8.3.0, 9.12.3, 10.5.2 and main. Pre-8.3 form (4.7.2 to 8.2.0) [exec]: the point query for the finder's point still misses, the east-edge point throws IndexOutOfBoundsException, 6 of 361 whole-degree longitudes miss, and the scan gives 758 point-query misses plus 137 exceptions. 4.0.0 to 4.6.1: root cause at tree level only [exec]. PackedQuadPrefixTree: every release since it was added in 5.2.0 (LUCENE-6422) [exec]. Not fixed upstream: no commit to QuadPrefixTree.java or PackedQuadPrefixTree.java on upstream main after ea57360912ed and no open PR touches them [read]. Not run: 4.0.0-alpha/-beta, x86, unreleased 10.x branches",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9800",
    "https://issues.apache.org/jira/browse/LUCENE-8755",
    "https://github.com/apache/lucene-solr/pull/824",
    "https://issues.apache.org/jira/browse/LUCENE-4978",
    "https://github.com/apache/lucene/issues/6042",
    "https://issues.apache.org/jira/browse/LUCENE-7859"
   ],
   "doc": "",
   "repro": "repro/LFV-316/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-371",
   "priority": "low",
   "priority_rank": 409,
   "novelty": "new",
   "withheld": false,
   "area": "spatial-extras / prefix trees (S2PrefixTree and S2PrefixTreeCell under RecursivePrefixTreeStrategy; Contains through ContainsPrefixTreeQuery)",
   "title": "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",
   "summary": "You index a document with point P through RecursivePrefixTreeStrategy over S2PrefixTree in the Geo3d spatial context and search with SpatialOperation.Contains and the same point P, expecting the document, because Contains is documented as the OGC 'Covers' predicate and its evaluate(P, P) is true, RecursivePrefixTreeStrategy builds a ContainsPrefixTreeQuery for it, a point query is resolved at full precision, and the geohash and quad trees do return the document. When P lies exactly on an S2 cell edge, for example Point(10, 0) on the equator, Contains finds 0 documents while Intersects finds 1. Indexing puts P in one cell per level (S2PrefixTree.getTreeCellIterator, from S2CellId.fromLatLng), but at query time S2PrefixTreeCell.getNextLevelCells has no point case and returns every child cell that touches P (2 on an edge, 4 at (0,0)), and ContainsPrefixTreeQuery requires the document to be in all of them.",
   "impact_class": "silent wrong results",
   "introduced_commit": "e3032dd3fcc28570c5f9d2dab4961b5b07555912 (master, first released in 8.0.0) and its branch_7x backport 1e86af061e41f1a7df1740f34ef58a1110626d96 (identical prefix/tree sources; the copy that shipped first, in 7.3.0), 'LUCENE-8126: New spatial prefix tree (SPT) based on google S2 geometry' (GitHub issue #9174; review PR apache/lucene-solr#302, closed without a GitHub merge and committed directly), by GitHub iverase [read]. Both halves of the mismatch (the query side without a point case and the one-cell-per-level index side) come from this commit; ContainsPrefixTreeQuery (LUCENE-4645, 8b573c413d4, 2013) and LegacyCell's point special case predate it. Not a regression",
   "introduced_date": "2018-03-02 (master e3032dd3fcc2 and branch_7x 1e86af061e41)",
   "first_affected_version": "7.3.0 [exec] (the first release with S2PrefixTree, from the branch_7x backport; the master commit first shipped in 8.0.0 [exec]); 7.2.1 has no such API [exec]",
   "affected_versions": "Every release from 7.3.0 to 10.6.0 (10.6.0 by reading) and main ea57360912ed; not fixed upstream. [exec] the finder's JUnit fails 1 of 1 (Contains 0 hits after the Intersects control finds 1) on 7.3.0, 7.3.1, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea; main also -da) (follow-up; releases up to 9.0.0 with only the LuceneTestCase import changed, 7.x with the JUnitCore runner); the independent reproduction's 96-configuration JUnit fails on main (-ea and -da), 10.5.2, 9.12.3, 8.11.4 and 7.3.0 with its controls passing. [read] no later commit changes either method (only the LUCENE-9570 reformat touches their lines); releases 7.4.0-7.7.2, 8.1.0-8.11.3, 9.1.0-9.12.2 and 10.1.0-10.5.1 are inferred from the unchanged code; upstream main e1c4184cb983 (2026-10-26) and branch_10x 1309534296e3 (2026-10-24) have S2PrefixTreeCell.java, S2PrefixTree.java and ContainsPrefixTreeQuery.java byte-identical to the tested commit. All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-371.html",
   "repro": "repro/LFV-371/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-705",
   "priority": "low",
   "priority_rank": 410,
   "novelty": "new",
   "withheld": false,
   "area": "spatial-extras / prefix trees: PackedQuadPrefixTree point-to-cell lookup (RecursivePrefixTreeStrategy and CompositeSpatialStrategy point queries)",
   "title": "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",
   "summary": "You index a point at longitude +180, for example Pt(180, 10), with RecursivePrefixTreeStrategy over PackedQuadPrefixTree(SpatialContext.GEO, 8) and query Intersects or Contains with that same point; the document must match, since a point intersects and contains itself and the prefix-tree approximation may only add matches (SpatialArgs: the error 'should not shrink' the shape). Instead the query returns 0 hits, and so does CompositeSpatialStrategy's Intersects: indexing keeps the first cell in Z order whose rectangle relate()s to the point, and a geo rectangle treats +180 as -180, so the point is stored in the cells at the -180 edge, while the point query's cell lookup (PackedQuadPrefixTree.getCell, a mid-point walk since LUCENE-8755 in 8.3.0) sends x=+180 to the cells at the +180 edge. The same point at -180, QuadPrefixTree, and a rectangle query touching +180 still find the document.",
   "impact_class": "silent wrong results",
   "introduced_commit": "26628b2717a73235db56fde94f7f5b64cbc5b8b2 (LUCENE-8755 'QuadPrefixTree robustness: can throw exception while indexing a point at high precision', apache/lucene#9800, from apache/lucene-solr#824, which was closed and committed directly; branch_8x backport c09ddcb7180ccc4abaef25f654ffc053421353a4, shipped in 8.3.0) [exec]",
   "introduced_date": "2019-08-20 (commit date; authored 2019-08-07)",
   "first_affected_version": "8.3.0 [exec] (8.2.0 and 7.7.3 pass [exec])",
   "affected_versions": "8.3.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2 and main a9779ef3c193; never fixed (getCell is unchanged on upstream main a95c754ee003 and branch_10x, read-only check 2026-10-27). [exec] the candidate repro fails 3/6 on 8.3.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) and passes 6/6 on 7.7.3 and 8.2.0; the independent reproduction's own JUnit fails on main (-ea, -da), 10.5.2 (-ea, -da) and 9.12.3, and the independent reproduction's framework-free main() passes on 8.2.0 and fails on 8.3.0. In 8.3.0-9.12.x a tree built through SpatialPrefixTreeFactory with version < 8.3.0 keeps the old getCell and is not affected (the switch was removed by 1ddb01044a0 in 10.0.0); the public constructor and the default factory version are affected.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-705.html",
   "repro": "repro/LFV-705/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-301",
   "priority": "low",
   "priority_rank": 411,
   "novelty": "new",
   "withheld": false,
   "area": "spatial-extras / PointVectorStrategy (Intersects and IsWithin rectangle queries: makeWithin x filter)",
   "title": "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)",
   "summary": "You index a point with PointVectorStrategy in the default geo context and search it with SpatialOperation.Intersects or IsWithin and a rectangle that does not cross the dateline but has one edge on the antimeridian, expecting the point to be found whenever spatial4j's relate, which defines these predicates, says it is inside (in geo, -180 and +180 are the same meridian). Instead a point stored at x=+180 is missed by a box whose west edge is -180 (Pt(180,0) with rect(-180,-170,-10,10): 0 hits, oracle 1), and a point at x=-180 by a box whose east edge is +180 (Pt(-180,0) with rect(170,180,-10,10)). BBoxStrategy and both prefix-tree strategies in the same module return the hit; PointVectorStrategy.makeWithin filters x with one plain DoublePoint range [minX, maxX] for every non-crossing box, so +180 and -180 are different values to it.",
   "impact_class": "silent wrong results",
   "introduced_commit": "6f1fde90512 (branch_4x, svn r1381280; trunk equivalent 1db287ce640, svn r1381230), 'LUCENE-4351 Update to Spatial4j 0.3' (issue apache/lucene#5417), by dsmiley, no PR (SVN + JIRA patch era) [exec]. Behavioural introduction: the commit changed no line of the x filter; it bumped spatial4j 0.2 to 0.3. spatial4j 0.2 normalized longitude +180 to -180 in makePoint/makeRect and its relate treated the two values as different, so the plain range agreed with the oracle; from 0.3 on, +180 is kept and relate treats +/-180 as one meridian. Code origin [read]: the plain x range dates from the module import 66a852234d4 (LUCENE-3795, 2012-02-20); the current crossing/non-crossing shape of makeWithin is from LUCENE-4389 'Fix TwoDoubles dateline support' (#5455; trunk 922c7316d81, branch_4x ed444bdac7d, 2012-09-15), which handled only boxes that cross the dateline",
   "introduced_date": "2012-09-05 (6f1fde90512 on branch_4x and 1db287ce640 on trunk)",
   "first_affected_version": "4.0.0 [exec] (tag 2012-10-11); the earlier builds that shipped the strategy, 4.0.0-ALPHA and 4.0.0-BETA (spatial4j 0.2), are not affected [exec], and 3.6.x has no such API [exec]",
   "affected_versions": "Every release from 4.0.0 on, and main. [exec] fails on 4.0.0 (-ea and -da), 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main ea57360912ed (-ea and -da), with spatial4j 0.3 to 0.8 (follow-up; 4.x and 5.x through main() ports of the same cases and oracle); the independent reproduction, the cross-model review and the intended-behaviour check independently reproduce on main, 10.5.2 and/or 9.12.3. [read] branch_10_6 and branch_10x have the same makeWithin; upstream main is unchanged (last commit touching PointVectorStrategy.java is dfd536186fe, 2026-04-01, cosmetic). Not affected: 4.0.0-ALPHA, 4.0.0-BETA and branch_4x 8dd92aa7e90 [exec]; 3.6.2 has no such API [exec].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-301.html",
   "repro": "repro/LFV-301/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1113",
   "priority": "low",
   "priority_rank": 412,
   "novelty": "new",
   "withheld": false,
   "area": "spatial-extras / BBoxStrategy and PointVectorStrategy query construction (inclusive DoublePoint range bounds taken unchanged from spatial4j rectangles: BBoxStrategy.makeNumericRangeQuery, PointVectorStrategy.rangeQuery)",
   "title": "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",
   "summary": "You index a point stored at longitude -0.0 (for example parsed from 'POINT(-0 5)') with BBoxStrategy and PointVectorStrategy and query the rectangle Rect(minX=0.0, maxX=10, minY=0, maxY=10); you expect the point to match Intersects and IsWithin in both strategies, because SpatialOperation.evaluate says it lies on the rectangle's west edge (spatial4j compares coordinates as primitives, so -0.0 == 0.0). Instead BBoxStrategy finds it for Intersects but not for IsWithin, and PointVectorStrategy finds it for neither, with no error. Both strategies pass the rectangle's 0.0 edge unchanged as an inclusive DoublePoint range bound, and DoublePoint orders -0.0 below +0.0; BBoxStrategy's Intersects uses only exclusive bounds, which it moves with Math.nextUp/Math.nextDown, and those give the same result for both zeros.",
   "impact_class": "silent wrong results",
   "introduced_commit": "As old as the strategies, not a regression. PointVectorStrategy: 66a852234d4 (2012-02-20, David Wayne Smiley; initial copy of the spatial-lucene module, LUCENE-3795 / #4868; the class was then TwoDoublesStrategy, renamed by e9cffebf96f, LUCENE-4374), whose makeWithin built an inclusive NumericRangeQuery.newDoubleRange from the raw rectangle bounds. BBoxStrategy: 26d3f1f813e (LUCENE-4175 / #5247, 2012-06-28, Ryan McKinley), inclusive raw bounds in makeWithin / makeContains, released through the branch_4x port c608265684c (LUCENE-5714 / #6776 and LUCENE-5779, 2014-07-09). Today's lines and BBoxStrategy's Intersects-vs-IsWithin contradiction: e1b45568b41 on master and f9da8164483 on the 6.0 branch (LUCENE-7094 / #8150, 2016-03-30, nknize), which moved both strategies to DoublePoint.newRangeQuery with raw inclusive bounds and Math.nextUp/Math.nextDown for exclusive ones. [read]",
   "introduced_date": "2012-02-20 (66a852234d4, PointVectorStrategy); BBoxStrategy 2012-06-28 on trunk (26d3f1f813e) and 2014-07-09 on branch_4x (c608265684c); current form 2016-03-30 (e1b45568b41); author dates equal commit dates for all cited commits",
   "first_affected_version": "4.0.0 [exec]; not a regression: no release ever matched these shapes (3.6.2 ships only the old contrib spatial code, with no SpatialStrategy API)",
   "affected_versions": "Every release that ships the strategies: PointVectorStrategy 4.0.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b), BBoxStrategy 4.10.0 through 10.6.0, and main e1faeba08bde (12.0.0-SNAPSHOT). Executed with a point stored at x = -0.0 against Rect(0.0, 10, 0, 10), hits of [BBox Intersects, BBox IsWithin, PointVector Intersects, PointVector IsWithin], expected [1, 1, 1, 1], -1 = strategy not in the release (main() ports, -da): 4.0.0 and 4.9.1 [-1, -1, 0, 0]; 4.10.0, 4.10.4, 5.0.0 and 5.5.5 [0, 0, 0, 0] (the legacy trie encoding orders -0.0 below +0.0 on the exclusive path too, so BBox Intersects misses as well); 6.0.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.6.0 and main [1, 0, 0, 0] [exec]. The independent reproducer's JUnit fails [1, 0, 0, 0] on main -ea and -da, and on 10.6.0, 10.5.2 and 9.12.3 with -da [exec]; the finder's mirror-direction JUnit fails on main -ea and -da, main ea57360912ed, 10.6.0 and 9.12.3 [exec]. Releases between the executed ones were not run individually; the range code is unchanged between them apart from formatting [read]. Upstream: the newest commits on both files (bc7deedc092 #15499, author 2025-12-11; dfd536186fe #15889, author 2026-04-01) are in e1faeba08bde and cosmetic; no open PR touches either file (2026-11-02) [read]. Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1113.html",
   "repro": "repro/LFV-1113/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-619",
   "priority": "low",
   "priority_rank": 413,
   "novelty": "new",
   "withheld": false,
   "area": "spatial-extras / prefix trees (DateRangePrefixTree date parsing: parseCalendar, also reached through NumberRangePrefixTree.parseShape for single dates and range bounds)",
   "title": "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",
   "summary": "You parse a date such as 2014-11-31, or a range such as [2014-11-01 TO 2014-11-31], with DateRangePrefixTree.parseCalendar or parseShape and expect a ParseException, which the parser has given since LUCENE-8640 for day 32, month 13, hour 25 and minute 60. Instead the day is checked only against 1..31 and set on a lenient java.util.Calendar, which moves it into the next month when the fields are read: 2014-11-31 becomes 2014-12-01, 2014-02-30 becomes 2014-03-02, and the range parses to [2014-11 TO 2014-12-01], so an Intersects query on a NumberRangePrefixTreeStrategy index also returns a document dated 2014-12-01.",
   "impact_class": "wrong error",
   "introduced_commit": "bb267a143e009f7b1375f7fa9755b76fcc82ec4f (trunk, svn r1600555, 'LUCENE-5648: DateRangePrefixTree and NumberRangePrefixTreeStrategy', author GitHub dsmiley; branch_5x got it through the bulk backport 55594bad9b0, LUCENE-5944, 2014-09-18; no PR, svn era, JIRA LUCENE-5648 is now GitHub #6710): the parser set the parsed day on a lenient Calendar from the start, at first with no field validation at all (day 32 and month 13 rolled over too). The specific inconsistency, day 32 rejected but a day past the month's end rolled over, dates from 8e69d12dd7e2b6d2341322e4ac7e5c33b789507a ('LUCENE-8640: date range syntax validation', committed by GitHub mkhludnev, 2019-01-26; backports d482312b854 branch_8x and 62ee5df5e17 branch_7x; issue #9686; the contributed PR apache/lucene-solr#538 was closed and the change committed directly), which added parseAndCheck with fixed per-field bounds (day 1..31) and no month-length check [read]. Not a regression; later edits to these lines are formatting and renames only (2cbf261032d reformat, 54283150a81 checkDelimeter -> checkDelimiter)",
   "introduced_date": "2014-06-05 (bb267a143e00, trunk); 2014-09-18 (branch_5x backport); 2019-01-26 (8e69d12dd7e, LUCENE-8640 per-field validation without a month-length check)",
   "first_affected_version": "5.0.0 [exec] (first release with DateRangePrefixTree; up to 7.6.0 no field was validated, so day 32 and month 13 rolled over as well); 7.7.0 [exec] is the first release in which day 32 is rejected while a non-existent day is still rolled over (LUCENE-8640 shipped in 7.7.0 and 8.0.0); 4.10.4 and earlier have no DateRangePrefixTree [exec]",
   "affected_versions": "Every release from 5.0.0 through 10.6.0 (10.6.0 by reading) and main a9779ef3c193, never fixed. [exec] the follow-up's version-neutral main() probe shows 2014-02-30 -> 2014-03-02, 2014-11-31 -> 2014-12-01, 2013-02-29 -> 2013-03-01 and 2014-04-31T10 -> 2014-05-01T10 on 5.0.0, 6.0.0, 7.6.0, 7.7.0, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (on main with both template calendars), with day 32 accepted up to 7.6.0 and rejected from 7.7.0, and passes on main with the fix shadowed; the finder's JUnit (with the pre-9.1 test-framework package for 7.x-9.0) fails as claimed on 7.7.0, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da on main) and on 7.6.0 fails earlier, at its day-32 control; the independent reproduction's JUnit fails 2 of 3 on main (-ea and -da), 10.5.2 and 9.12.3. [read] releases between the executed points: the day-parsing lines changed only by formatting and renames since 8e69d12dd7e; upstream main a95c754ee003 (2026-10-26) has no parsing change and the only open PR touching the file (#12295) replaces instanceof casts, so 10.6.0 (released 2026-10-29) and the unreleased 11.0 line are affected (not executed). Not executed: x86 and older JDKs (pure Java Calendar logic; lenient GregorianCalendar rollover is long-standing JDK behaviour). JDK 25.0.3, aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-619.html",
   "repro": "repro/LFV-619/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-550",
   "priority": "low",
   "priority_rank": 414,
   "novelty": "known",
   "withheld": false,
   "area": "core document / LatLon distance sort (LatLonPointDistanceComparator competitive bounding box, Rectangle.fromPointDistance pad)",
   "title": "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",
   "summary": "You index two points about 45 cm from the north pole with LatLonDocValuesField and sort with Sort(LatLonDocValuesField.newDistanceSort(\"p\", -90, 146.5868...), new SortField(\"tie\", INT)); both documents report the same distance (2.0015113815150492E7 m) and search(n=2) correctly returns [1, 0], the tie broken by \"tie\". You expect search(n=1) to return that head, doc 1, and one-hit searchAfter pages to return [1, 0]. Instead search(n=1) returns doc 0 and the pages return only doc 0: once doc 0 is the queue bottom, the comparator's pruning box (radius = the bottom's sloppy distance + 7 cm) leaves out doc 1, whose exact distance near the antipode exceeds that sloppy distance by more than 7 cm, so compareBottom returns -1 instead of 0 without computing doc 1's equal key and the secondary sort never runs.",
   "impact_class": "silent wrong results",
   "introduced_commit": "05d62a357711d1e4e850a5d2fb7336bf0a7acf24 (main, 2016-04-07, 'LUCENE-7185: fix tie-breaker sort bug', by GitHub rmuir), with the branch_6x backport 01867a5b318d6509731feea118b3f82764310380 the same day (JIRA-patch workflow, no pull request; LUCENE-7185 = GitHub issue #8240, open). It masked SloppyMath.haversinSortKey to 8-ulp steps to fix a different tie-breaker bug, which raised the worst-case distance error (its author wrote 'from 0.1cm to 20cm'; b839325740f, 2016-04-18, corrected the javadoc to 40 cm) above the 7 cm pad that 045659533cd (2016-03-29, Ryan Ernst (GitHub rjernst), committed under LUCENE-7147 with the code comment '// LUCENE-7143') had added to the box radius nine days earlier; the pad was never widened. The design gap is older: e169050dc3f (2016-03-11, LUCENE-7099, rmuir) added the competitive box with no margin, and the 2-document repro already fails there; it passes from 045659533cd until 05d62a35771. [exec]. Not a regression of any release: all three commits predate 6.1.0, the first release with the API.",
   "introduced_date": "2016-04-07 (05d62a35771 on main and 01867a5b318 on branch_6x)",
   "first_affected_version": "6.1.0 [exec] (tag date 2016-06-16; the first release with a lat/lon distance sort, then in lucene/sandbox); there is no unaffected earlier release with the API: 5.5.5, 6.0.0 and 6.0.1 have no newDistanceSort (probe reports API absent) [exec]",
   "affected_versions": "Every release before 10.6.0 with a lat/lon distance sort, 6.1.0 to 10.5.2, plus main ea57360912ed; the comparator is in lucene/sandbox in 6.1.0-7.4.0 and in lucene/core from 7.5.0 [read]. [exec] the follow-up's version-agnostic 2-document probe PoleTieProbe fails on 6.1.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (release runs with -ea); its randomized probe PoleRandomProbe (2000 trials, origin within 1 cm of a pole) gives identical counts on 6.1.0, 6.6.6, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main (404 top-k and 758 paging mismatches with distinct points, 607 and 801 with paired points) and 0 with the 0.4 m fix shadowed on main; the finder's JUnit fails on main (-ea and -da), 10.5.2 and 9.12.3 and the finder's main() probes on 8.11.4, 8.0.0, 7.7.3 and 6.6.6; the independent reproduction's JUnit fails on main (-ea and -da), 10.5.2 (-ea, and -da in the registration check) and 9.12.3; the intended-behaviour check re-ran 10.5.2. 10.6.0 (released 2026-10-29) was not run: Maven Central returned 404 for it on 2026-10-26. Not fixed upstream: LatLonPointDistanceComparator.java, Rectangle.java and SloppyMath.java are byte-identical on upstream main ffa9d816eeb4 (2026-10-26), branch_10x and branch_10_6. Not executed: x86, and each release's own JDK (all runs used JDK 25.0.3 on aarch64).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/8198",
    "https://issues.apache.org/jira/browse/LUCENE-7143",
    "https://issues.apache.org/jira/browse/LUCENE-7147",
    "https://issues.apache.org/jira/browse/LUCENE-7185",
    "https://github.com/apache/lucene/issues/8240",
    "https://github.com/apache/lucene/issues/10283"
   ],
   "doc": "",
   "repro": "repro/LFV-550/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-578",
   "priority": "low",
   "priority_rank": 415,
   "novelty": "known",
   "withheld": false,
   "area": "core document + geo / LatLon box queries (the newBoxQuery/newSlowBoxQuery 90/180 special case vs Rectangle2D.create and LatLonShapeBoundingBoxQuery)",
   "title": "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)",
   "summary": "You index one point at (90, 0) with LatLonPoint (stored at the top encoded latitude, 89.99999995809048) and query the box lat 90..90, lon -180..180 through LatLonPoint.newGeometryQuery, expecting the point to be either INTERSECTS or DISJOINT and every box path of the field to agree. Instead INTERSECTS, which newGeometryQuery routes to newBoxQuery and its deliberate MatchNoDocsQuery for minLatitude == 90, matches 0 docs; DISJOINT, which goes through Rectangle2D.create (commented 'behavior of LatLonPoint.newBoxQuery()' but copying only the dateline part of that special case, then rounding the box up onto the top row with a saturating encodeLatitudeCeil), also matches 0; WITHIN, INTERSECTS(box, box), LatLonPointQuery and LatLonShape.newBoxQuery match 1. LatLonDocValuesField's slow queries behave the same, a box lon 180..180 over a point at (0, 180) gives the same pattern, and upstream's own equivalence assertion (BaseLatLonPointTestCase.testBoundingBoxQueriesEquivalence: count(newBoxQuery) == count(LatLonPointQuery INTERSECTS)) fails for this box, 0 vs 1.",
   "impact_class": "silent wrong results",
   "introduced_commit": "8bfbed8d4cd476a008ee85310b1f6535920b4622 (main, LUCENE-9552 = apache/lucene#10591, pull request apache/lucene-solr#1940 'Adds a LatLonPoint query that accepts an array of LatLonGeometries' by GitHub iverase, merged 2020-11-03; branch_8x backport e30959f8cab9d56dfcbb8cd41efb64cba3714d3b): it added LatLonPoint.newGeometryQuery and LatLonDocValuesField.newSlowGeometryQuery, which send one Rectangle to the special-cased newBoxQuery/newSlowBoxQuery and everything else to Rectangle2D.create, which got the comment '// behavior of LatLonPoint.newBoxQuery()' but only the dateline variant of the special case. Co-introducing: 14009f4424d847ce84fa23a71d8066dfe6c70da0 (LUCENE-9641 = apache/lucene#10680, apache/lucene-solr#2155 by iverase, merged 2021-01-08; branch_8x backport f73f6b11f0ed4bcbfce445152d813adb3327d249) added the DISJOINT/WITHIN relations (DISJOINT as negated INTERSECTS in SpatialQuery) and testBoundingBoxQueriesEquivalence, which gives the INTERSECTS 0 / DISJOINT 0 / WITHIN 1 symptom. The special case itself is older and deliberate (e0c507a40012, LUCENE-7185, GitHub rmuir, 2016-04-07, first in 6.1.0) and was harmless while every same-field box path carried it. [exec]",
   "introduced_date": "2020-11-03 (LUCENE-9552; LUCENE-9641 followed on 2021-01-08; both first released in 8.8.0)",
   "first_affected_version": "8.8.0 [exec] (contains both LUCENE-9552 and LUCENE-9641; no release has one without the other). Up to 8.7.0 the disagreeing same-field APIs do not exist: the full repro does not compile on 8.7.0, and the same-field probe passes on 8.5.0, 8.6.3 and 8.7.0, where newBoxQuery and newSlowBoxQuery both carry the special case. A narrower cross-field-type form (LatLonPoint.newBoxQuery 0 vs LatLonShape.newBoxQuery 1 on the same point) exists in lucene-core from 8.5.0 [exec] and in the sandbox LatLonShape from 7.5.0 [read]",
   "affected_versions": "every release from 8.8.0 to 10.6.0 (10.6.0 by reading) and main ea57360912ed. [exec] the follow-up's same-field probe fails on 8.8.0, 8.8.1, 8.8.2, 8.9.0, 8.10.1, 8.11.0, 8.11.4, 9.0.0, 9.1.0, 9.2.0, 9.3.0, 9.4.2, 9.5.0, 9.6.0, 9.7.0, 9.8.0, 9.9.2, 9.10.0, 9.11.0, 9.11.1, 9.12.0, 9.12.1, 9.12.2, 9.12.3, 10.0.0, 10.1.0, 10.2.2, 10.3.2, 10.4.0, 10.5.2 and main; the finder's JUnit fails 3 of 3 on main (-ea and -da), 10.5.2, 10.0.0, 9.12.3 and 9.11.1, and its pre-9.1 variant 3 of 3 on 9.0.0, 8.11.4, 8.11.2 and 8.8.0; the independent reproduction's JUnit fails 2 of 5 (its 3 controls pass) on main (-ea and -da), 10.5.2 and 9.12.3; re-runs on main -ea and -da and 10.5.2 -da. [read] the releases not executed (8.10.0, 8.11.1, 8.11.3, 9.4.0, 9.4.1, 9.9.0, 9.9.1, 10.2.0, 10.2.1, 10.3.0, 10.3.1, 10.5.0, 10.5.1) sit between failing releases with the special case and Rectangle2D.create unchanged; branch_10_6, released as 10.6.0 on 2026-10-29, carries the same code. On 8.8.0-9.11.1 the doc-values numbers for the pole box differ (INTERSECTS(box, box) 0, DISJOINT 1, WITHIN 0) because of a separate, already fixed bug, the GeoEncodingUtils Grid overflow apache/lucene#13703 (fixed by #13704 in 9.12.0; shadowing only that file into 9.11.1 gives the 9.12.0 values); the points-path disagreement is the same on every release from 8.8.0. Not fixed upstream: upstream main a95c754ee003 (2026-10-26) still has both special cases and the unchanged Rectangle2D.create, and no open PR changes them. All runs used JDK 25 on aarch64 (pure integer and double logic; not run on x86)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/10194",
    "https://issues.apache.org/jira/browse/LUCENE-9154",
    "https://github.com/apache/lucene-solr/pull/1193",
    "https://github.com/apache/lucene/issues/8565",
    "https://issues.apache.org/jira/browse/LUCENE-7514",
    "https://issues.apache.org/jira/browse/LUCENE-9552"
   ],
   "doc": "",
   "repro": "repro/LFV-578/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1134",
   "priority": "low",
   "priority_rank": 416,
   "novelty": "new",
   "withheld": false,
   "area": "core / geo (Circle2D.containsLine/containsTriangle for haversine circles whose bounding box crosses the dateline, behind LatLonShape.newDistanceQuery WITHIN)",
   "title": "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",
   "summary": "You index a two-point LatLonShape line from (lat 0, lon -179.5) to (lat 0, lon 179.5); Lucene runs its edge straight through (0, 0), so the document matches INTERSECTS a 100 km circle around (0, 0). A WITHIN query with a 100 km circle around (0, 180), 20,000 km from that point, should then return 0 hits, but it returns 1 with no error. Circle2D treats a circle that crosses the dateline as two longitude pieces, and containsLine/containsTriangle accept a shape once every vertex lies in either piece, never checking that the edges between them stay inside.",
   "impact_class": "minor",
   "introduced_commit": "d48bafb2999542224c86f278d1fd0dcb949388cc on master and its branch_8x cherry-pick 50168ab5bc85c382a6d558553caa1f752bf5afc1 (LUCENE-8707 'Add LatLonShape and XYShape distance query', apache/lucene-solr#587 by iverase, opened 2019-02-25, merged 2020-02-19; JIRA LUCENE-8707 = apache/lucene#9753): the first Circle2D already reported a segment or triangle as inside when every vertex passed contains(), with no dateline check. Today's containsLine/containsTriangle bodies come from f914e08b3647ad91eb97ada6ebefe1e96ebd5a89 / a001f135f229a4c08afe4b6eb3dc11da5db91605 (LUCENE-9273, apache/lucene-solr#1341 = apache/lucene#10313, 2020-04-20, first in 8.6.0), which kept the vertex-only rule while giving the box query's containsLine/containsTriangle an explicit same-side check for boxes that cross the dateline; the only later change is reformatting (LUCENE-9570, 2d6ad2fee6d) [read]",
   "introduced_date": "2020-02-19 (author date 2020-02-19T16:03:30+01:00 of d48bafb2999 and 50168ab5bc8); current form f914e08b364, author date 2020-04-20",
   "first_affected_version": "8.5.0 [exec]",
   "affected_versions": "every release since the API exists: 8.5.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT). Executed with the one test: 8.5.0, 8.5.2, 8.6.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.6.0 and main (-ea and -da) all fail at the WITHIN assertion while the INTERSECTS anchor passes; the independent reproduction's own test also fails on 10.5.2, 10.6.0 and 9.12.3 [exec]; the other releases by tag ancestry and reading (no commit after f914e08b364 changed containsLine/containsTriangle except reformatting) [read]. Not new in 10.6 (8.5.0 and 10.5.2 fail). Not fixed upstream: Circle2D.java is the same blob (8fd98adbc55) at ea57360912ed, 5adff78bb168 and releases/lucene/10.6.0, its newest upstream commit is f22f2b70a7d (author date 2025-07-07, a typo fix, #14898), and upstream main 1c2072f0284 (author date 2026-11-02) has no later change to it [read]. Runs used JDK 25.0.3 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1134.html",
   "repro": "repro/LFV-1134/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-366",
   "priority": "low",
   "priority_rank": 417,
   "novelty": "new",
   "withheld": false,
   "area": "document / shape doc values (ShapeDocValues centroid; LatLonShapeDocValuesField and XYShapeDocValuesField getCentroid)",
   "title": "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)",
   "summary": "You build a doc-values shape with LatLonShape.createDocValueField or XYShape.createDocValueField and ask for its centroid; you expect getCentroid(), documented as 'the centroid location for the geometry', to be a point of the shape, inside the bounding box that the same object returns. For a line whose points coincide after encoding (new Line({40, 40}, {-70, -70}), or two points closer than one encoding step) or a polygon thinner than one encoding step, Lucene returns Point(0.0, 0.0) instead, 7,500 km or more from the shape in these examples: the centroid is weighted by length or area, and when the total weight is zero the code skips the division and keeps the zero numerator. The other public factory, createDocValueField(name, createIndexableFields(name, line)), returns the real point for the same line.",
   "impact_class": "silent wrong results",
   "introduced_commit": "d7fd48c9502c567e4760a011fa99b1a491fea2cb (main) and its branch_9x backport ddf0d0acf4e4443ddea37bb855dead7bed5cc1a2 (the copy that shipped in 9.4.0), 'LUCENE-10654: Add new ShapeDocValuesField for LatLonShape and XYShape' by nknize (PR apache/lucene#1017, backport #1064, issue #11690) [read]. Not a regression: present since the feature was added; the later commits to ShapeDocValues.java (fad3108b27b, #11974, a header serialization flag; de3b294be44, formatting) do not touch it",
   "introduced_date": "2022-08-09 (d7fd48c9502c and its backport ddf0d0acf4e)",
   "first_affected_version": "9.4.0 [exec] (tag 2022-09-30, the first release with ShapeDocValuesField; CHANGES 9.4.0 'LUCENE-10654: Add new ShapeDocValuesField for LatLonShape and XYShape'); 9.3.0 has no such API [exec]",
   "affected_versions": "Every release from 9.4.0 to 10.6.0 (10.6.0 by reading) and main ea57360912ed; not fixed upstream. [exec] the finder's JUnit fails 5 of 5 on 9.4.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) (finder and follow-up; the intended-behaviour check repeated 10.5.2 and 9.4.0); the independent reproduction's own JUnit fails 7 of 10 (its 3 controls pass) on main (-ea and -da), 10.5.2, 9.12.3 and 9.4.0. [read] 9.4.1 to 10.5.1 are inferred: git log shows no commit that changes the centroid code; upstream main at cf398bfb142c (2026-10-26) has no change to it and no open PR touches it (the prior-report record). All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-366.html",
   "repro": "repro/LFV-366/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1130",
   "priority": "low",
   "priority_rank": 418,
   "novelty": "new",
   "withheld": false,
   "area": "core / document: shape doc values (ShapeDocValues.ShapeComparator bounding box behind LatLonShapeDocValues / XYShapeDocValues getEncodedMinX, getEncodedMinY, getEncodedMaxX, getEncodedMaxY)",
   "title": "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",
   "summary": "You build a LatLonShapeDocValues (or XYShapeDocValues) from a shape's doc-value bytes, call relate() with a query box, and then read getEncodedMinX/MinY/MaxX/MaxY, which are documented as 'the shape's bounding box'; you expect the same four values as before the relate() call. Instead, when the query box crosses the shape's box so that relate() walks down the shape's tree, the getters afterwards return the box of the last tree node visited: for the points (0,0), (10,10), (20,20) and a small box around (0,0), relate() correctly answers CELL_CROSSES_QUERY but getEncodedMaxX() then returns 0 instead of encodeLongitude(20) = 238609294, with no error. The getters read the reader's single reusable scratch box, which relate() overwrites for every node it visits, while getBoundingBox() of the same object, computed once in the constructor, stays correct.",
   "impact_class": "minor",
   "introduced_commit": "d7fd48c9502 on main ('LUCENE-10654: Add new ShapeDocValuesField for LatLonShape and XYShape (#1017)', Nick Knize; migrated issue #11690; branch_9x copy ddf0d0acf4e, PR #1064, first released in 9.4.0) [read]. Client reachability came with e7253f112de (PR #11753, issue #11752, Navneet Verma, author date 2022-10-28; branch_9x copy a4ef70f0656, PR #11890), which added the public factories LatLonShape.createLatLonShapeDocValues(BytesRef) and XYShape.createXYShapeDocValues(BytesRef). Not a regression: the two later commits on ShapeDocValues.java (fad3108b27b, #11974, a Writer serialization flag; de3b294be44, formatting) do not touch these lines.",
   "introduced_date": "2022-08-09 (author and commit date of d7fd48c9502 and ddf0d0acf4e; 9.4.0 tagged 2022-09-30); reachable from client code since e7253f112de (author date 2022-10-28), first released in 9.5.0 (tagged 2023-01-30)",
   "first_affected_version": "9.5.0 [exec] (the first release with the public factories createLatLonShapeDocValues / createXYShapeDocValues, so the first where client code can obtain an instance; the finder's repro fails there). The defective code first shipped in 9.4.0 [exec], but 9.4.x exposes no instance to client code (both classes have protected constructors and no public method returns one; the finder's repro does not compile on 9.4.0 or 9.4.2); 9.3.0 has no shape doc values [exec].",
   "affected_versions": "Every release from 9.5.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b), 27 releases, and main 5adff78bb168 (12.0.0-SNAPSHOT); not fixed upstream. [exec] the finder's one-test repro fails with 'arrays first differed at element [1]; expected:<238609294> but was:<0>' (getEncodedMaxX) on main (-ea and -da, also in the re-run), 10.6.0 (-ea and -da), 10.0.0, 9.12.3 and 9.5.0 (-da); the independent reproduction's two-method test (a polyline, LatLon and XY) fails on main (-ea, -da), 10.6.0, 10.5.2, 9.12.3 and 9.5.0; the intended-behaviour check's XY polygon test fails on main (-ea, -da) and on the 10.6.0 jars. [read] the alias line, the scratch reset and the per-node resetBBox are present at every 9.x/10.x tag from 9.4.0 to 10.6.0 (follow-up tag sweep); ShapeDocValues.java is identical at 10.6.0 and main and unchanged on upstream main 1c2072f02843 (2026-11-02) since de3b294be44 (author date 2023-10-10). 9.4.0-9.4.2 contain the code but give client code no instance. Not new in 10.6. All runs JDK 25.0.3 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1130.html",
   "repro": "repro/LFV-1130/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-792",
   "priority": "low",
   "priority_rank": 419,
   "novelty": "new",
   "withheld": false,
   "area": "geo / Tessellator cure step (polygon indexing for LatLonShape and XYShape, shape doc values)",
   "title": "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",
   "summary": "You index a polygon with LatLonShape or XYShape (createIndexableFields or createDocValueField) and expect each triangle of its tessellation to be stored once. When the Tessellator's cure step (cureLocalIntersections) cuts off a triangle to repair a small local self-intersection, it appends that same triangle twice (two identical tessellation.add calls at Tessellator.java:890 and :892, left by LUCENE-8620 in 8.3.0), so the shape carries one extra indexed triangle, ShapeDocValuesField.numberOfTerms is one too high and getCentroid() counts that triangle's area twice; query results do not change. On its own the cure step fires only for self-crossing rings, which the javadoc excludes but the default checkSelfIntersections=false path accepts (for example POLYGON((6 3, 0 6, 4 0, 3 4, 5 1, 3 2, 6 3)), duplicated on every release from 8.3.0), and a valid polygon reaches it only when it already hits LFV-210 (a hole touching the shell), whose fix removes it.",
   "impact_class": "minor",
   "introduced_commit": "62001b9b9651e54b54f73352801061d40da75168 on master (apache/lucene-solr#771 'LUCENE-8620: Update Tessellator logic to label if triangle edges belongs to the original polygon', by iverase, merged 2019-09-09; issue LUCENE-8620, migrated as apache/lucene#9666), backported to branch_8x as 252421bb77c (2019-09-09), the commit that shipped first (8.3.0). In cureLocalIntersections it inserted a new tessellation.add above the comment '// Return the triangulated vertices to the tessellation' and rewrote the old single add 'tessellation.add(new Triangle(a, node, b))' below it into the same call [read]. The LUCENE-9570 reformat (2d6ad2fee6d, 2020-12-23) made the two lines byte-identical. The cure step itself dates from LUCENE-8396 (b5ef13330f1, 7.5.0) and added the triangle once until 8.2.0.",
   "introduced_date": "2019-09-09 (master 62001b9b965 and branch_8x 252421bb77c)",
   "first_affected_version": "8.3.0 [exec] (8.2.0 is the last unaffected release [exec]; in 8.3.0-8.4.1 the classes shipped in lucene-sandbox, in lucene-core from 8.5.0; the doc-values numberOfTerms and centroid effect exists from 9.4.0, when ShapeDocValuesField was added)",
   "affected_versions": "[exec] the portable main() repro (one triangle indexed twice for the valid touching-hole polygon through XYShape and LatLonShape and for the self-crossing ring POLYGON((6 3, 0 6, 4 0, 3 4, 5 1, 3 2, 6 3))) fails on 36 releases: 8.3.0, 8.3.1, 8.4.0, 8.4.1, 8.5.0, 8.5.2, 8.6.3, 8.7.0, 8.8.2, 8.9.0, 8.10.1, 8.11.0, 8.11.4, 9.0.0, 9.1.0, 9.2.0, 9.3.0, 9.4.0, 9.4.2, 9.5.0, 9.6.0, 9.7.0, 9.8.0, 9.9.2, 9.10.0, 9.11.1, 9.12.0, 9.12.3, 10.0.0, 10.1.0, 10.2.2, 10.3.2, 10.4.0, 10.5.0, 10.5.1 and 10.5.2, and on main a9779ef3c193 (-ea and -da); it passes on 8.2.0. The finder's JUnit fails 4 of 4 on main (-ea and -da), 10.5.0 and 10.5.2; on 9.4.0, 9.12.3, 10.0.0 and 10.4.0 only 3 of its 4 failures are this bug, because those releases reject its ring POLYGON((6 0, 6 4, 5 1, 6 5, 6 1, 2 6, 2 0, 6 0)) with 'Unable to Tessellate shape' (accepted, and duplicated, only from 10.5.0 through #15739); on 9.3.0 it does not compile (no shape doc values yet). The independent reproduction's JUnit fails 6 of 7 on main (-ea and -da), 10.5.2 and 9.12.3. [read] all 47 release tags 8.3.0..10.5.2 in the history clone carry both adds and 7.5.0..8.2.0 carry one. Still unfixed on upstream main 20ced71c1e6e (2026-10-27), branch_10x and branch_10_6, so 10.6.0 has both adds (by reading).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-792.html",
   "repro": "repro/LFV-792/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-675",
   "priority": "low",
   "priority_rank": 420,
   "novelty": "new",
   "withheld": false,
   "area": "spatial-extras / spatial4j bridge to spatial3d (Geo3dRectangleShape.reset), read by BBoxStrategy's value sources (BBoxValueSource: makeShapeValueSource, makeOverlapRatioValueSource)",
   "title": "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",
   "summary": "You use the Geo3d spatial context (Geo3dSpatialContextFactory) with BBoxStrategy and read each document's box with makeShapeValueSource() or rank by makeOverlapRatioValueSource(queryBox, ...), or you call reset(10, 20, 30, 40) on a Geo3d rectangle yourself. You expect reset to replace the whole rectangle (the spatial4j Rectangle.reset javadoc: 'Resets the state of this shape given the arguments'; spatial4j's own RectangleImpl.reset assigns all four bounds), so getMinX()..getMaxY() return 10, 20, 30, 40, the shape values return each document's indexed box, and a document box equal to the query scores 1.0, as it does with the default SpatialContext.GEO. Instead Geo3dRectangleShape.reset rebuilds only the wrapped GeoBBox and clears the center and bounding-box caches, never assigning the four fields that getMinX()..getMaxY(), getWidth(), getHeight() and getCrossesDateLine() read: the rectangle equals rect(10, 20, 30, 40) but reports its previous bounds, BBoxValueSource (which creates one rect(0, 0, 0, 0) per segment and resets it for each document) reports (0, 0, 0, 0) for every document, and the self-overlap score is 0.0.",
   "impact_class": "silent wrong results",
   "introduced_commit": "035523ba7a86773500c053129f65c9a6dc4fd384 (master) and its branch_7x cherry-pick 85491401d54c59e1593a5c9f13dca7bfcdda31a2 (the commit that shipped in 7.1.0): LUCENE-7951 'Spatial4j implementations using Geo3d' (migrated as apache/lucene#9000), from PR apache/lucene-solr#246 by GitHub iverase, committed directly by GitHub dsmiley (the PR was closed without a GitHub merge). Geo3dRectangleShape is a new file in it and its reset has never assigned the four bound fields [read]. Inside the PR, the first version ea31e5ce0f derived the bounds lazily from a cached LatLonBounds and reset cleared it ('bounds = null'); commit cfbac2fb00 (iverase, 2017-09-12) replaced the cache with four stored fields and the 6-argument constructor and removed the cache clear from reset without assigning the new fields [read]. No review comment mentions reset.",
   "introduced_date": "2017-09-20 (commit date 23:09:46 -0400, i.e. 2017-09-21T03:09:46Z); the omission entered the PR in cfbac2fb00 on 2017-09-12",
   "first_affected_version": "7.1.0 [exec]; 7.0.0 and 7.0.1 are not affected [exec]",
   "affected_versions": "Every release from 7.1.0 through 10.5.2 (the last release before 10.6.0) and main a9779ef3c193; not fixed upstream. [exec] the finder's JUnit (the 7.x and 8.x runs use a source variant that differs only in the LuceneTestCase import) fails 3 of 3 on 7.1.0, 7.7.3, 8.0.0, 8.9.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the bisection test fails 1 of 3 (both controls pass) on 7.1.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) and passes on 7.0.0 and 7.0.1; with the 4-line fix both tests pass on 7.1.0 and main (follow-up); the independent reproduction's JUnit fails 3 of 7 (controls pass) on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check ran the finder's JUnit on main (-ea and -da) and 10.5.2 (3 of 3 fail). [read] a source scan of the 63 local release tags 7.1.0-8.8.1 and 9.0.0-10.5.2 finds that reset never assigns the fields; the 8.8.2-8.11.x tags are not in the local clones (8.9.0 and 8.11.4 executed, the rest inferred from branch lineage); upstream main (a95c754ee003, 2026-10-26) and branch_10x still have the unchanged reset (read 2026-10-27).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-675.html",
   "repro": "repro/LFV-675/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-778",
   "priority": "low",
   "priority_rank": 421,
   "novelty": "new",
   "withheld": false,
   "area": "spatial-extras / SpatialStrategy recip-distance scoring (every strategy with a distance value source)",
   "title": "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)",
   "summary": "You score a geo spatial query with makeRecipDistanceValueSource, whose javadoc says zScaling is one tenth of the distance from the centre to the farthest edge, so scores run from 1 at the centre down to about 0.1 at the furthest edge. For a box wider than 180 degrees of longitude the method instead takes half the great-circle distance between the box's two opposite corners, and that distance goes the short way round the globe: for rect(-170,170,-10,10) zScaling is 1.41 instead of 17.0, and the edge point (170,0) scores 0.0082 instead of about 0.091 (for the band rect(-180,180,-5,5), 0.0028). Nothing fails; distance is over-weighted, so with FunctionScoreQuery.boostByValue a hit with inner score 10 at 170 degrees ranks below a hit with inner score 1 at 10 degrees on the band query, the reverse of the documented scaling.",
   "impact_class": "silent wrong results",
   "introduced_commit": "577e25c7ffc11a3dfd64252bc43cde6b62e3fada (LUCENE-4208 'Spatial distance relevancy should use score of 1/distance', now GitHub apache/lucene#5280; SVN trunk r1385074, shipped through the branch_4x backport 11e5aca556b58bae04854493e0b687a1b7767e64, r1385122; SVN era, no PR; by GitHub dsmiley) [read] [exec]. The defect came with the method, so it is not a regression. The same half corner-to-corner computation was fixed in the sibling SpatialArgs.calcDistanceFromErrPct by LUCENE-4550 (6ba9d0b6418, 4.2.0) and left unchanged here",
   "introduced_date": "2012-09-15",
   "first_affected_version": "4.0.0 [exec] (the first release with SpatialStrategy.makeRecipDistanceValueSource; 4.0.0-BETA, the release before, does not have the method [exec])",
   "affected_versions": "Every release from 4.0.0 to 10.5.2 and main a9779ef3c193; not fixed upstream (SpatialStrategy.java last changed in 2cbf261032d, a 2021 reformat, on main and branch_10x; no open PR touches it, 2026-10-27). [exec] a probe (one source variant per API generation) fails with identical values (control rect(-60,60,-10,10) edge 0.09160 in band; rect(-170,170,-10,10) 0.00823; rect(-180,180,-5,5) 0.00285) on 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.0.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main a9779ef3c193; the finder's JUnit fails 3 of 3 on main (-ea, -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 2 of 3 (the control passes) on main (-ea, -da), 10.5.2 and 9.12.3. [read] the zScaling lines are the same computation at every release tag 4.0.0..10.5.2 in the history clone (8.9.0-8.11.3 are not tagged there; bracketed by 8.11.4 [exec]). All runs on JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-778.html",
   "repro": "repro/LFV-778/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-369",
   "priority": "low",
   "priority_rank": 422,
   "novelty": "new",
   "withheld": false,
   "area": "spatial-extras / BBoxStrategy overlap-ratio relevance (BBoxOverlapRatioValueSource.score: intersection width when both boxes cross the dateline)",
   "title": "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",
   "summary": "You index a dateline-crossing rectangle with BBoxStrategy in the default geo context and score it with makeOverlapRatioValueSource and a query rectangle that also crosses the dateline, and you expect the documented score intersectionArea/queryArea*p + intersectionArea/targetArea*(1-p), where intersectionArea is 'the area of the intersection between the query and target envelopes'. When the two boxes wrap far enough round the globe that they overlap twice, once across the dateline and once on the far side (query rect(10,-170,-10,10) and document rect(170,20,-10,10) share 170..-170 across the dateline, 20 degrees, and 10..20, 10 degrees), the score counts only the piece across the dateline: 0.10317460317460317 instead of 0.15476190476190477 at p = 0.5. The both-cross branch computes the width as right - left + 360, which is only that piece, while the branch for one crossing box already adds up both pieces.",
   "impact_class": "silent wrong results",
   "introduced_commit": "7e0aff8dabc4c3780f1e16a515646483cf92c2cc (trunk, svn r1608793) and its branch_4x backport c608265684cf73f50bf89bfbf252b7080769ee22 (svn r1608987, the copy that shipped first, in 4.10.0), 'LUCENE-5714, LUCENE-5779: Enhance BBoxStrategy & Overlap similarity. Configurable docValues / index usage. Add new ShapeAreaValueSource.', by dsmiley; no pull request (SVN + JIRA era; LUCENE-5714 is apache/lucene#6776, LUCENE-5779 is #6841). It created BBoxOverlapRatioValueSource with the documented intersection-area formula and rewrote the one-crossing branch to sum both pieces, but kept the both-cross single-arc formula. Origin of the formula: 26d3f1f813ea234ef443f237a932b187d65709a9 (svn r1354841, 2012-06-28, 'LUCENE-4175: adding bbox strategy', by ryantxu, #5247), whose unreleased trunk class AreaSimilarity had 'width = right + 360.0 - left'. [read]. Not a regression: the line is unchanged since (later commits on the block: LUCENE-6446 explanations and the LUCENE-9570 reformat)",
   "introduced_date": "2014-07-08 (trunk 7e0aff8dabc4); 2014-07-09 (branch_4x c608265684cf); the formula itself dates from 26d3f1f813ea, 2012-06-28 (unreleased trunk AreaSimilarity)",
   "first_affected_version": "4.10.0 [exec] (tag 2014-09-02, the first release with BBoxStrategy and BBoxOverlapRatioValueSource; fails with -ea and -da); 4.9.0 and 4.9.1 have no such API [exec]",
   "affected_versions": "Every release from 4.10.0 to 10.6.0 (10.6.0 by reading) and main ea57360912ed; not fixed upstream. [exec] the same pair scores 0.10317460317460317 instead of 0.15476190476190477 on 4.10.0 (-ea and -da), 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) (follow-up; 4.10.0 to 8.11.4 through main() ports of the same rectangles, public indexing path and oracle, each of which also scores a one-crossing two-piece control exactly; 8.11.4 and 9.0.0 through the JUnit with only the LuceneTestCase import changed; 9.1.0 on through the unchanged JUnit); the independent reproduction's own JUnit fails 4 of 5 on main (-ea and -da), 10.5.2 and 9.12.3. [read] all 103 release tags in the history clone that contain the class (4.10.0 to 8.8.1, 9.0.0 to 10.5.2) have the both-cross line unchanged; 8.8.2 to 8.11.3 are not in the clone (8.11.4 was executed); branch_10_6 has a file identical to main (not executed, so 10.6.0 is very likely affected). All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-369.html",
   "repro": "repro/LFV-369/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-240",
   "priority": "low",
   "priority_rank": 423,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / spell checking (DirectSpellChecker.suggestSimilar with a non-default StringDistance; FuzzyTermsEnum competitive-boost pruning)",
   "title": "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)",
   "summary": "You give DirectSpellChecker a metric such as LevenshteinDistance or JaroWinklerDistance and expect what setDistance documents: candidates drawn from the term dictionary by Damerau-Levenshtein (the internal similarity), then ranked by your metric. Since 7.0 the code stores your metric's score in ScoreTerm.boost, a field documented as the internal similarity, and then skips later candidates and tells FuzzyTermsEnum to lower its edit distance by comparing their internal similarity with that number, which is on a different scale, so better terms are never looked at. With default settings, the index {lucen, lucena, lucenb, lucenc, lucend, lucenes} and the query 'lucene', LevenshteinDistance returns 'lucen' (0.833) instead of 'lucenes' (0.857), and with maxInspections=1 and the index {lucen, lucenes} all three shipped metrics return 'lucen' although 'lucenes' scores higher under the internal similarity and under each metric.",
   "impact_class": "silent wrong results",
   "introduced_commit": "faf3bc3134c6e5ba3e2caa15762524872e083152 (LUCENE-7439 'clean up FuzzyQuery/FuzzyTermsEnum sources' by mikemccand, a JIRA patch now tracked as GitHub issue #8491, committed to master on 2016-09-12 with no pull request and not backported to branch_6x) [read]: the commit removed FuzzyTermsEnum's scale factor, changed 'st.boost = boost' (the enum boost) to 'st.boost = score' and the uncompetitive check from 'boost <= stQueue.peek().boost' to 'score <= stQueue.peek().boost'; with the scale factor gone this is neutral for the internal distance only. Later commits on the loop are mechanical: 9d72bfc1afe (LUCENE-9068, 9.0.0) replaced the attributes with e.getBoost()/e.setMaxNonCompetitiveBoost(), and 2cbf261032d reformatted it",
   "introduced_date": "2016-09-12",
   "first_affected_version": "7.0.0 [exec] (the first release containing faf3bc3134c; tag releases/lucene-solr/7.0.0 dated 2017-09-08 in the history clone); 6.6.6, the last release without it, passes [exec]; DirectSpellChecker and setDistance exist since 4.0.0-alpha (LUCENE-2507, 5190ea52329) and kept 'st.boost = boost' through 6.6.6 [exec]",
   "affected_versions": "every 7.x, 8.x, 9.x and 10.x release, 7.0.0 through 10.6.0 (10.6.0 by reading), and main ea57360912ed [read]; not affected: 4.0.0-alpha to 6.6.6 [exec]; not fixed on main (the defect lines are unchanged and no open PR changes them); release branches after 10.5.2 were not run, but branch_10_6 and the 10.6.0 tag (4ae946e5a9b) have the same DirectSpellChecker.java and FuzzyTermsEnum.java as main [read]. The per-release runs of the finder's maxInspections=1 test stop at the first failing metric (LevenshteinDistance); the JaroWinklerDistance and NGramDistance failures are executed on main only",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-240.html",
   "repro": "repro/LFV-240/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-647",
   "priority": "low",
   "priority_rank": 424,
   "novelty": "known",
   "withheld": false,
   "area": "suggest / spell: SpellChecker.indexDictionary de-duplication (cached searcher vs. the new IndexWriter's index; clearIndex, swapSearcher)",
   "title": "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)",
   "summary": "You build a spell index with SpellChecker.indexDictionary from the words {apple, banana}, then rebuild it from {apple, cherry}, passing an IndexWriterConfig with OpenMode.CREATE, which is documented as 'Creates a new index or overwrites an existing one'. You expect the spell index to hold apple and cherry. Instead it holds only cherry: the new writer starts from an empty index, but indexDictionary skips every word that its cached searcher of the old index still contains, so apple is silently dropped; the same stale check makes a call after a failed searcher reopen drop words (after clearIndex()) or index them twice (on a retry).",
   "impact_class": "silent wrong results",
   "introduced_commit": "Headline (fault-free OpenMode.CREATE) trigger: 0ea6a0058d5bc72deb6a506504b3f4acfa4ffe0a on branch_3x (first released in 3.5.0) and 369a07a196ef9e0692112f70486f09199b44050d on trunk (first released in 4.0.0-alpha / 4.0.0), both 'LUCENE-3557: SpellChecker should take IWC, remove sneaky silent optimize() methods' (@rmuir, 2011-11-04; JIRA-era patch, no pull request; now apache/lucene#4631, whose description and 3 comments do not mention OpenMode). It replaced indexDictionary(dict, mergeFactor, ramMB, optimize), which built its own IndexWriterConfig with the default CREATE_OR_APPEND, by indexDictionary(dict, IndexWriterConfig config, optimize) -> new IndexWriter(dir, config), and left the de-duplication against the cached searcher unchanged [read]. Failure-path triggers: LUCENE-2108 (apache/lucene#3184; trunk ab447b6af0653d1c1438b0aa4fa33b270814af65, @s1monw, 2009-12-05, first released in 3.1.0; backports bfe5f91cb884d53c53aec7e4eea7a6faf52ead02 to the 3.0 branch, 3.0.1, and be65c5c2e26a0fbd962da14b6aed734ec892fb96 to the 2.9 branch, 2.9.2, both @mikemccand, 2009-12-06) introduced swapSearcher, which opens the new searcher first and keeps the old, still-open searcher if that throws [exec]. Older background: the de-dup source became the cached searcher in LUCENE-1152 (a379a6787596, 2008-05-22, 2.4.0), and LUCENE-2391 (c26fd7564a5, 2011-01-05) wrote today's per-segment seekExact loop over that searcher [read].",
   "introduced_date": "2011-11-04 (LUCENE-3557, both branches; headline OpenMode.CREATE trigger); failure-path triggers 2009-12-05 (trunk ab447b6af06) / 2009-12-06 (2.9 and 3.0 backports)",
   "first_affected_version": "3.5.0 (2011-11-25) for the fault-free OpenMode.CREATE trigger [exec]; 2.9.2 and 3.0.1 (both 2010-02-24; 3.1.0 on the trunk line) for the failure-path triggers [exec]",
   "affected_versions": "Headline OpenMode.CREATE trigger: every final release from 3.5.0 to 10.5.2 [exec] plus main a9779ef3c193. Failure-path triggers (a failed searcher reopen after clearIndex() or indexDictionary(), then the instance is used again): every final release from 2.9.2 to 10.5.2 [exec] plus main. -da runs: probe A on 3.5.0 and 10.5.2, probe B on 2.9.2 and 10.5.2, same results. The finder's JUnit fails 3/3 on main (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 3/7 (its 3 bug tests; 4 controls pass) on main (-ea and -da), 10.5.2, 9.12.3 and 8.11.4 (8.x test base); the cross-model intended review's JUnit fails 3/5 on 10.5.2 and 9.12.3. Main with the candidate fix shadowed passes every probe and JUnit. [read] SpellChecker.java on upstream main is byte-identical to a9779ef3c193 and branch_10x differs only in a javadoc <pre> tag (2026-10-27). Not executed: the 4.0.0-alpha/beta pre-releases, the 'IndexWriter.close() throws after its commit' failure point on old releases, x86.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/2229",
    "https://issues.apache.org/jira/browse/LUCENE-1152",
    "https://github.com/apache/lucene/issues/1958",
    "https://issues.apache.org/jira/browse/LUCENE-883",
    "https://github.com/apache/lucene/issues/1940",
    "https://issues.apache.org/jira/browse/LUCENE-865"
   ],
   "doc": "",
   "repro": "repro/LFV-647/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-583",
   "priority": "low",
   "priority_rank": 425,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / SuggestStopFilter (query analysis of the analyzing and document suggesters)",
   "title": "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)",
   "summary": "You build an AnalyzingSuggester over 'one direction' and 'one of the best' with a StopFilter index analyzer and a SuggestStopFilter query analyzer, as the SuggestStopFilter javadoc recommends, and look up 'one of the ' (the user has typed 'the' and a space). You expect what a StopFilter query analyzer gives, [one of the best], because the class is documented as 'Like StopFilter' except that it keeps an unterminated last stop word, and StopFilter adds the positions of removed trailing stop words to the final position increment in end(). Instead SuggestStopFilter.end() reports the input's own final increment (0 instead of 2), so the lookup automaton has too few trailing holes and the lookup also returns 'one direction'; the tokens and the final offset are correct.",
   "impact_class": "silent wrong results",
   "introduced_commit": "e005a580e9f856e1cdebc3bf3230768911c7105c (branch_4x, svn r1515909, LUCENE-3849 'position increments should be implemented by TokenStream.end()', apache/lucene#4922, committed by mikemccand; the commit that shipped in 4.5.0) and its trunk twin 2a5421ca685b7341bbead24975cd218cbcaf34f7 (svn r1515887, first released in 6.0.0; git blame on main credits it with the SuggestStopFilter lines). Both capture endState right after input.end() and restore it in end() without adding skippedPositions or the removed last stop word's increment, while the same commit made FilteringTokenFilter.end() (StopFilter) add skippedPositions [exec]. The suggester-visible symptom starts with LUCENE-7619 (branch_6x 4e4ec082caa, trunk 637915b890d), which made TokenStreamToAutomaton turn the end() position increment into trailing holes [exec]",
   "introduced_date": "2013-08-20 (wrong end() increment, LUCENE-3849); 2017-01-17 (visible in suggesters, LUCENE-7619)",
   "first_affected_version": "4.5.0 (wrong end() increment) [exec]; 6.5.0 for the suggester-visible extra suggestions [exec]",
   "affected_versions": "Every release from 4.5.0 to 10.5.2 (114 release tags) and main a9779ef3c193 (unreleased 11.0) [read]. Executed: wrong end() increment on 4.5.0, 4.10.4, 5.5.5, 6.4.2, 6.5.0, 6.6.6, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main [exec]; extra suggestions on 6.5.0, 6.6.6, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main, not on 6.4.2 [exec]; JUnit fails on 9.12.3 and 10.5.2 (-ea) and on main (-ea and -da) [exec]. Not affected: 4.4.0 and earlier (no SuggestStopFilter) [exec]. Not fixed upstream: SuggestStopFilter.java has had only non-functional changes since 2013 (last a 2021 reformat) on main, branch_10x and branch_10_5 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-583.html",
   "repro": "repro/LFV-583/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-918",
   "priority": "low",
   "priority_rank": 426,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-common / Russian analyzer default stop words (RussianAnalyzer, snowball/russian_stop.txt; interaction with the Snowball RussianStemmer's ё-to-е fold)",
   "title": "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 е",
   "summary": "You analyze Russian text with the stock RussianAnalyzer. Its default stop list, the bundled Snowball russian_stop.txt, says in its header that 'letter ё is translated to е', so it lists её, ещё, всё, неё and чём only as ее, еще, все, нее and чем, and since 9.0 the same analyzer without stop words maps the ё and е spellings of every word that reaches its stemmer to one term. But the StopFilter runs before the only step that folds ё to е (the Snowball RussianStemmer), so the е spellings are removed while the ё spellings pass the StopFilter and are indexed as е, ещ, все, не and чем: 'Он все еще читает книгу' gives [чита, книг] but 'Он всё ещё читает книгу' gives [все, ещ, чита, книг], with no error.",
   "impact_class": "minor",
   "introduced_commit": "0203815ab2bf72a77fe8f58daa0e6e269e00e9a8 ('LUCENE-9220: regenerate all stemmers/stopwords/test data from snowball 2.0 (#1262)', apache/lucene-solr PR #1262 by rmuir; issue LUCENE-9220, now apache/lucene#10260) [read]. It regenerated org.tartarus.snowball.ext.RussianStemmer from Snowball 2.0, whose stem() first replaces every U+0451 with U+0435; it did not touch RussianAnalyzer, and the 159 entries of russian_stop.txt are identical before and after. So the defect is an interaction: the chain order StopFilter before SnowballFilter and the analyzer's use of the Snowball list (imported by LUCENE-2206), whose header states the ё-to-е precondition, both date from LUCENE-2055 (a6b7c5552ba, rmuir, 2010-02-05, first released in 3.1.0); from 3.1.0 to 8.11.4 that precondition was already unmet, but the stemmer kept ё distinct for every word too, so stop words were treated like all other words. Nothing in the PR or issue discusses Russian or ё.",
   "introduced_date": "2020-02-17 (authored and committed; PR merged 2020-02-17T17:38:02Z; master only, first released in 9.0.0)",
   "first_affected_version": "9.0.0 [exec] (the first release containing 0203815ab2b: the finder's JUnit, legacy-import variant, fails 4 of 6 with both controls passing, and the version-independent probe keeps 5 of 5 ё spellings while the stop-free chain maps both spellings to one term for 5 of 5 stop words and 5 of 5 ordinary words, with -ea and -da). Releases 3.1.0 to 8.11.4 also keep the ё spellings [exec], but there the stemmer keeps ё distinct for every word, so the analyzer-internal inconsistency does not exist; only the stop file's stated precondition is unmet. No 8.x release contains the commit.",
   "affected_versions": "Every 9.x and 10.x release, 9.0.0 through 10.5.2 (33 releases, git tag --contains 0203815ab2b), plus 10.6.0 (branch_10_6 4ae946e5a9b, the RC1 revision) and main a9779ef3c193; not fixed. [exec] the finder's JUnit or the follow-up probe fails on 9.0.0 (-ea and -da), 9.12.3, 10.0.0, 10.5.2, branch_10_6 4ae946e5a9b and main (-ea and -da); the independent reproduction's own JUnit fails on main (-ea and -da), 10.5.2 and 9.12.3, its main() form on 9.0.0 and main. [read] the other releases have the same chain order, the same ё fold and the same 159 entries; the later Snowball upgrades (#13209, #13227, 2024; #15505, 2025-12-18) kept the fold. Upstream main c5ab3e57b9ba (2026-10-28): last commit on analysis/ru 2026-01-15 (#15573, javadoc markup), on russian_stop.txt 2025-07-14 (#14933, build scripts), on RussianStemmer.java 2025-12-18 (#15505); none touches the chain or the stop lookup.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/12172",
    "https://github.com/apache/lucene/issues/13233",
    "https://issues.apache.org/jira/browse/LUCENE-1576",
    "https://github.com/apache/lucene/issues/2650",
    "https://issues.apache.org/jira/browse/LUCENE-1963",
    "https://github.com/apache/lucene/issues/3038"
   ],
   "doc": "",
   "repro": "repro/LFV-918/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-677",
   "priority": "low",
   "priority_rank": 427,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / language analyzers (TeluguAnalyzer default stop set te/stopwords.txt, applied after IndicNormalizationFilter and TeluguNormalizationFilter)",
   "title": "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",
   "summary": "You analyze Telugu text with the stock new TeluguAnalyzer(), whose default stop list (te/stopwords.txt) holds common function words such as కూడా ('also') that the analyzer should drop. The analyzer normalizes every token before its StopFilter and folds long vowel signs to short ones (ూ to ు, ీ to ి, ే to ె, ో to ొ), but the list holds only the unnormalized spellings, so the StopFilter sees కుడా and never matches the entry కూడా. As a result 13 of the 43 single-word default stop words are never removed and are indexed and searched as ordinary terms, while the Hindi analyzer, which has the same chain, ships the normalized forms in its list and removes all of its stop words.",
   "impact_class": "minor",
   "introduced_commit": "544dbbea46878b49be5c4c4e82d9b06a5679c891 (LUCENE-10083 'Analyzer and stemmer for Telugu language', apache/lucene PR #275 by vinodrenu, approved ('LGTM') and merged by rmuir on 2021-09-02; issue #11121; backported to branch_8x of the former lucene-solr repository as 114c9dff46c the same day) [read]. It is the commit that added TeluguAnalyzer, so the bug shipped with the feature and is not a regression: the stop list (blob ea175d67), the StopFilter placed after both normalization filters and the four long-vowel-sign folds were already in the PR's first commit c143ef618e (2021-08-13). te/stopwords.txt has had no commit since. The later TeluguAnalyzer.java commits do not change this behaviour: cc342ea7407 (LUCENE-10335, stop-file loading only), 9caeb9395da (#13059, normalize() only), 694d797526a, f99deb58b74 and 54283150a81 (visibility, formatting, comments).",
   "introduced_date": "2021-09-02 (merged on main and backported to branch_8x the same day; first released in 8.10.0)",
   "first_affected_version": "8.10.0 [exec] (the first release with TeluguAnalyzer; CHANGES lists LUCENE-10083 under 8.10.0 New Features). 8.9.0, the last release before it, has no Telugu analysis API [exec]. On the main line the first affected release is 9.0.0.",
   "affected_versions": "Every release that has TeluguAnalyzer, 8.10.0 through 10.6.0 (10.6.0 by reading), and main a9779ef3c193; not fixed. [exec] the follow-up's history matrix ran the finder's JUnit (2 tests, public API) 48 times: it fails 2 of 2 with the identical message (same 13 survivors) on all 40 releases (8.10.0, 8.10.1, 8.11.0-8.11.4, the 21 releases 9.0.0-9.12.3 and the 12 releases 10.0.0-10.5.2), on the introducing commit's sources over the 9.0.0 jars and on main, with extra -da runs on 8.10.0, 9.12.3, 10.5.2 and main; 8.9.0 does not compile (API absent); 8.10.0 with only the fixed stop list first on the classpath passes. The independent reproduction's own JUnit fails on main (-ea and -da), 10.5.2, 9.12.3, 8.11.4 and 8.10.0; the intended-behaviour check re-ran the finder's JUnit on main (-ea and -da) and on 10.5.2, 9.12.3 and 8.10.0 (-da), all failing. [read] te/stopwords.txt is the same blob (ea175d67) at every 9.x and 10.x tag, inside the 8.10.0 and 8.11.4 jars, on main, on the unreleased branch_10x head and on the head of branch_10_6, from which 10.6.0 was released on 2026-10-29 (read through the GitHub contents API on 2026-10-27, not executed); upstream main a95c754ee003 (2026-10-26) is unchanged.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-677.html",
   "repro": "repro/LFV-677/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-672",
   "priority": "low",
   "priority_rank": 428,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-common / Bengali analyzer default stop words (BengaliAnalyzer, bn/stopwords.txt; interaction with IndicNormalizationFilter and BengaliNormalizationFilter)",
   "title": "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",
   "summary": "You index Bengali text with the stock BengaliAnalyzer, whose constructor javadoc says it uses the default stop words from its bundled stopwords.txt, so a listed word such as কারণ ('because') should produce no token. But the analyzer runs IndicNormalizationFilter and BengaliNormalizationFilter before its StopFilter, and they rewrite letters (শ and ষ to স, ণ to ন, ঙ to ং, the ্য sign is dropped), while the bundled list holds only the original spellings, unlike the Hindi list in the same module, which also carries the normalized forms. So 13 of the 116 default stop words never match and are indexed and searched as ordinary terms (কারণ becomes কারন, শুধু becomes সুধু, অন্য becomes অন), with no error.",
   "impact_class": "minor",
   "introduced_commit": "1bca06b8a938bfe89b288877399942d217c8453d (the contributor's first commit of apache/lucene-solr PR #238, LUCENE-7940 'Bengali Analyzer for Lucene', now apache/lucene#8989; its message says 'LUCENE-7490', a typo for LUCENE-7940) [read]: it adds the chain IndicNormalizationFilter, BengaliNormalizationFilter, then StopFilter, then BengaliStemFilter together with bn/stopwords.txt, J. Savoy's list in its unnormalized spellings. It landed on master through the merge 08128f712fc and on branch_7x through the squashed backport e18532cb687 (both by rmuir, 2017-09-05; the backport is the commit that shipped in 7.1.0). Not a regression: the list's only later change is a trailing newline on main (560fd549f04, #15652, 2026-02-01) and the chain order never changed. The unreleased master commits between the first commit and the merge (3197d5af71d, 40dddf9324e) changed BengaliNormalizer, so the exact retained set at 1bca06b8a93 may differ from the 13 (not executed; not a release).",
   "introduced_date": "2017-08-24 (authored; landed on master and branch_7x 2017-09-05; first released in 7.1.0)",
   "first_affected_version": "7.1.0 [exec] (the first release with the org.apache.lucene.analysis.bn package; the follow-up's JUnit, run with the junitcore runner, and its version-independent main() both fail there with the same 13 of 116 words). 7.0.1, the last release before it, has no Bengali analysis API [exec], so no release ever removed these 13 words.",
   "affected_versions": "Every release that ships BengaliAnalyzer, 7.1.0 through 10.6.0 (10.6.0 by reading), and main a9779ef3c193; not fixed. [exec] the follow-up's JUnit and version-independent main() repros fail on 7.1.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea), each with the same 13 retained words; the finder's JUnit fails 2 of 2 on main (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 3 of 6 on main (-ea and -da), 10.5.2 and 9.12.3, and its main() keeps 13 of 116 on 7.1.0, 8.11.4 and main; the intended-behaviour check's fails on main (-ea and -da) and 10.5.2 (-da). [read] upstream main a95c754ee003 (2026-10-26), branch_10x 1309534296e3, branch_10_6 2763db11b0a7 and branch_10_5 have the same chain and the same list (read 2026-10-27).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16911",
    "https://github.com/apache/lucene/issues/14659",
    "https://github.com/apache/lucene/issues/9079",
    "https://github.com/apache/lucene/issues/3041",
    "https://issues.apache.org/jira/browse/LUCENE-1966"
   ],
   "doc": "",
   "repro": "repro/LFV-672/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-703",
   "priority": "low",
   "priority_rank": 429,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / language analyzers (default stop sets of SoraniAnalyzer, LatvianAnalyzer and GalicianAnalyzer; choice of WordlistLoader overload)",
   "title": "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",
   "summary": "You call SoraniAnalyzer.getDefaultStopSet(), LatvianAnalyzer.getDefaultStopSet() or GalicianAnalyzer.getDefaultStopSet(), documented as 'the default stop words set' built from the analyzer's bundled 'File containing default Kurdish/Latvian/Galician stopwords', and expect the stop words of that file; its '#' lines are comments, the format that about two dozen sibling analyzers load with the '#' comment marker and that StopFilterFactory's default 'wordset' format skips. Instead the three analyzers load the file with WordlistLoader.getWordSet(InputStream), which 'adds every line as an entry', so 60 of Sorani's 122 entries, 9 of Latvian's 170 (including a bare '#') and 1 of Galician's 161 are comment text such as '# set of kurdish stopwords', '# and' or '# galican stopwords'. The stock analyzers' tokens do not change, but code that lists, counts or reuses these sets sees the comments, and with a WhitespaceTokenizer the Latvian set removes a standalone '#' token ('lucene # search' gives [lucene, search]).",
   "impact_class": "minor",
   "introduced_commit": "One introducing commit per analyzer, each the commit that added the analyzer, all three by rmuir [read]: GalicianAnalyzer c7cfe0b8cc5525acb0ef5f515dc6b09d3412cb94 (branch_3x; trunk 61872be09dfd), LUCENE-2842 'add Galician analyzer' (migrated as apache/lucene#3916), first release 3.1.0; LatvianAnalyzer df3e3d735118 (branch_3x; trunk c3f63316390d), LUCENE-3016 (#4090), first release 3.2.0; SoraniAnalyzer a670b8d5b229 (branch_4x; trunk 2140f4368ade), LUCENE-5379 (#6442), first release 4.7.0. Each loaded its '#'-commented file with a no-comment WordlistLoader overload although the comment-aware overload existed in the same tree; later refactors (LUCENE-2564, LUCENE-5560, LUCENE-5859, LUCENE-9570, LUCENE-10335 cc342ea7407c, which gave today's getWordSet(IOUtils.requireResourceNonNull(getResourceAsStream(...))) form) kept the no-comment overload",
   "introduced_date": "2011-01-06 (Galician); 2011-04-14 (Latvian); 2014-01-04 (Sorani)",
   "first_affected_version": "3.1.0 [exec] (GalicianAnalyzer; LatvianAnalyzer from 3.2.0 [exec], SoraniAnalyzer from 4.7.0 [exec]; 3.0.3 has none of the three analyzers [exec])",
   "affected_versions": "Every release that contains one of the three analyzers, 3.1.0 to 10.5.2, and main a9779ef3c193, with -ea and -da [exec]. All 131 release tags from 3.1 to 10.5.2 in the history clone read the same way [read]; 8.8.2-8.11.3 are not tagged there (inferred from 8.8.1 [read] and 8.11.4 [exec]); 4.0.0-alpha/-beta by tag containment only. Not fixed: upstream main a95c754ee003 (2026-10-26) still has the three no-comment calls [read]; branch_10x was not checked.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-703.html",
   "repro": "repro/LFV-703/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-851",
   "priority": "low",
   "priority_rank": 430,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / WordDelimiterGraphFilterFactory and WordDelimiterFilterFactory types option (parseTypes) versus the default WordDelimiterIterator character-type table",
   "title": "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",
   "summary": "You give WordDelimiterGraphFilterFactory a types file with one rule for a character that is not in your text (for example '$ => DIGIT', or even '- => SUBWORD_DELIM', which '-' already is) and expect every other character to keep the type it has without the option. Instead parseTypes fills all 256 Latin-1 entries from WordDelimiterIterator.getType() (the Unicode general category), while the table the filter uses without the option is built from Character.isLowerCase/isUpperCase/isDigit; the two disagree on exactly 8 characters, so 'm² x³ 1½ ¼' analyzes to [m, ², x, ³, 1½, ¼] instead of [m, x, 1] and 'ªB' is no longer split. Nothing reports an error; a small change that seeds the Latin-1 entries from the default table fixes both factories.",
   "impact_class": "minor",
   "introduced_commit": "33cc5a041e8125a5ecf8e58c994fece4cfb03c7f (SOLR-2059 'Allow customizing how WordDelimiterFilter tokenizes text', SVN r990451 on trunk, by GitHub rmuir; SVN era, no GitHub PR) and its same-day branch_3x backport 878a697766c0 (r990456), which shipped in Solr 3.1.0: they add parseTypes with the comment 'ensure the table is always at least as big as DEFAULT_WORD_DELIM_TABLE for performance' and the loop 'types[i] = WordDelimiterIterator.getType(i)' over every entry, and make getType public for it [read]. The WordDelimiterGraphFilterFactory copy came with LUCENE-7619 (apache/lucene#8670, by GitHub mikemccand): branch_6x 4e4ec082caa7, master 637915b890d9 [read]. The two tables that disagree are older (Latin-1 table from the first WordDelimiterFilter, 148b4dbc923, 2006; the Character.getType switch with OTHER_NUMBER -> DIGIT and OTHER_LETTER -> ALPHA from SOLR-1078, 79414d2b726, 2009, used then only above the table); SOLR-2059 is the first change that types U+0000-U+00FF with getType. Later changes to these lines are formatting only (8ef6a0da5687 LUCENE-9570, 8ac26737913d LUCENE-10003). Not a regression: present since the option was added",
   "introduced_date": "2010-08-28 (SOLR-2059, author date 2010-08-28T21:25:44Z trunk, 22:01:10Z branch_3x); the WordDelimiterGraphFilterFactory copy 2017-01-17 (LUCENE-7619)",
   "first_affected_version": "Lucene 4.0.0-BETA [exec] (first Lucene artifact with WordDelimiterFilterFactory, moved from Solr into the analysis module; first GA release 4.0.0 [exec]; the 4.0.0-ALPHA Lucene jar has no factory, compile error [exec]); before that as Solr code from Solr 3.1.0 [exec]; WordDelimiterGraphFilterFactory from 6.5.0 [exec] (6.4.2 has no such factory [exec])",
   "affected_versions": "every Lucene release from 4.0.0-BETA to 10.5.2, the branch_10_6 head 4ae946e5a9b9 (10.6.0, released 2026-10-29) and main a9779ef3c193; Solr 3.1.0-3.6.2 as Solr code. [exec] Solr 3.1.0; Lucene 4.0.0-BETA, 4.0.0, 4.4.0, 4.10.4, 5.0.0 and 6.4.2 (WordDelimiterFilterFactory; the graph factory is absent), 6.5.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.5.2, branch_10_6 4ae946e5a9b9 and main (-ea and -da) (both factories); the candidate JUnit fails on 9.12.3, 10.5.2, branch_10_6 and main (-ea and -da); the independent reproduction's JUnit fails on main (-ea and -da), 10.5.2 and 9.12.3. [read] the key lines are identical apart from formatting at 3.1, 4.0.0-beta, 6.5.0, 8.8.1, 9.12.3, 10.5.2 and main; releases between the executed ones are inferred from tag containment and unchanged code. Not affected: Solr 1.4.1 and earlier (no types option, jar inspection). Not fixed upstream: upstream main 20ced71c1e6e (2026-10-27) last changed the two factories in 378ca8d1bbf3 (2026-01-15, javadoc tag). JDK caveat: the 6 number characters differ on every JDK; ª and º differ only where the JDK's Unicode data gives them category Lo (JDK 25: yes; Unicode 3.2 data: Ll, so on 2010-era JDKs most likely only 6 characters differed; no old JDK was run)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-851.html",
   "repro": "repro/LFV-851/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-862",
   "priority": "low",
   "priority_rank": 431,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / synonym.word2vec (Word2VecSynonymProvider.getSynonyms result cap; Word2VecSynonymFilter)",
   "title": "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",
   "summary": "You configure Word2VecSynonymFilter with maxSynonymsPerTerm=k, whose javadoc calls it the 'maximum number of result returned by the synonym search', so you expect at most k synonyms per token. Word2VecSynonymProvider.getSynonyms searches the HNSW graph for k+1 neighbours on the assumption that the query term is always its own nearest neighbour, drops only the query term and never caps the result, so when the term is not among the hits it returns all k+1. With three terms that share one vector and k=1, getSynonyms(c) returns [a, b] and the filter emits 2 SYNONYM tokens; with 4000 distinct clustered vectors and the factory defaults, 4 terms get 6 synonyms because the approximate search with a beam of 6 does not reach the query term itself, although it is its own strict nearest neighbour by a margin of more than 0.03.",
   "impact_class": "silent wrong results",
   "introduced_commit": "1f4f2bf50957ad1a13c32d5351c7de77154953f1 on main (apache/lucene#12169 'Introduced the Word2VecSynonymFilter', feature issue #12168; author dantuzi, co-author Alessandro Benedetti, merged by alessandrobenedetti; first in 10.0.0) and its branch_9x backport 64b48b89b501 (committed 2023-05-30, author date 2023-04-24; first in 9.7.0; an earlier backport 53709ccaecc was reverted by 7e15a390688 on 2023-04-25) [read]",
   "introduced_date": "2023-04-24 (main 1f4f2bf5095); 2023-05-30 (branch_9x re-backport 64b48b89b50, author date 2023-04-24)",
   "first_affected_version": "9.7.0 [exec] (the first release with the API; 9.6.0 has no synonym.word2vec package, the repro does not compile there [exec], although CHANGES.txt lists GITHUB#12169 under 9.6.0); first on the main line: 10.0.0 [exec]",
   "affected_versions": "Every release that has the API: 9.7.0 to 9.12.3 and 10.0.0 to 10.5.2, 24 releases [exec], the branch_10_6 head 4ae946e5a9b9 (10.6.0, released 2026-10-29) [exec] and main a9779ef3c193 [exec]. Not fixed upstream: the provider file is byte-identical in 9.12.3, 10.0.0, 10.5.2 and branch_10_6, main differs only by #15704 (collection type), and no commit on the package follows 7335eb0ad96 (#15704, author date 2026-02-26) on upstream main c5ab3e57b9b (2026-10-28) [read]. All runs on aarch64 Linux with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-862.html",
   "repro": "repro/LFV-862/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-518",
   "priority": "low",
   "priority_rank": 432,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / spell: SpellChecker.indexDictionary (n-gram spell index build)",
   "title": "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",
   "summary": "You index a word list into SpellChecker with one indexDictionary call, and the list contains a word twice, for example a PlainTextDictionary with the lines relieve, relieve, receive. You expect each word to be indexed once, as indexDictionary already ensures for words that were in the spell index before the call, so suggestSimilar(\"recieve\", 2) returns [relieve, receive]. Instead the duplicate check looks only at the spell index as it was before the call, so the repeated word is indexed twice and suggestSimilar returns [relieve, relieve], pushing receive out; the same words split over two calls are de-duplicated correctly.",
   "impact_class": "silent wrong results",
   "introduced_commit": "57cd0765650d0f73db37e090eaed4748fcd2fc82 (svn r151014, 2004-11-02, 'prelim checking of spellchecker, v1.1', the sandbox import of the contributed spellchecker; no pull request or JIRA issue, it predates both) [read]. In that first version indexDictionnary() skipped a word if exist(word), and exist() read an IndexReader opened at its first call and kept until the end of the indexing call, so words the writer had just added were never seen. Every rewrite kept that pre-call view: LUCENE-1152 a379a678759 (2.4.0), LUCENE-2108 ab447b6af06 (3.1) and LUCENE-2391 c26fd7564a5 / 9b6c71a5920 (3.1, rmuir, 2011-01-05), which wrote today's per-segment seekExact loop over the pre-call searcher and the skip on an empty index (main lines 497-512 and 525-530 blame there). LUCENE-883 3c4dc0484b8 (2.2.0) fixed only the consecutive-call case. Latent since the API was added, not a regression.",
   "introduced_date": "2004-11-02 (57cd0765650); the current form of the check dates from 2011-01-05 (LUCENE-2391, c26fd7564a5)",
   "first_affected_version": "1.9 (2006-02-27, the first release that ships contrib/spellchecker) [read]; 1.9.1 is the earliest release executed [exec] (1.9 has no Maven Central artifact); there is no unaffected earlier release: 1.4.3 ships no spellchecker",
   "affected_versions": "Every release from 1.9 to 10.5.2 (the last release before 10.6.0), plus main ea57360912ed. [exec] the follow-up's main() history probe (oracle: docFreq(word:relieve) after one call, on a fresh and on a non-empty index, with a split-across-calls control) is affected on 24 releases: 1.9.1, 2.0.0, 2.1.0, 2.2.0, 2.3.1, 2.4.1, 2.9.4, 3.0.3, 3.1.0, 3.4.0, 3.5.0, 3.6.2, 4.0.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0 and 10.5.2 (-ea; also -da on 9.12.3 and 10.5.2) and on main (-ea and -da), and passes on main with the fix shadowed; the 2004 introducing code compiled over the 1.9.1 core is affected too; the finder's JUnit fails on main (-ea and -da), 10.5.2 (-ea and -da), 10.0.0 and 9.12.3 (-ea and -da); the independent reproduction's JUnit fails on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's on main (-ea and -da) and 10.5.2. In 2.1.0 the across-call control also duplicates and suggestSimilar returns [] (stale searcher), both fixed in 2.2.0 by LUCENE-883; the within-call duplicate is present as everywhere else. [read] upstream origin/main a9779ef3c193 has SpellChecker.java identical to ea57360912ed, and branch_10x 1309534296e3 and branch_10_6 2763db11b0a7 identical to 10.5.2 (2026-10-26). Not executed: 1.9 itself (sources identical to 1.9.1), releases outside the matrix (same check structure by reading), x86.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-518.html",
   "repro": "repro/LFV-518/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-566",
   "priority": "low",
   "priority_rank": 433,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / spell: SpellChecker.suggestSimilar (index-based n-gram spell checker; comparator vs. full-queue accuracy cutoff)",
   "title": "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)",
   "summary": "You build an index-based SpellChecker with the shipped SuggestWordFrequencyComparator ('Frequency first, then score') and ask for suggestions restricted to a field, expecting the most frequent qualifying words among the retrieved candidates. Once the queue holds numSug words, suggestSimilar raises its accuracy cutoff to the score of the queue's head, which under this comparator is the least frequent queued word, so a later candidate that is more frequent but scores slightly lower is rejected before its frequency is even read. With 'receive' in 50 documents and one-edit neighbours such as 'relieve', 'reprieve' and 'retrieve' in one document each, suggestSimilar('recieve', 1, reader, field, SUGGEST_WHEN_NOT_IN_INDEX) returns [relieve] instead of receive (numSug 1-3 all leave it out; numSug 4 ranks it first).",
   "impact_class": "silent wrong results",
   "introduced_commit": "a63af850b076831ccd601c8e3ec8085a0df53fd5 (branch_3x, svn r986482, first shipped in 3.1.0) and its trunk twin f39ad7f02eecad81fb78ebf2a7723ee69babaae5 (svn r986477, first shipped in 4.0.0-ALPHA), both 'LUCENE-2479: Add support for alternate comparators for spelling' (JIRA LUCENE-2479, now GitHub issue #3553; svn era, no pull request) [read]. The commit added the Comparator constructor, setComparator, SuggestWordScoreComparator and SuggestWordFrequencyComparator and built the queue with the comparator, but left the full-queue cutoff unchanged. The cutoff itself comes from the 2004 sandbox import 57cd0765650 ('min=((SuggestWord) sugqueue.top()).score'), when the only order was score then frequency and the cutoff was a valid lower bound; later commits on those lines only renamed or reformatted them (895f763d214 2006, 3619c380d6f LUCENE-1968 insertWithOverflow, 5b83cc59b2e LUCENE-1257 generics, 1620366b5ca LUCENE-2608 min renamed to the accuracy parameter, 4c724b958b1 SOLR-2257 term-text tie-break in both comparators, 2cbf261032d LUCENE-9570 reformatting). Latent in the feature since it shipped, not a regression of the cutoff code",
   "introduced_date": "2010-08-17 (trunk 20:40:58 UTC, branch_3x 21:02:43 UTC); the cutoff line dates from 2004-11-02 (57cd0765650)",
   "first_affected_version": "3.1.0 [exec] (tagged 2011-03-30, the first release containing a63af850b07; contrib/spellchecker, artifact lucene-spellchecker); trunk line: 4.0.0-ALPHA [read], 4.0.0 [exec]; no earlier release is affected because the Comparator API did not exist: on 3.0.3 the repro does not compile (no SuggestWordFrequencyComparator) and the default-order control is consistent [exec]",
   "affected_versions": "every release from 3.1.0 to 10.6.0 (10.6.0 by reading), and main ea57360912ed. [exec] the follow-up's version-portable main() (scenario A: 'recieve' -> [relieve] at numSug=1; scenario B: numSug=2 -> [abcdefghijkl, abcdefgx] instead of the prefix [abcdefghijkl, abxdefyh]; default-comparator control) fails with the same outputs on 3.1.0, 3.4.0, 3.5.0, 3.6.2, 4.0.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea; also -da on 9.12.3, 10.5.2 and main), with the default-comparator control consistent in every run; the finder's JUnit fails 2 of 2 on main (-ea and -da), 10.5.2, 10.0.0 and 9.12.3; the independent reproduction's JUnit fails 3 of 4 on main (-ea and -da), 10.5.2, 10.0.0 and 9.12.3; the finder's portable main() fails on 8.0.0, 8.11.4 and 9.0.0. [read] 4.0.0-ALPHA and 4.0.0-BETA (tags contain f39ad7f02ee) and the releases between the executed ones (the cutoff and the comparator plumbing are unchanged since 2010); upstream origin/main a9779ef3c193 has SpellChecker.java, SuggestWordQueue.java and SuggestWordFrequencyComparator.java identical to ea57360912ed, and branch_10x 1309534296e3 and branch_10_6 2763db11b0a7 identical to 10.5.2 (2026-10-26). Not executed: 4.0.0-ALPHA/BETA, x86",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-566.html",
   "repro": "repro/LFV-566/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-538",
   "priority": "low",
   "priority_rank": 434,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / spell (WordBreakSpellChecker word breaks)",
   "title": "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",
   "summary": "You index some words and call WordBreakSpellChecker.suggestWordBreaks with setMaxChanges(3) or more, and you expect the maxSuggestions splits of the term that rank best by Lucene's own order (fewest breaks, then highest frequency). Instead, once an earlier branch of the search has filled the queue, a later branch returns before it looks for its own splits, so a better split can be missing: with the index {a, ab, b, c, d, e}, the term 'abcde', maxChanges=4 and maxSuggestions=1 the method returns [a b c d e] (4 breaks) instead of [ab c d e] (3 breaks), while asking for 2 suggestions returns both in the right order. No error is raised, raising maxChanges from 3 to 4 makes the answer worse, and 9.11.1 returns the right split.",
   "impact_class": "silent wrong results",
   "introduced_commit": "cc854f408fd06553de4780b1874992c16b71f26e (main) and its same-day branch_9x cherry-pick 3eadfe6031cbba1c150569bfb8669027347cb1bd, 'WordBreakSpellChecker.suggestWordBreaks now does a breadth first search (#12100)' by hossman, committed directly from a patch attached to issue #12100 (no pull request) [exec]",
   "introduced_date": "2024-07-10",
   "first_affected_version": "9.12.0 [exec] (9.x line, tagged 2024-09-28); on the 10.x line 10.0.0 [exec] (tagged 2024-10-14); last unaffected release 9.11.1 [exec]",
   "affected_versions": "main ea57360912ed (-ea and -da), 10.5.2, 10.0.0, 9.12.3 and 9.12.0 fail the finder's JUnit 3 of 3 [exec]; 9.12.1, 9.12.2 and 10.1.0-10.5.1 carry the same file blob (b3a84e9aaf on 9.12.x, 58d68a66bd on all 12 10.x tags before 10.6.0) [read]; not fixed upstream: the unguarded early return is unchanged on origin/main a9779ef3c19, branch_10x and branch_10_6 [read]; unaffected: 4.0.0-ALPHA (first release of the API) through 9.11.1, where the early return does not exist [read], executed passes on 8.11.4, 9.0.0 (import-adapted copy, with shadow controls that fail), 9.4.2, 9.5.0, 9.11.0 and 9.11.1 [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-538.html",
   "repro": "repro/LFV-538/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-986",
   "priority": "low",
   "priority_rank": 435,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / spell checking (DirectSpellChecker.suggestSimilar candidate budget numSug * maxInspections)",
   "title": "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",
   "summary": "You tell DirectSpellChecker to inspect as many candidates as it likes with setMaxInspections(Integer.MAX_VALUE) and ask suggestSimilar for 2 suggestions; you expect the best suggestions, at least as good as with a budget of 1000. Instead the internal budget numSug * maxInspections overflows int to -2: if the word has a one-edit neighbour the call throws NullPointerException, and if its only neighbours are two edits away it returns an empty array with no error. The outcome flips with the parity of numSug (1 and 3 work, 2 and 4 fail), and the one-line fix is to compute the budget in long and cap it at Integer.MAX_VALUE.",
   "impact_class": "silent wrong results",
   "introduced_commit": "5190ea52329 ('LUCENE-2507: Add automaton spellchecker', by Robert Muir (rmuir), author and commit date 2010-10-01, svn r1003642; JIRA LUCENE-2507, migrated as #3581; no pull request, Lucene used Subversion then): the commit that created DirectSpellChecker already had the unvalidated setMaxInspections, the int product 'int inspections = numSug * maxInspections;', the pass-2 guard 'terms.size() < inspections' and the unchecked stQueue.peek() dereference. The peek line was reworded by LUCENE-7439 (faf3bc3134c, 2016, boost -> score) without changing the check [read]",
   "introduced_date": "2010-10-01 (author and commit date of 5190ea52329; LUCENE-2507 resolved the same day)",
   "first_affected_version": "4.0.0-ALPHA [exec] (the first release with DirectSpellChecker, tag 2012-06-29; first GA release 4.0.0, 2012-10-11). The class is absent from every 1.x-3.x release [exec], so no release that has the API is unaffected",
   "affected_versions": "Every release that has DirectSpellChecker [exec]: all 132 Maven Central releases from 4.0.0-ALPHA to 10.5.2 (4.0.0-ALPHA, 4.0.0-BETA and 130 GA releases: 23 4.x, 15 5.x, 18 6.x, 14 7.x, 27 8.x, 21 9.x, 12 10.x; latest 9.x 9.12.3, 10.x through 10.5.2), 10.6.0 (released 2026-10-29; run as its RC, branch_10_6 4ae946e5a9b9) and main a9779ef3c193, each with the same outcomes (NPE leg, empty edit-distance-2 leg, parity row, default-setting truncation to 4 of 10); 4.0.0 also with -da. Bytecode check on all 134 suggest jars: the budget is an int multiply and the NPE frame line holds PriorityQueue.peek() then a ScoreTerm.boost read. The one-line saturating fix makes 4.0.0-ALPHA pass. Not fixed upstream: main 645d4fe14a20 still has 'int inspections = numSug * maxInspections;' at :359, and the newest commit on DirectSpellChecker.java on main, branch_11x, branch_10x and branch_10_6 is de3b294be44 (formatting, author date 2023-10-10) (recheck 2026-10-29). Caveat: all runs used JDK 25.0.3 on Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-986.html",
   "repro": "repro/LFV-986/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-999",
   "priority": "low",
   "priority_rank": 436,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / document (NRT) suggester: NRTSuggester.lookup topN = num x prefix paths (SuggestIndexSearcher.suggest with ContextQuery, RegexCompletionQuery or FuzzyCompletionQuery; Util.TopNSearcher)",
   "title": "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)",
   "summary": "You index suggestions with ContextSuggestField, one context each, so that one segment holds 10^6 distinct contexts, and call SuggestIndexSearcher.suggest(query, num, false) with a ContextQuery over a PrefixCompletionQuery that matches every context (no contexts added, which ContextQuery documents as 'suggest across all contexts', or a shared context prefix via addContext(prefix, boost, false)); you expect the top num completions, and num = 2147 does return 2147. With num = 2148 you get no suggestions and no error: NRTSuggester.lookup computes topN = num * prefixPaths.size() in int (NRTSuggester.java:142), 2148 x 10^6 wraps to -2146967296, and Util.TopNSearcher's loop 'while (results.size() < topN)' never runs. When the product wraps to a small positive value the list is silently cut to that many (3000 contexts and num = 1431656 return 704 of 3000), and a RegexCompletionQuery or FuzzyCompletionQuery with many matching prefixes behaves the same (1000 regex prefixes and num = 2147484 return none).",
   "impact_class": "silent wrong results",
   "introduced_commit": "Two stages, both by Areek Zillur [read]. Stage 1: be4d58c7740bea4e797eb1acff6355eb260e7c93 (trunk, svn r1682158) and 380bb29f39595de1c3947075296d1d0a36f02fd8 (branch_5x, r1682170), LUCENE-6459 'add common suggest API for document based NRT suggester' (#7518; Areek Zillur's patch, committed by Michael McCandless; Subversion era, no pull request) added ContextQuery, RegexCompletionQuery, FuzzyCompletionQuery and prefix paths, and passed the int product getCountToCollect() * prefixPaths.size() to getMaxTopNSearcherQueueSize only, so a small positive wrap bounds the queue and truncates the list (5.3.0). Stage 2: 4e2d9deff4a0251ea5f30d4f380f6f98d7411f2f (trunk, r1711158) and 714017f57430ede8820edb59ca7794a2583bf831 (branch_5x, r1711159), LUCENE-6858 (#7916, author and committer Areek Zillur) made the same int product the TopNSearcher topN ('final int topN = ...', blame on main NRTSuggester.java:133-142), which adds the empty-result leg (5.4.0)",
   "introduced_date": "2015-05-28 (stage 1, LUCENE-6459); 2015-10-28 (stage 2, LUCENE-6858)",
   "first_affected_version": "5.3.0 [exec] for the truncation leg (704 of 3000; the product fed only the queue size); 5.4.0 [exec] for the empty-result leg; 5.2.1 has no ContextQuery, RegexCompletionQuery or prefix paths, so the repro does not compile [exec]",
   "affected_versions": "5.3.0-5.3.2: truncation leg only [exec]; every release from 5.4.0 to 10.5.2: both legs [exec]; the int product is the TopNSearcher topN in all 91 local release tags from 5.4.0 to 10.5.2 [read]; 10.6.0 (released 2026-10-29; branch_10_6 4ae946e5a9b9) [exec]; main a9779ef3c193 [exec]. A saturating shadow patch restores every count on 5.3.2 (on the queue-size argument) and 5.4.0 (on topN) [exec]. Not fixed: upstream main 645d4fe14a20 (2026-10-28) still has 'final int topN = collector.getCountToCollect() * prefixPaths.size();' at line 142, and the newest commit on NRTSuggester.java is fe86094f2f4 on main and 9ca6ca0dba6 on branch_10x and branch_10_6 (#14364, author date 2025-03-19), which does not touch it [read]. Caveat: all runs used JDK 25.0.3 on Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-999.html",
   "repro": "repro/LFV-999/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-571",
   "priority": "low",
   "priority_rank": 437,
   "novelty": "new",
   "withheld": false,
   "area": "queries / MoreLikeThis query construction (MoreLikeThis.createQuery truncation at IndexSearcher.getMaxClauseCount)",
   "title": "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)",
   "summary": "You let MoreLikeThis select more terms than the global boolean clause limit, for example setMaxQueryTerms(2000) on a long text under the default limit of 1024, and call like(...). You expect the query, which createQuery deliberately truncates to the clause limit instead of failing, to keep the 1024 most interesting (highest tf*idf) of the selected terms, as it did up to 4.9.1. Instead createQuery pops its queue lowest score first and stops at the first TooManyClauses, so the query holds the 1024 lowest-scoring selected terms and none of the best ones (in the repro, 0 of the 76 top words survive).",
   "impact_class": "silent wrong results",
   "introduced_commit": "173a44e67c7c3c1a9ffbe7259ea8b45f1f53b015 (trunk, svn r1609474; the line main descends from, shipped from 6.0.0 on) and its branch_4x backport 1427d574d3dae460d638b8d6584116baf4756214 (svn r1609493, shipped in 4.10.0 and 5.x): LUCENE-5795 'More Like This: ensures selection of best terms is indeed O(n)' (now apache/lucene#6857; a JIRA patch committed by s1monw, CHANGES credits Alex Ksikes and Simon Willnauer; SVN era, no pull request; CHANGES 4.10.0 'Optimizations') [read]. It bounded the term queue to min(maxQueryTerms, #terms), flipped it from highest-first (FreqQ.lessThan 'fa > fb') to lowest-first ('a.score < b.score') and removed createQuery's own maxQueryTerms stop, but kept createQuery's pop-and-break-on-TooManyClauses loop, which dates from the first MoreLikeThis check-in (7952217cea6, 2005-01-17) and was correct only for a best-first queue; the issue thread (9 comments) never mentions the pop order or the clause limit. Later edits kept the behaviour: LUCENE-6570 (4aafacfbef4, BooleanQuery.Builder), LUCENE-6590 (962313b83ba, BoostQuery), LUCENE-8811 (53f56fb7ad4, the clause limit moved to IndexSearcher in 9.0), #14761 (a7704f5242d, 2025, FreqQ -> PriorityQueue.usingComparator, same ascending order) and ae82130c71b (catch parameter renamed to _)",
   "introduced_date": "2014-07-10",
   "first_affected_version": "4.10.0 [exec]",
   "affected_versions": "every release from 4.10.0 through 10.6.0 (10.6.0 by reading) and main ea57360912ed [exec]; not affected: 4.9.1 and older (4.9.0 and 4.9.1 [exec]; 2.4.0, 3.6.2 and 4.0.0 best-first by code reading); branch_10_6 (2763db11b0a, in the released 10.6.0) and the unreleased branch_10x (1309534296e) have the same code [read]; not fixed upstream [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-571.html",
   "repro": "repro/LFV-571/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1072",
   "priority": "low",
   "priority_rank": 438,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / spell (WordBreakSpellChecker word combinations)",
   "title": "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",
   "summary": "You configure a WordBreakSpellChecker with setMinSuggestionFrequency(2), whose javadoc says the minimum is 'Not applicable when used with SUGGEST_MORE_POPULAR', and ask suggestWordCombinations for SUGGEST_MORE_POPULAR suggestions; you expect every indexed combined word that is at least as frequent as its most popular part, which is the method's own MORE_POPULAR rule and what suggestWordBreaks does with the same setting. Instead the minimum still filters combinations: with sun, flower and sunflower in one document (docFreq 1 each), suggestWordCombinations([f:sun, f:flower], 5, reader, SUGGEST_MORE_POPULAR) returns no suggestion instead of sunflower. The cause is the check combinedTermFreq >= minSuggestionFrequency (WordBreakSpellChecker.java:208), which runs after the MORE_POPULAR rule in every mode.",
   "impact_class": "minor",
   "introduced_commit": "642b882d5a50721ab88ade17b06cd9e2927745b1 (trunk, svn r1344318, 'LUCENE-3523: Add WordBreakSpellChecker to suggest based on word combinations and/or breaks', by jdyer1; JIRA LUCENE-3523 = apache/lucene#4597; svn era, no pull request) and its same-day branch_4x commit 99fa008a71ef1600bf4217824f7786682432a48c (svn r1344329, the code 4.0.0-ALPHA ships). The class was born with all three pieces of the inconsistency: the setter javadoc 'Not applicable when used with SUGGEST_MORE_POPULAR', the suggestWordBreaks substitution useMinSuggestionFrequency = (origFreq == 0 ? 1 : origFreq) under SUGGEST_MORE_POPULAR, and the unconditional combinedTermFreq >= minSuggestionFrequency check in suggestWordCombinations (main :208, 4.0.0 :232) [read]. No later commit changed these lines (LUCENE-4587, #12077, #12100, #13328, #16255 and formatting commits touch other code). Not a regression.",
   "introduced_date": "2012-05-30 (trunk 642b882d5a5 at 15:58Z; branch_4x 99fa008a71e at 16:10Z)",
   "first_affected_version": "4.0.0-ALPHA [exec]; first GA release 4.0.0 [exec]; no earlier release has the API (3.6.0, 3.6.1 and 3.6.2 have no WordBreakSpellChecker [exec])",
   "affected_versions": "Every release that has WordBreakSpellChecker, 4.0.0-ALPHA through 10.6.0 (released 2026-10-29, 4ae946e5a9b), and main 645d4fe14a20 (unreleased 11.0); not fixed. [exec] the one public-API probe (one document with sun, flower, sunflower; control minSuggestionFrequency 1 returns [sunflower], probe 2 returns []) fails on 4.0.0-ALPHA, 4.0.0, 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2, 10.6.0 and main with -ea, and with -da on 4.0.0-ALPHA, 4.0.0, 10.6.0 and main; the one-test JUnit fails on main (-ea and -da), 10.6.0, 10.5.2 and 9.12.3 (9.x port: only the CombineSuggestion field access differs, the class became a record in 10.0 via #13328). [read] all 124 release tags 4.0.0-alpha..10.6.0 in the history clone contain the line-208 check, the setter javadoc and the suggestWordBreaks substitution (8.8.2 and 8.9.0-8.11.x are untagged in the clone; 8.11.4 was executed). Upstream main e1faeba08bd (2026-11-02) has a WordBreakSpellChecker.java byte-identical to 645d4fe14a20; branch_10_6 has the 10.6.0 copy, which differs from main only by a comment typo. Not new in 10.6. Executed on Linux aarch64 with JDK 25.0.3 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1072.html",
   "repro": "repro/LFV-1072/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1073",
   "priority": "low",
   "priority_rank": 439,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / spell (WordBreakSpellChecker word combinations)",
   "title": "WordBreakSpellChecker.suggestWordCombinations looks every combined word up in the field of terms[0], so a leading SEPARATOR_TERM silently disables all combination suggestions",
   "summary": "You call WordBreakSpellChecker.suggestWordCombinations with the class's own SEPARATOR_TERM in front of your terms, for example [SEPARATOR_TERM, f:sun, f:flower] on an index that holds f:sunflower, and expect the same 'sunflower' suggestion you get without the separator, because the separator is documented only to stop two adjacent terms from being combined. Instead you get no suggestion and no error: the code looks every combined word up in the field of terms[0], which for a leading separator is the empty field \"\", where nothing is indexed. The same line also picks the field when one call passes terms of several fields.",
   "impact_class": "minor",
   "introduced_commit": "642b882d5a50721ab88ade17b06cd9e2927745b1 (trunk, svn r1344318, 'LUCENE-3523: Add WordBreakSpellChecker to suggest based on word combinations and/or breaks', by James Dyer; JIRA LUCENE-3523 = apache/lucene#4597; svn era, no pull request) and its same-day branch_4x commit 99fa008a71ef1600bf4217824f7786682432a48c (svn r1344329, the code the 4.x releases ship): the class was born with SEPARATOR_TERM = new Term(\"\", \"\"), a leading separator skipped as a left term, and new Term(terms[0].field(), ...) for every combination [read]. LUCENE-4587 (927531255d48 trunk / 669fa5d4a6a branch_4x, 2012-12-07, first in 4.1.0) rewrote the line from BytesRef to String but kept terms[0].field(), which is why git blame on main :203 shows 927531255d48. Not a regression.",
   "introduced_date": "2012-05-30 (trunk 642b882d5a5 at 15:58Z; branch_4x 99fa008a71e at 16:10Z)",
   "first_affected_version": "4.0.0-ALPHA [exec]; first GA release 4.0.0 [exec]; 3.6.0, 3.6.1 and 3.6.2 are not affected because they have no WordBreakSpellChecker [read]",
   "affected_versions": "every release from 4.0.0-ALPHA through 10.6.0 (released 2026-10-29, 4ae946e5a9b), and main 645d4fe14a20 (unreleased 11.0) [exec]; the releases in between by a static check of all 124 releases/lucene* tags that contain the introducing commit, each with new Term(terms[0].field(), ...) exactly once [read]. Not new in 10.6 (10.5.2 fails the same test). Not fixed upstream: main e1faeba08bd (2026-11-02) and branch_10_6 still have the line at :203 [read]. Executed on Linux aarch64 with JDK 25 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1073.html",
   "repro": "repro/LFV-1073/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-800",
   "priority": "low",
   "priority_rank": 440,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / spell (WordBreakSpellChecker word breaks)",
   "title": "WordBreakSpellChecker.suggestWordBreaks ignores a maxChanges below 1: with setMaxChanges(0) it still returns one-break suggestions, while suggestWordCombinations returns none",
   "summary": "You configure a WordBreakSpellChecker with setMaxChanges(0), documented as 'The maximum numbers of changes (word breaks or combinations) to make on the original term(s)', and expect no word-break and no combination suggestions. suggestWordCombinations indeed returns none, but suggestWordBreaks still returns every one-break split: with the terms a, b and ab indexed, suggestWordBreaks('ab') returns [a, b] with score 1 (one break), and with sun and flower indexed 'sunflower' returns [sun, flower]; negative values behave the same. The method always makes the first break and reads maxChanges only before it tries a second one.",
   "impact_class": "minor",
   "introduced_commit": "642b882d5a50721ab88ade17b06cd9e2927745b1 (trunk, svn r1344318, 'LUCENE-3523: Add WordBreakSpellChecker to suggest based on word combinations and/or breaks', by jdyer1; JIRA LUCENE-3523 = apache/lucene#4597; svn era, no pull request) and its same-day branch_4x commit 99fa008a71ef1600bf4217824f7786682432a48c (svn r1344329, the code 4.0.0-ALPHA ships): the class was born with suggestWordBreaks starting generateBreakUpSuggestions at numberBreaks = 1 and maxChanges read only before the recursion to a second break [read]; LUCENE-4587 (927531255d4, 4.1.0), #12077 (9007f746a39, 9.5.0) and the #12100 breadth-first rewrite (cc854f408fd, 9.12.0) kept the unconditional first break. Not a regression.",
   "introduced_date": "2012-05-30 (trunk 642b882d5a5 at 15:58Z; branch_4x 99fa008a71e at 16:10Z)",
   "first_affected_version": "4.0.0-ALPHA [exec]; first GA release 4.0.0 [exec]; 3.6.2 is not affected because it has no WordBreakSpellChecker [exec]",
   "affected_versions": "every release that has WordBreakSpellChecker, 4.0.0-ALPHA to 10.5.2, 10.6.0 (by reading) and main a9779ef3c193 (unreleased 11.0) [exec]; the releases in between by the static check of all 123 release tags [read] (8.8.2-8.11.3 are untagged in the history clone and affected by inference). branch_10_6 and branch_10x heads: same WordBreakSpellChecker.java blob as 10.5.2 [read]. Not fixed upstream: origin/main 20ced71c1e6 has the same blob as a9779ef3c193, and no open PR changes the check [read]. Unaffected: 3.6.2 and earlier (no API) [exec]. Executed on Linux aarch64 with JDK 25 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-800.html",
   "repro": "repro/LFV-800/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-373",
   "priority": "low",
   "priority_rank": 441,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / hunspell (Hunspell.spell compound checking)",
   "title": "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)",
   "summary": "You load a Hunspell dictionary with CHECKCOMPOUNDTRIPLE, which hunspell(5) defines as 'Forbid compounding, if compound word contains triple repeating letters (e.g. foo|ox or xo|oof)', and expect Hunspell.spell to reject a compound with a triple letter at any boundary, as C Hunspell 1.3.2 and 1.7.2 do and as Lucene's own checkcompoundtriple fixture requires for bareeel (bare|eel). Instead Lucene rejects bareeel but accepts operabareeel, barebareeel and foobareeel (opera, bare or foo + bare|eel), and with the public Swedish dictionary (sv_SE) it accepts sommarmusikradiooomskuren while it rejects musikradiooomskuren. The cause: Hunspell.mayBreakIntoCompounds receives an absolute break position (the tail's offset in the word plus the relative break) but tests 'breakPos < length - 1' against the tail's relative length, so at the second and later boundaries the x|xx half of the check is skipped whenever the absolute break position is at least the tail length minus 1, while the xx|x half ('breakPos > offset + 1') is offset-aware and still works.",
   "impact_class": "silent wrong results",
   "introduced_commit": "9d45dfe776a29b50143a0eedce1ccda47c8bbac2, LUCENE-9710 'Hunspell: support minor compounding-related flags' (apache/lucene-solr#2272, by donnerpeter, merged by dweiss with no review comments; migrated issue apache/lucene#10749; a sub-task of LUCENE-9687, #10726), then in SpellChecker.java (renamed Hunspell.java by LUCENE-9765, 02ea7a11392) [read]. Reached 8.x through the squashed branch_8x backport c6b964a11576 (lucene-solr#2499, LUCENE-9687). Present since the check was first written; not a regression",
   "introduced_date": "2021-02-01 (main); 2021-05-28 (branch_8x backport)",
   "first_affected_version": "8.9.0 [exec] (the first release with the spell-checking API; 8.8.2 and older have no Hunspell or SpellChecker class [exec]); on the 9.x line 9.0.0 [exec]",
   "affected_versions": "every release that has the spell-checking API: 8.9.0 - 8.11.4, 9.0.0 - 10.5.2 and 10.6.0 (by reading), and main ea57360912ed. Executed (version-portable main() probe, COMPOUNDFLAG dictionary, -ea): 8.9.0, 8.10.0, 8.10.1, 8.11.0, 8.11.1, 8.11.2, 8.11.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main; the same probe with a COMPOUNDBEGIN/COMPOUNDMIDDLE/COMPOUNDEND dictionary on 8.9.0, 9.0.0, 10.5.2 and main, and with -da on 8.9.0; the JUnit fails on 9.12.3, 10.5.2 and main with -ea and -da [exec]. [read] the clause and its call are byte-identical at all 33 release tags 9.0.0 - 10.5.2 in the history clone. Not fixed upstream: Hunspell.java line 430 is unchanged on upstream main e1c4184cb983, branch_10x and branch_10_6 (2026-10-26). Not affected: 8.8.2 and older (no spell-checking API). 10.6.0 (released 2026-10-29) was read, not executed. All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-373.html",
   "repro": "repro/LFV-373/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-731",
   "priority": "low",
   "priority_rank": 442,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / hunspell (Hunspell.spell compound checking, COMPOUNDRULE)",
   "title": "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",
   "summary": "You load a Hunspell dictionary that joins foo/G and bar/H by 'COMPOUNDRULE GH', give foo or bar one of the per-entry flags KEEPCASE, FORCEUCASE, NEEDAFFIX or FORBIDDENWORD, call Hunspell.spell, and expect the answer C Hunspell 1.3.2 and 1.7.2 give (and Lucene itself gives when the same parts are joined by COMPOUNDFLAG): Foobar and FOOBAR rejected when foo is KEEPCASE, foobar rejected when bar is FORCEUCASE, and foobar rejected when foo is a NEEDAFFIX virtual stem or a FORBIDDENWORD entry. Instead spell() returns true in all four cases, with and without -ea, in every release since 8.9.0; on the public Swedish dictionary sv_SE it accepts lower-case rule compounds such as tolvkronorsgatan that the dictionary's FORCEUCASE flag and C Hunspell reject. The cause: checkCompoundRules takes every non-final part as a raw dictionary.lookupWord result, without the NEEDAFFIX, FORBIDDENWORD, COMPOUNDFORBIDFLAG and first-part case (KEEPCASE) filters, and checkLastCompoundPart never applies the FORCEUCASE check (hasForceUCaseProblem) that the COMPOUNDFLAG path uses.",
   "impact_class": "silent wrong results",
   "introduced_commit": "d7968130c3f5, LUCENE-9684 'Hunspell: support COMPOUNDRULE' (apache/lucene-solr#2228, by donnerpeter; issue apache/lucene#10723): it added checkCompoundRules with raw dictionary.lookupWord lookups for the parts and no case argument; git blame on main still points Hunspell.java:445 to it [read] [exec]. The FORCEUCASE form starts at 9d45dfe776a (LUCENE-9710, apache/lucene-solr#2272), which implemented FORCEUCASE on the COMPOUNDFLAG path only (before it Lucene ignored FORCEUCASE everywhere); 4b3fb1e0659 (LUCENE-9776, apache/lucene-solr#2397) moved only the last rule part to Stemmer.doStem, which fixed NEEDAFFIX for the last part only [exec]. Reached 8.x through the backport c6b964a1157 (apache/lucene-solr#2499, LUCENE-9687, merged 2021-05-28). Present since the feature's first commit, before any release; not a regression",
   "introduced_date": "2021-01-22 (main line, d7968130c3f); 2021-02-01 for the FORCEUCASE form (9d45dfe776a); 2021-05-28 (8.x backport)",
   "first_affected_version": "8.9.0 [exec] (the first release with the spell-checking API, through the 8.x backport; 8.8.2 has no Hunspell class [exec]); on the main line 9.0.0 [exec]",
   "affected_versions": "every release that has the spell-checking API: 8.9.0 - 8.11.4, 9.0.0 - 9.12.3 and 10.0.0 - 10.5.2, and main a9779ef3c193. Executed and failing 4 of 4 (the four claim assertions; no control fails): 8.9.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) [exec]; the independent reproduction independently executed main, 10.5.2 and 9.12.3 with its own test, and the cross-model reviews executed 10.5.2 and 9.12.3 [exec]. The other releases [read]: after 4b3fb1e0659, git log -L on checkCompoundRules and checkLastCompoundPart shows only refactors and performance changes (af97c5ef379, d537013e708, a454388b80e, ab453b9541a). Not affected: 8.8.2 and older (no spell-checking API) [exec]. Not fixed upstream: Hunspell.java and Stemmer.java last changed in ab453b9541ad (2025-02-27) on upstream main a95c754ee003 (2026-10-26), and no open PR touches them [read]. All runs on Linux aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-731.html",
   "repro": "repro/LFV-731/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-639",
   "priority": "low",
   "priority_rank": 443,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / hunspell (WordFormGenerator: getAllWordForms, generateAllSimpleWords)",
   "title": "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 [])",
   "summary": "You load a Hunspell dictionary in which an ordinary entry carries a compound-position flag, for example 'COMPOUNDBEGIN B', 'SFX A 0 s .' and the entry foo/AB (foo may also start a compound such as foobar), and ask Hunspell.getAllWordForms(\"foo\") for all forms of that entry. You expect [foo, foos]: Lucene's own spell() accepts both and analyzeSimpleWord() attributes them to foo/AB, as C Hunspell 1.7.2 also does, because COMPOUNDBEGIN/MIDDLE/END only allow a word to take part in compounds while ONLYINCOMPOUND is the flag that forbids it on its own. Instead you get [], because WordFormGenerator.shouldConsiderAtAll (WordFormGenerator.java:261-273) rejects the three compound-position flags together with FORBIDDENWORD and ONLYINCOMPOUND, both for the entry (so the entry yields nothing) and for affix continuation classes (so with 'SFX C 0 n/W' and W = COMPOUNDEND, getAllWordForms(\"Computer\") never yields Computern, a word in Lucene's own germancompounding .good list); generateAllSimpleWords skips the same entries.",
   "impact_class": "silent wrong results",
   "introduced_commit": "d537013e70872015364c745e5f320727efc034b7 (apache/lucene#975 'LUCENE-10626 Hunspell: add tools to aid dictionary editing', by donnerpeter, approved by dweiss; issue LUCENE-10626, migrated as #11662), merged to main 2022-07-05; on branch_9x as the cherry-pick 3b763af12f576b8b8120e98ae38b7a67461a99e8 (committed 2023-01-13), which is how it reached 9.5.0 [read] [exec]. Not a regression: the exclusion is as old as the generator, and spell() already accepted the words on 9.4.2 and 9.5.0, so generation and spell-checking have disagreed on them since the generator's first release.",
   "introduced_date": "2022-07-05 (merged to main); 2023-01-13 (branch_9x cherry-pick 3b763af12f5)",
   "first_affected_version": "9.5.0 [exec] (the first release with Hunspell.getAllWordForms and WordFormGenerator; first 10.x release 10.0.0 [exec]); 9.4.2 and older are unaffected only because the API is absent (the repro is a compile error on 9.3.0, 9.4.0, 9.4.1 and 9.4.2 [exec])",
   "affected_versions": "every release from 9.5.0 through 10.6.0 (26 releases through 10.5.2, and 10.6.0 by reading) and main a9779ef3c193; never fixed. [exec] the finder's JUnit fails 2/2 at the two getAllWordForms assertions on all 26 releases and main with -ea, and with -da on 9.5.0, 9.12.3, 10.0.0, 10.5.2 and main (32 failing runs, follow-up); the independent reproduction's JUnit fails the same 6 of 9 tests (its 3 controls pass) on main (-ea, -da), 9.5.0, 9.12.3, 10.0.0 and 10.5.2. Not affected: 9.4.2 and older (no API). All runs on aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-639.html",
   "repro": "repro/LFV-639/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-932",
   "priority": "low",
   "priority_rank": 444,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / hunspell (Dictionary FLAG UTF-8 parsing under the SET encoding)",
   "title": "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)",
   "summary": "You load a Hunspell dictionary whose affix file says FLAG UTF-8 (flags are UTF-8 characters) and SET ISO8859-2, KOI8-R, microsoft-cp1251 or another 8-bit encoding except ISO8859-1, with two suffix classes whose flags are, say, U+00E1 and U+00E2, and expect what C Hunspell 1.3.2 and 1.7.2 do on the same bytes: a word that carries only the first flag takes only the first suffix. Instead Lucene reads the flags from text already decoded with the SET charset, so each 2-byte flag becomes two characters and an affix rule keeps only the first one, the shared lead byte: both classes merge, spell() accepts the forbidden forms (kote, lasa in the repro) and the stemmer returns kot for kote, with no error. Only no SET, SET ISO8859-1 and SET UTF-8 work; ISO8859-14 merges too (its decoder reports ISO-8859-1 as its charset, and the re-encode turns remapped flag bytes into '?'), and with ISO8859-3, -6 or -8 the load throws UnmappableCharacterException because a flag byte is unassigned in that charset.",
   "impact_class": "silent wrong results",
   "introduced_commit": "e3172b9239c (trunk) / 1e084f1d08e (branch_3x), LUCENE-3414 'Added Hunspell for Lucene' (apache/lucene#4487, no PR, SVN era), first released in 3.5.0: FLAG UTF-8 mapped to SimpleFlagParsingStrategy (one flag per char of the line already decoded with the SET charset). The symptom then changed twice: a4b6ef84dd0 (branch_4x) / 2c98dd5b320 (trunk), LUCENE-5517 (#6580, 4.8.0) made parseFlag throw 'expected only one flag', so the same dictionaries were rejected at load; then 7a7949aed2a, LUCENE-9708 (#10747, PR apache/lucene-solr#2270) added DefaultAsUtf8FlagParsingStrategy only for the ISO-8859-1 charset, and 1cc26b6bb44, LUCENE-9724 (#10763, PR apache/lucene-solr#2307) set checkFlags = false, which turned the load error back into the silent merge for every other 8-bit SET. Both 2021 commits first shipped in 9.0.0 and, through the LUCENE-9687 bulk backport c6b964a1157 (PR apache/lucene-solr#2499), in 8.9.0. The fix site (getFlagParsingStrategy / the flag strategies) is LUCENE-3414 code patched for ISO-8859-1 only by LUCENE-9708; LUCENE-9724 only changed the symptom. [read]",
   "introduced_date": "2011-09-10 (LUCENE-3414, author date); current silent form 2021-02-01 (LUCENE-9708) and 2021-02-07 (LUCENE-9724), author dates; 8.x backport 2021-05-28",
   "first_affected_version": "3.5.0 [exec] (tagged 2011-11-25), the first release with the Hunspell module; 3.4.0 has no Hunspell API [exec]. Current silent form since 8.9.0 (8.x line) and 9.0.0 [exec]; 4.8.0-8.8.2 reject the same dictionaries at load instead [exec]",
   "affected_versions": "Every release that has the Hunspell module, 3.5.0 to 10.6.0 (10.6.0 run as its release revision, branch_10_6 4ae946e5a9b), and main a9779ef3c193, with three symptoms for FLAG UTF-8 plus an 8-bit SET other than ISO8859-1 [exec]. 3.5.0-4.7.2: flags silently merged, even for ISO8859-1 (tested ISO8859-1, -2 and -15; ISO8859-14 is not a supported charset there). 4.8.0-8.8.2: the same dictionaries rejected at load with IllegalArgumentException 'expected only one flag', ISO8859-1 included (tested ISO8859-1, -2, -14 and -15). 8.9.0-8.11.4 and 9.0.0-main: ISO8859-1 and no SET correct; ISO8859-2, -4, -5, -7, -9, -13, -14, -15, KOI8-R, KOI8-U, microsoft-cp1251 and TIS620-2533 silently merge (main, 18-value probe). ISO8859-3 fails to load in every release tested. [read] getFlagParsingStrategy is unchanged on upstream main 645d4fe14a20 (2026-10-28); open PR #16422 rewrites it as a switch with the same ISO-8859-1-only test. Not fixed upstream. All runs on Linux aarch64 with JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-932.html",
   "repro": "repro/LFV-932/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-693",
   "priority": "low",
   "priority_rank": 445,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-stempel / egothor stemmer trie reductions (Optimizer, Optimizer2; Compile tool, Trie.reduce)",
   "title": "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",
   "summary": "You build a stempel table with the Compile tool and a method string that has two merge passes (for example '-M22' or '-0ME22'), or you call reduce(new Optimizer2()) (or Optimizer) on a table that a merge pass already reduced, such as a loaded table; Optimizer2's javadoc says its row joining keeps the stemmer able to 'recognize words for which the original trie was built', so the training words should keep their stems, as they do after one pass. Instead the second pass silently corrupts the trie: two Optimizer2 passes over the one-word trie {aab -> Da} lose its only entry, Compile '-22' stems every training form of a small table to null and '-M22' leaves every form unstemmed (while '-2' and '-M2' are correct), and one more Optimizer2 pass over the bundled Polish table changes 8,356 of 21,147 keys whose whole path is stored. The cause is Optimizer.optimize (inherited by Optimizer2): it walks the rows from the highest index down and remaps every child reference through a remap[] array that is still 0 for rows it has not placed yet, which is only correct when every child has a higher index than its parent; a freshly built trie has that property, but the output of a merge pass does not (shared rows, self-loops, pre-order renumbering).",
   "impact_class": "silent wrong results",
   "introduced_commit": "98c47c57e0a54ab4aab9d91dd60c33edef130893 (trunk, svn r940433, 'LUCENE-2298: Add stempel, an algorithmic stemmer with included Polish support', committed by GitHub rmuir on 2010-05-03; issue LUCENE-2298 = apache/lucene#3374, no pull request in the svn era): the import of the whole org.egothor.stemmer package, whose Optimizer.optimize already leaves remap[] unfilled and walks the rows downward; the release line got it through the branch_3x backport 58328f0379049045b325d2082295836a7a50e9ce (svn r941704, 2010-05-06). Not a regression: the code is the Egothor stemmer (the StempelStemmer javadoc says the implementation is 'taken verbatim from the Egothor project'), and the prior-report search found the same loop in a 2010 copy of the original Stempel source, so the defect most likely predates Lucene. Later commits only reformatted these lines (8ac26737913 LUCENE-10003, dbaf97f5dcc #14965) or changed Row's cell map (6e2a8fc9b75 #13420, backport 6f774936ef6) [read]",
   "introduced_date": "2010-05-03 (trunk 98c47c57e0a; branch_3x backport 58328f03790 on 2010-05-06)",
   "first_affected_version": "3.1.0 [exec] (tagged 2011-03-30; the first release with the stempel module, through the branch_3x backport; the trunk commit first shipped in 4.0.0-ALPHA). No release that has the API is unaffected: 3.0.3 has no stempel module [exec].",
   "affected_versions": "Every release that ships stempel, 3.1.0 to 10.5.2, and main a9779ef3c193; no upstream fix. [exec] [read]. Since 9.11.0 (Row cells in a hash map, the #13420 backport) the exact counts differ (the probe's '-0ME22' check changes 31 instead of 27 of 94 Polish training forms); the defect is the same.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-693.html",
   "repro": "repro/LFV-693/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-694",
   "priority": "low",
   "priority_rank": 446,
   "novelty": "new",
   "withheld": false,
   "area": "analysis/stempel / egothor stemmer table serialization (Row.store vs Row(DataInput); Gener, Compile 'G', StempelStemmer.load)",
   "title": "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",
   "summary": "You compile a stemmer table with the stempel Compile tool using a method string that contains G (Gener, the reduction that drops infrequent commands), or reduce a trie with Gener and store it, and expect StempelStemmer.load to read the table back and stem like the trie that was stored. Instead Row.store writes the number of all cells of a row and then skips the empty cells (no command and no reference) that Gener leaves behind, so Row(DataInput) reads too many cell records and runs into the next row: usually load fails with java.io.EOFException (Compile -0ME2G, -0M2G and -0MEG on an 11-lemma Polish table, -EG on a 20-line table, the bundled table reduced with Gener, which then has 38,322 empty cells), and sometimes the table loads without error but answers wrongly (Compile G on a 4-line dictionary: for 'walked' the expected patch is Db and the loaded table gives null). Writing getCells(), the existing count of the non-empty cells, fixes it in one line and changes no byte of any table without empty cells, such as the bundled table and every table compiled without G.",
   "impact_class": "silent wrong results",
   "introduced_commit": "98c47c57e0a54ab4aab9d91dd60c33edef130893 (trunk, SVN r940433, 'LUCENE-2298: Add stempel, an algorithmic stemmer with included Polish support', JIRA LUCENE-2298 'Polish Analyzer', now GitHub issue #3374; patch attached by @rmuir, CHANGES credits Andrzej Bialecki via Robert Muir; SVN era, no pull request), branch_3x backport 58328f0379049045b325d2082295836a7a50e9ce ('LUCENE-2298: backport', r941704, the copy that shipped in 3.1.0): the first import of the stempel module already had Row.store write cells.size() and skip cells with cmd < 0 && ref < 0, Row(DataInput) read exactly that count, Gener.eat create such cells, and Compile handle 'G' and then store the trie [read]; not a regression: the bug is as old as the module in Lucene. The same count/skip pattern is in the original Egothor2 v4.0.4 code (as imported by another contributor's fork) and in the Lucene.NET port [read]",
   "introduced_date": "2010-05-03 (trunk 98c47c57e0a5); branch_3x backport 2010-05-06 (58328f03790)",
   "first_affected_version": "3.1.0 [exec]; 3.0.3 and earlier have no stempel API (lucene-stempel 3.0.3 is not on Maven Central, and the probe does not compile against core + analyzers 3.0.3: 'package org.egothor.stemmer does not exist') [exec], so no release has the API without the bug",
   "affected_versions": "every release from 3.1.0 through 10.5.2 and main a9779ef3c193 (unreleased 11.0) [exec]; the releases in between [read]. Results are the same before (9.12.3) and after (10.0.0) the #13420 iterator change. The silent-misread variant was executed on main only, not per release. Not fixed upstream: upstream main a95c754ee003 still writes cells.size() at Row.java:232, branch_10x and branch_10_6 are unchanged, so 10.6.0 (released 2026-10-29 from branch_10_6) is affected too, and no open PR changes Row.store (2026-10-27) [read]. lucene/analysis/stempel is identical at ea57360912ed and a9779ef3c193 (empty git diff). Executed on Linux aarch64 with JDK 25 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-694.html",
   "repro": "repro/LFV-694/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-377",
   "priority": "low",
   "priority_rank": 447,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / hunspell (Hunspell.spell and suggest compound checking, CHECKCOMPOUNDPATTERN replacements)",
   "title": "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)",
   "summary": "You load a Hunspell dictionary whose CHECKCOMPOUNDPATTERN rule has a replacement, which hunspell(5) documents as 'The optional replacement parameter allows simplified compound form' (for example 'CHECKCOMPOUNDPATTERN ff f ff' from the Hunspell ChangeLog, for pre-reform German Schiffahrt = Schiff + Fahrt), and expect Hunspell.spell to accept the simplified form wherever it occurs in a compound, as native Hunspell 1.3.2 and 1.7.2 do for dampfschiffahrt, donaudampfschiffahrt, barfozar and barfur, and to return true or false for every word. Instead Lucene accepts schiffahrt but rejects dampfschiffahrt and donaudampfschiffahrt (and barfozar, barfur and barbozan on the content of its own checkcompoundpattern2/3 fixtures), and spell()/suggest() throw StackOverflowError for schiffschiffahrt, for 'auu' with the one-word dictionary au and 'CHECKCOMPOUNDPATTERN u u u', and for words of native Hunspell's own checkcompoundpattern4 (Telugu sandhi) fixture. The cause: CheckCompoundPattern.expandReplacement builds the expanded word from the start of the whole word (word.chars[0 .. word.offset + breakPos], which keeps the earlier compound parts for the FORCEUCASE check) but returns it as a CharsRef with offset 0, while its callers index it relative to the current part, so at the second and later boundaries the stem lookup starts at the beginning of the word and the remaining tail never gets shorter.",
   "impact_class": "silent wrong results",
   "introduced_commit": "902cb93db2274a0a1d424fb69fdd6be645887da5, LUCENE-9775 'Hunspell: make FORCEUCASE work when the first compound word is inherently title-case' (apache/lucene-solr#2375, by donnerpeter; migrated issue apache/lucene#10814), on lucene-solr master, now part of the apache/lucene main history [read] [exec]. Reached 8.x through the squashed branch_8x backport c6b964a11576 (lucene-solr#2499, LUCENE-9687; commit id from the ASF git bot comment on LUCENE-9687, not in the local clone; the bad line is in the 8.9.0 bytecode). A regression against the 2021-02-03 feature commit, but no release ever had the feature without the bug",
   "introduced_date": "2021-02-17 (main); 2021-05-28 (branch_8x backport)",
   "first_affected_version": "8.9.0 [exec] (the first release with the spell-checking API and CHECKCOMPOUNDPATTERN; 8.8.2 has no Hunspell class and does not compile the repro [exec]); on the main line 9.0.0 [exec]",
   "affected_versions": "every release that has the feature: 8.9.0 - 8.11.4, 9.0.0 - 9.12.3 and 10.0.0 - 10.6.0 (10.6.0 by reading), and main ea57360912ed. Executed (history probe or version-portable main(), -ea): 8.9.0, 8.10.1, 8.11.4, 9.0.0, 9.4.2, 9.8.0, 9.12.3, 10.0.0, 10.3.2, 10.5.2 and main; the finder's and the independent reproduction's JUnits fail on 9.12.3, 10.5.2 and main (main also -da), the intended-behaviour check's German example on 9.12.3 and main (-ea and -da) [exec]. [read] javap shows the same new String(chars, 0, offset + breakPos) construction in expandReplacement in every cached analysis-common jar from 8.9.0 to 10.5.1, and all 21 9.x and 12 10.x release tags contain 902cb93. Not affected: 8.8.2 and older (no spell-checking API) [exec]. Not fixed upstream: no commit after 902cb93 changes expandReplacement, and no open apache/lucene PR touches CheckCompoundPattern.java or Hunspell.java (2026-10-26). All runs on Linux aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-377.html",
   "repro": "repro/LFV-377/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-374",
   "priority": "low",
   "priority_rank": 448,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / hunspell (affix conditions: Dictionary loading, Hunspell.spell/getRoots, Stemmer and HunspellStemFilter)",
   "title": "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",
   "summary": "You load a Hunspell dictionary with the suffix rule 'SFX A abc d [c]' (strip abc, add d, condition [c]) on the root xabc and expect the condition to be tested where Hunspell lines it up, at the end of the root, which for a condition shorter than the strip is the end of the strip: xd should be a correct word with stem xabc and 'SFX A abc e [a]' should never apply, as C Hunspell 1.3.2 answers and as Lucene itself answers when the same condition is written as the literal c. Instead Lucene rejects xd and accepts xe as a form of xabc, and the prefix rules 'PFX B abc d [a]' and 'PFX B abc e [c]' on the root abcx are reversed the same way (dx rejected, ex accepted); spell, getRoots and HunspellStemFilter give these wrong verdicts and stems with no error. The cause is AffixCondition.compile: for a condition with [ ] or . and no more character patterns than the strip, it decides the rule once at load by matching the strip against 'kind == PREFIX ? \".*\" + condition : condition + \".*\"', which tests the strip's start for SFX and its end for PFX, the two templates swapped between the kinds.",
   "impact_class": "silent wrong results",
   "introduced_commit": "3a99e2aa82d860b6a319cea39607ab3c8ef590b5, LUCENE-9806 'Hunspell: speed up affix condition checking' (apache/lucene-solr#2423, by donnerpeter, reviewed by rmuir, merged 2021-02-24; migrated issue apache/lucene#10845; a sub-task of LUCENE-9687, #10726) [read]. Reached 8.x through the branch_8x backport c6b964a11576 (lucene-solr#2499, LUCENE-9687; identical line at its AffixCondition.java:94). A regression: before it, Dictionary built 'isSuffix ? \".*\" + condition : condition + \".*\"' and matched it against the whole root (stem plus strip), which is correct; the commit moved the check onto the strip alone and gave each template to the other kind",
   "introduced_date": "2021-02-24 (main); 2021-05-28 (branch_8x backport)",
   "first_affected_version": "8.9.0 [exec] (all 19 releases from 8.0.0 to 8.8.2 are correct [exec]; the stemming path exists in every 8.x release, while the spell-checking class Hunspell first ships in 8.9.0); on the 9.x line 9.0.0 [exec]",
   "affected_versions": "every release from 8.9.0 to 8.11.4, 9.0.0 to 9.12.3 and 10.0.0 to 10.5.2 (41 releases), 10.6.0 (by reading) and main ea57360912ed. Executed: the version-portable public-API probe (Dictionary + HunspellStemFilter, 6 bug cases xd, xe, data, quanta, redo, repack with expected values from C Hunspell 1.3.2, plus 2 literal-condition controls) on all 60 Maven Central releases from 8.0.0 to 10.5.2 and on main with -ea and -da: 8.0.0-8.8.2 correct, 8.9.0-10.5.2 and main wrong in all 6 cases, controls pass everywhere; the finder's JUnit fails on main (-ea, -da), 10.5.2 and 9.12.3 (it compiles from 9.9.0 on); the independent reproduction's JUnit fails on main (-ea, -da), 10.5.2 and 9.12.3. [read] the line is identical at 10.5.2, 9.12.3 and 9.0.0. Not fixed upstream: main 645d4fe14a2 still fails [exec]; the template is unchanged on branch_10x 657014b3c57 and branch_10_6 4ae946e5a9b [read] and on branch_10_5 [read]. 10.6.0 (released 2026-10-29) was read, not executed. All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-374.html",
   "repro": "repro/LFV-374/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-642",
   "priority": "low",
   "priority_rank": 449,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / hunspell (Stemmer affix compatibility: COMPLEXPREFIXES twofold prefixes)",
   "title": "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)",
   "summary": "You load a hunspell dictionary that sets COMPLEXPREFIXES (twofold prefix stripping) with the outer prefix 'PFX A 0 re', an inner prefix class C with two rules, 'un' without a continuation class and 'dis/A', and the root foo/C, and expect what hunspell(5), C Hunspell 1.3.2 and 1.7.2 and Lucene up to 9.4.2 do: re may only precede dis, so redisfoo is a word and reunfoo is not, just as Lucene still checks the mirror-image twofold suffixes rule by rule. Instead spell(\"reunfoo\") is true, getRoots(\"reunfoo\") is [foo] and HunspellStemFilter turns the token reunfoo into foo, because since 9.5.0 Stemmer.isAffixCompatible returns true for any prefix stripped after another prefix (Stemmer.java:541, 566) and the only remaining gate is the dictionary-wide check that some prefix rule carries the flag A (Dictionary.isSecondStagePrefix).",
   "impact_class": "silent wrong results",
   "introduced_commit": "d537013e70872015364c745e5f320727efc034b7 (apache/lucene#975, LUCENE-10626 'Hunspell: add tools to aid dictionary editing: analysis introspection, stem expansion and stem/flag suggestion', a feature PR by donnerpeter; issue migrated as #11662), merged to main 2022-07-05; reached branch_9x as the cherry-pick 3b763af12f576b8b8120e98ae38b7a67461a99e8 (committed 2023-01-13), first released in 9.5.0 [read] [exec]. Same commit as LFV-375, different line and different fix",
   "introduced_date": "2022-07-05 (merged to main); 2023-01-13 (branch_9x cherry-pick, author date kept as 2022-07-05)",
   "first_affected_version": "9.5.0 [exec] (10.0.0 on the 10.x line [exec]); 9.4.2 is the last unaffected release [exec]: it was released after the main commit but cut from branch_9x before the cherry-pick",
   "affected_versions": "9.5.0 - 9.12.3, 10.0.0 - 10.6.0 (10.6.0 by reading) and main a9779ef3c193. [exec] the finder's JUnit fails on 9.5.0 (-ea and -da), 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da), a main() spell() variant fails on 9.5.0, 9.12.3, 10.5.2 and main and a main() HunspellStemFilter variant on 9.5.0, 9.12.3, 10.0.0, 10.5.2 and main (follow-up); the independent reproduction's JUnit fails 3 of 4 on main (-ea and -da), 10.5.2, 9.12.3 and 9.5.0; upstream main a95c754ee003, branch_10x and branch_10_6 still do (2026-10-27, source only). Not affected: 4.8.0 - 9.4.2 [exec]; before 4.8.0 there was no twofold prefix stripping [read]. All runs on aarch64 with JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-642.html",
   "repro": "repro/LFV-642/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-638",
   "priority": "low",
   "priority_rank": 450,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / hunspell (WordFormGenerator: canStemToOriginal, getAllWordForms, generateAllSimpleWords, compress)",
   "title": "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",
   "summary": "You load a Hunspell dictionary with 'NEEDAFFIX X', 'SFX A 0 s/XB' (so foos needs one more suffix), 'SFX B 0 en' and an unrelated class 'SFX C 0 s', with the entries foo/A and bar/C, and call Hunspell.getAllWordForms(\"foo\"). You expect [foo, foosen]: spell() rejects foos (C Hunspell 1.7.2 does too), and the generator's check canStemToOriginal is documented to keep only forms that are 'accepted by the spell-checker and analyzed to be the form of the original dictionary entry'. Instead you get [foo, foos, foosen], because canStemToOriginal accepts as soon as any affix-stripping path gives back the stem text, here class C, which foo does not even have, and ignores which affixes were stripped (WordFormGenerator.java:211); generateAllSimpleWords leaks the same words, and compress([kat, kater, katern]) suggests kat/PQ, which does not accept kater.",
   "impact_class": "silent wrong results",
   "introduced_commit": "d537013e70872015364c745e5f320727efc034b7 (apache/lucene#975 'LUCENE-10626 Hunspell: add tools to aid dictionary editing', by donnerpeter, approved by dweiss; issue LUCENE-10626, migrated as #11662), merged to main 2022-07-05; on branch_9x as the cherry-pick 3b763af12f576b8b8120e98ae38b7a67461a99e8 (2023-01-13), which is how it reached 9.5.0 [read] [exec]. Not a regression: the text-only comparison is as old as the generator. The spell-checker has rejected these NEEDAFFIX pseudo-affix forms since LUCENE-9706 (#10745, commit 4ba78f2ab25, 2021-01-29, first released in 9.0.0), which also added the needaffix5 fixture whose .wrong file lists them.",
   "introduced_date": "2022-07-05 (merged to main); 2023-01-13 (branch_9x cherry-pick 3b763af12f5)",
   "first_affected_version": "9.5.0 [exec] (the first release with Hunspell.getAllWordForms and WordFormGenerator; first 10.x release 10.0.0 [exec]); 9.4.2 and older are unaffected only because the API is absent (the repro is a compile error on 9.3.0, 9.4.0, 9.4.1 and 9.4.2 [exec])",
   "affected_versions": "every release from 9.5.0 through 10.6.0 (26 releases through 10.5.2, and 10.6.0 by reading) and main a9779ef3c193; never fixed. [exec] the finder's JUnit fails 1/1 at the same assertion (actual [foos]) on all 26 releases from 9.5.0 to 10.5.2 with -ea, also with -da on 9.5.0, 9.12.3 and 10.5.2, and on main with -ea and -da (31 failing runs, follow-up); the independent reproduction's JUnit fails 2 of 4 on main (-ea and -da), 10.5.2, 9.12.3 and 9.5.0; the intended-behaviour check's fails 3 of 4 on main (-ea, -da) and 10.5.2. Not affected: 9.4.2 and older (no API). All runs on aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-638.html",
   "repro": "repro/LFV-638/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-376",
   "priority": "low",
   "priority_rank": 451,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / hunspell (AffixCondition: affix conditions used by Hunspell.spell/suggest and by stemming through Stemmer/HunspellStemFilter)",
   "title": "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",
   "summary": "You load a Hunspell dictionary with the rules 'SFX A b x [a-c]' and 'SFX A b y [^a-c]' on the root ab and expect [a-c] to mean what hunspell(5) says, the set {a, -, c} ('Dash hasn't got special meaning'), so the first rule never applies (ab ends in b) and the second one does: C Hunspell 1.3.2 and 1.7.2 reject ax and accept ay. Instead Lucene's Hunspell.spell accepts ax and rejects ay (likewise xa and ya for the PFX twins on ba), and HunspellStemFilter stems ax to ab and leaves ay unstemmed. AffixCondition.compile decides the part of a condition that overlaps the strip once, at load time, with String.matches (java.util.regex) on the raw condition text, which reads [a-c] as a range, while the part checked against the stem goes through escapeDash; a reversed pseudo-range such as [c-a] even makes java.util.regex throw, and the rule is silently turned into 'never applies'.",
   "impact_class": "silent wrong results",
   "introduced_commit": "3a99e2aa82d860b6a319cea39607ab3c8ef590b5, LUCENE-9806 'Hunspell: speed up affix condition checking' (apache/lucene-solr#2423, by GitHub donnerpeter, merged 2021-02-24 into lucene-solr master, which became 9.0; migrated issue apache/lucene#10845, a sub-task of LUCENE-9687 / #10726) [read] [exec]. Reached 8.x through the squashed branch_8x backport c6b964a11576 (lucene-solr#2499, LUCENE-9687, 2021-05-28; the backported file has the same raw calls). A regression: Lucene had escaped the dash in the whole condition since the 2014 Hunspell rewrite (LUCENE-5468) and LUCENE-5777 (1e881bf7931, 2014-06-19); the PR's stated purpose was speed only",
   "introduced_date": "2021-02-24 (main); 2021-05-28 (branch_8x backport)",
   "first_affected_version": "8.9.0 [exec]; on the 9.x line 9.0.0 [exec]",
   "affected_versions": "8.9.0 - 8.11.4, 9.0.0 - 9.12.3, 10.0.0 - 10.6.0 (10.6.0 by reading) and main ea57360912ed. Executed: the portable probe fails on 8.9.0, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main and passes on 8.0.0, 8.8.1 and 8.8.2; the finder's JUnit fails 3 of 4 on main (-ea and -da), 10.5.2 and 9.12.3 (it needs SortingStrategy, so not on 9.0.0/9.1.0); the independent reproduction's JUnit fails 6 of 8 on main (-ea and -da), 10.5.2 and 9.12.3. [read] the releases in between: the three calls are unchanged at every 9.x and 10.x tag that contains 3a99e2aa82d8 (git log -L), and on branch_8x c6b964a11576 is the only change to AffixCondition.java, which first ships in the 8.9.0 jar. Stemming (Dictionary + Stemmer, HunspellStemFilter) existed before 8.9.0 and was correct there; the Hunspell spell/suggest class first ships in 8.9.0, so spell() is affected in every release that has it. Not fixed upstream: main 645d4fe14a2 still fails [exec]; AffixCondition.java:108/113/120 are unchanged there (#16919 touched the file only at :126 and :147) and on branch_10x 657014b3c57 and branch_10_6 4ae946e5a9b [read]. Releases before 8.0.0 not executed. All runs on aarch64 with JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-376.html",
   "repro": "repro/LFV-376/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-724",
   "priority": "low",
   "priority_rank": 452,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / hunspell (Hunspell.spell compound checking, COMPOUNDWORDMAX)",
   "title": "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",
   "summary": "You load a Hunspell dictionary with 'COMPOUNDFLAG C', 'COMPOUNDMIN 1', 'COMPOUNDWORDMAX 1' and the words foo/C and bar/C, call Hunspell.spell(\"foobar\"), and expect false: hunspell(5) defines COMPOUNDWORDMAX as the maximum word count in a compound, and C Hunspell 1.3.2 and 1.7.2 reject foobar. Instead Lucene returns true, with and without -ea; COMPOUNDWORDMAX 0, which the parser clamps to 1, behaves the same, while with COMPOUNDWORDMAX 2 Lucene correctly accepts foobar and rejects foobarfoo. The cause: checkCompounds counts parts only when a previous part exists ('prev != null && prev.index > compoundMax - 2'), so the first part is never counted and checkCompoundsAfter accepts first part + last part at any limit; the original LUCENE-9699 check, which did enforce a limit of 1, was lost in a 2021 refactoring (LUCENE-9729).",
   "impact_class": "minor",
   "introduced_commit": "650f16ad5d8e, LUCENE-9729 'Hunspell: support CHECKCOMPOUNDREP flags' (apache/lucene-solr#2300, by donnerpeter; issue apache/lucene#10768), in the PR's refactoring sub-commit f78cc2563024 'LUCENE-9729: [Hunspell] refactoring': it replaced 'if (depth > dictionary.compoundMax - 2) return false;' (depth 0 at the first part, so COMPOUNDWORDMAX 1 rejected every compound, as written by LUCENE-9699 a176308aa63, apache/lucene-solr#2248, issue apache/lucene#10738) with 'if (prev != null && prev.index > dictionary.compoundMax - 2) return false;', which skips the first part [read] [exec]. Reached 8.x through the backport apache/lucene-solr#2499 (LUCENE-9687, merged 2021-05-28). Both the feature and the regression predate every release, so no release ever enforced COMPOUNDWORDMAX 1 and it is not a regression of a released version",
   "introduced_date": "2021-02-05 (main line; the sub-commit is dated 2021-02-03); 2021-05-28 (8.x backport)",
   "first_affected_version": "8.9.0 [exec] (the first release with the spell-checking API, through the 8.x backport; 8.8.2 has no Hunspell class [exec]); on the main line 9.0.0 [exec]",
   "affected_versions": "every release that has the spell-checking API: 8.9.0 - 8.11.4, 9.0.0 - 9.12.3 and 10.0.0 - 10.5.2, and main a9779ef3c193. Executed and failing: 8.9.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) [exec]; the independent reproduction and the intended-behaviour check independently executed 8.9.0, 8.11.4, 9.0.0, 9.12.3 and 10.5.2 with their own tests [exec]. The other releases [read]: the guard line is byte-identical in all 33 release tags from 9.0.0 to 10.5.2, and the 8.9.0 bytecode (javap) has the same guard. Not affected: 8.8.2 and older (no spell-checking API) [exec]. Not fixed upstream: Hunspell.java:214 is unchanged on upstream main a95c754ee003 (2026-10-26) and no open PR changes it [read]. All runs on Linux aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-724.html",
   "repro": "repro/LFV-724/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-634",
   "priority": "low",
   "priority_rank": 453,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / hunspell (WordFormGenerator: getAllWordForms, generateAllSimpleWords, compress)",
   "title": "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]",
   "summary": "You load a Hunspell dictionary in which a prefix rule's continuation class allows a suffix, for example 'PFX U 0 kilo/S' and 'SFX S 0 s' with the entry ampere/U, and ask Hunspell.getAllWordForms(\"ampere\") for all forms of that entry. You expect ampere, amperes, kiloampere and kiloamperes: Lucene's own spell() accepts all four and analyzeSimpleWord() analyses each one as a form of ampere/U, as C Hunspell 1.7.2 also does. Instead you get only [ampere, kiloampere], because WordFormGenerator applies suffixes only from the entry's own flags and then forbids any suffix once a prefix has been applied (WordFormGenerator.java:378); generateAllSimpleWords misses the same words, and compress() suggests an unneeded flag (for work/P with 'PFX P 0 re/S', compress([work, rework, reworks]) proposes work/PS, which also adds the unrequested word works).",
   "impact_class": "silent wrong results",
   "introduced_commit": "d537013e70872015364c745e5f320727efc034b7 (apache/lucene#975 'LUCENE-10626 Hunspell: add tools to aid dictionary editing', by donnerpeter, approved by dweiss; issue LUCENE-10626, migrated as #11662), merged to main 2022-07-05; on branch_9x as the cherry-pick 3b763af12f576b8b8120e98ae38b7a67461a99e8 (2023-01-13), which is how it reached 9.5.0 [read] [exec]. Not a regression: the guard is as old as the generator. The spell-checker side has accepted this affix pattern since LUCENE-9688 (#10727, commit 0a1a3f4c409, 2021-01-22, first released in 9.0.0), 17 months before the generator existed.",
   "introduced_date": "2022-07-05 (merged to main); 2023-01-13 (branch_9x cherry-pick 3b763af12f5)",
   "first_affected_version": "9.5.0 [exec] (the first release with Hunspell.getAllWordForms and WordFormGenerator; first 10.x release 10.0.0 [exec]); 9.4.2 and older are unaffected only because the API is absent (the repro is a compile error on 9.3.0, 9.4.0, 9.4.1 and 9.4.2 [exec])",
   "affected_versions": "every release from 9.5.0 through 10.6.0 (26 releases through 10.5.2, and 10.6.0 by reading) and main a9779ef3c193; never fixed. [exec] the finder's JUnit fails 1/1 at the same assertion on all 26 releases from 9.5.0 to 10.5.2 with -ea, also with -da on 9.5.0, 9.12.3 and 10.5.2, and on main with -ea and -da (31 failing runs, follow-up); the independent reproduction's JUnit fails 4 of 5 on main (-ea and -da), 10.5.2, 9.12.3 and 9.5.0; the guard is also present on upstream main a95c754ee003, branch_10x and branch_10_6 (source check only, not executed). Not affected: 9.4.2 and older (no API). All runs on aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-634.html",
   "repro": "repro/LFV-634/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-318",
   "priority": "low",
   "priority_rank": 454,
   "novelty": "new",
   "withheld": false,
   "area": "index / addIndexes reorder path: SlowCompositeCodecReaderWrapper doc-ID-to-reader lookup (stored fields, term vectors), reached through misc BPReorderingMergePolicy or any OneMerge#reorder",
   "title": "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",
   "summary": "You call IndexWriter.addIndexes(CodecReader...) with a 3-document reader, an empty reader (maxDoc() == 0) and a 2-document reader on a writer whose merge policy reorders the merge, such as BPReorderingMergePolicy or any OneMerge#reorder that returns a DocMap (the identity is enough), and you expect all 5 documents to keep their stored fields and term vectors, as they do with the same call without reordering. Instead the merged view that IndexWriter builds for the reorder (SlowCompositeCodecReaderWrapper) has doc starts [0, 3, 3, 5], Arrays.binarySearch finds start 3 at the empty reader's index, and docIdToReaderId keeps that exact hit, so merged doc 3 (the first document of the third reader) is read as doc 0 of the empty reader. The new segment is written without any error under -ea and -da: that document is still found by its id term and keeps its doc values, but its stored fields and term vectors are gone.",
   "impact_class": "data corruption",
   "introduced_commit": "f7cab1645017d863331b42900581b67d3591e2da on main and its branch_9x backport 6b1538b33136a4737ad0d22b3633e62f3d7f362b (identical patch), PR #12622 'Add a merge policy wrapper that performs recursive graph bisection on merge.' (jpountz): it created SlowCompositeCodecReaderWrapper with docStarts (prefix sums of maxDoc) and docIdToReaderId (Arrays.binarySearch, correction only on a miss), OneMerge#reorder and the merged-view call in IndexWriter.addIndexesReaderMerge [read]. Commit-level builds of f7cab164501 and its parent were not run (the parent has no reorder hook to express the repro)",
   "introduced_date": "2023-11-23 (f7cab164501 on main and the branch_9x backport 6b1538b3313)",
   "first_affected_version": "9.9.0 [exec] (tagged 2023-12-04, through the branch_9x backport 6b1538b3313; fails with -ea and -da); on the 10.x line 10.0.0 [exec]; 9.8.0 is the last unaffected release (no merged view, no OneMerge#reorder, no BPReorderingMergePolicy) [exec]",
   "affected_versions": "Every release from 9.9.0 through 10.6.0 (10.6.0 by reading; the 22 releases through 10.5.2: 9.9.0-9.9.2, 9.10.0, 9.11.0, 9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2) and main ea57360912ed [exec]. Not affected: 9.7.0 and 9.8.0 [exec]. Not fixed: docIdToReaderId is textually identical at all 22 tags and on main [read], and unchanged on main, branch_10x and branch_10_6 on 2026-10-26 [read]; the 10.6 line (10.6.0, released 2026-10-29) was not executed. All runs on aarch64 Linux, JDK 25 (plain Java logic, no vector code).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-318.html",
   "repro": "repro/LFV-318/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1133",
   "priority": "low",
   "priority_rank": 455,
   "novelty": "new",
   "withheld": false,
   "area": "index / index sorting at merge: MultiSorter doc maps, reached through IndexWriter.addIndexes(CodecReader...)",
   "title": "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",
   "summary": "You sort an IndexWriter by a long field k and call addIndexes(CodecReader...) with the single segment of a sorted 2-document index {a k=1, c k=2} followed by an empty reader that advertises the same sort (SortingCodecReader.wrap(SlowCodecReaderWrapper.wrap(new ParallelLeafReader()), sort)), and you expect a 2-document segment in which a TermQuery on id:a returns the document that stores a, as it does without an index sort or with the empty reader listed first. Instead MultiSorter.sort also queues a cursor at doc 0 for the empty reader, whose nonexistent doc 0 (missing sort value 0) is popped first and takes merged doc id 0, so a and c are mapped to 1 and 2 while the new segment has maxDoc 2. With assertions disabled addIndexes and commit succeed, but id:a returns the document that stores c and the posting of id:c points at doc 2 (>= maxDoc 2), which only CheckIndex at level 2 or higher reports.",
   "impact_class": "minor",
   "introduced_commit": "fdc220eeb42 on branch_6x (committed 2016-06-11; the copy that shipped in 6.2.0) and 54fa7dfd271 on master (reached master through the index_sort branch merge d715210467a, 2016-05-13), both 'LUCENE-6766: initial patch' by Mike McCandless for LUCENE-6766 'Make index sorting a first-class citizen' (migrated issue #7824; no PR, the work was done on a git branch against the JIRA issue): it created MultiSorter.java with the init loop that queues a doc-0 cursor for every reader without a maxDoc() > 0 check [read]",
   "introduced_date": "2016-05-04 (author date of both fdc220eeb42 and 54fa7dfd271; branch_6x commit date 2016-06-11)",
   "first_affected_version": "6.2.0 [exec] (tagged 2016-08-20; fails with -ea and -da, passes with the skip-empty MultiSorter shadow); on the master line first released in 7.0.0 [read]; 6.1.0 and earlier are not affected (no IndexWriterConfig.setIndexSort, no MultiSorter class) [exec]",
   "affected_versions": "Every release from 6.2.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT) [read]. Executed (fail): history runs of the independent reproduction's test body (adapted to each era) on 6.2.0 (-ea, -da), 6.4.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.6.3, 8.7.0, 8.11.4, 9.0.0 and 9.12.3 (-da); the independent reproduction's one test unchanged on 9.12.3, 10.5.2, 10.6.0 and main (-ea and -da each) and an API-adapted copy on 8.11.3 (-da); the finder's test on 10.0.0, 10.6.0 (-da) and main (-ea, -da); the intended-behaviour check on 10.6.0 (-da); a separate re-run on main (-ea, -da). The trigger form changed, the root cause did not: 6.2.0-7.7.3 accept any maxDoc-0 reader into a sorted writer, 8.0.0-8.6.3 need one that advertises the sort (LUCENE-8505, e.g. a FilterCodecReader), and from 8.7.0 on the SortingCodecReader form works (LUCENE-9484); in 6.2.0-6.3.0, before the LUCENE-7568 isSorted fast path, listing the empty reader first also corrupts (executed), while from 6.4.0 on that order is masked. Not new in 10.6. Not fixed upstream: MultiSorter.java is unchanged on upstream main 1c2072f0284 (author date 2026-11-02), branch_10_6 and branch_10x since e6f12f31d08 (#16202, author date 2026-06-05) [read]. Executed on Linux aarch64 with JDK 25.0.3 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1133.html",
   "repro": "repro/LFV-1133/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-788",
   "priority": "low",
   "priority_rank": 456,
   "novelty": "known",
   "withheld": false,
   "area": "memory / MemoryIndex reader FieldInfos vs term vectors (consequence in index / addIndexes(CodecReader...) term-vector merge)",
   "title": "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",
   "summary": "You build a MemoryIndex with MemoryIndex.fromDocument from a document whose body field stores term vectors and whose title is a plain TextField, copy its reader into an index with IndexWriter.addIndexes(SlowCodecReaderWrapper.wrap(reader)), and expect a clean index, as when the same document is added with IndexWriter.addDocument. Instead the copy succeeds and CheckIndex (level 2 or higher) reports the new segment broken, 'docID=0 has term vectors for field=title but FieldInfo has storeTermVector=false', because the MemoryIndex reader returns term vectors for every field with terms while, since 6.5.0, its FieldInfo takes storeTermVector from the field type. The bad segment survives merges with natively added documents, and the MemoryIndex reader itself already fails TestUtil.checkReader, even for a document that has only a plain TextField.",
   "impact_class": "silent wrong results",
   "introduced_commit": "6696eafaae18948c2891ce758c7a2ec09873dab8 (master, the 7.0 line) and its branch_6x backport cecc44c731b18c46bf2c0eaa92732eb207daa6ca (released in 6.5.0): LUCENE-7679 / apache/lucene#8730 'MemoryIndex.addField() ignores some FieldType settings' (an omitNorms fix; a JIRA patch by GitHub romseygeek, no GitHub PR), which replaced the storeTermVector argument true, set by LUCENE-6402 (apache/lucene#7462, commit 58107a2b760, GitHub rmuir, 5.2.0), with fieldType.storeTermVectors() in the new createFieldInfo and left termVectors() unchanged [read] [exec]. A regression of the closed LUCENE-6402",
   "introduced_date": "2017-02-09 (committed; authored 2017-02-07)",
   "first_affected_version": "6.5.0 [exec]; 6.4.2, cut from branch_6_4 without the backport although tagged after it, passes 0 of 3 with -ea and -da [exec]. The trigger API (MemoryIndex.addField(IndexableField, Analyzer) and fromDocument, LUCENE-6992) exists since 5.5.0; 5.5.0 to 6.4.2 hard-code the bit to true and are clean (5.5.0, 6.0.0 and 6.4.2 executed). First on the master line: 7.0.0",
   "affected_versions": "Every release from 6.5.0 through 10.6.0 (10.6.0 on the RC1 jars) and main a9779ef3c193 and 645d4fe14a2 [exec]. [exec] 3 of 3 bug checks fail on 6.5.0 (-ea, -da), 6.6.6, 7.0.0 (-da; with -ea an unrelated norms assertion fires first during addIndexes, most likely LUCENE-8055, fixed in 7.2.0, not investigated), 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (-ea, -da) and main (-ea, -da). [exec] the finder's JUnit fails 3 of 4 on 10.0.0, 10.5.2 and main (-ea, -da; it does not compile on 9.x); the independent reproduction's JUnit fails 4 of 6 on main (-ea, -da), 10.5.2 and 9.12.3 (9.x API variant, detected by CheckIndex at its 9.x default settings). [read] the other release tags in the history clone (74 tags from 6.5.0 to 8.8.1 and 9.0.0 to 10.5.2) by tag membership and the unchanged line; 8.9.0 to 8.11.3 inferred (tags not in the clone, between affected 8.8.1 and executed 8.11.4). Clean: 5.5.0, 6.0.0, 6.4.2 [exec]. Not fixed: upstream main 645d4fe14a2 (2026-10-29) still passes fieldType.storeTermVectors() at MemoryIndex.java:767 and has no commit to MemoryIndex.java after a9779ef3c193; no open PR changes the storeTermVector argument or termVectors() [read]. 10.6.0 (released 2026-10-29; branch_10_6 RC1 4ae946e5a9b) [exec] and branch_10x 657014b3c579 [read]. Not checked: x86",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/7462",
    "https://issues.apache.org/jira/browse/LUCENE-6402",
    "https://github.com/apache/lucene/issues/8730",
    "https://issues.apache.org/jira/browse/LUCENE-7679",
    "https://github.com/apache/lucene/issues/13525",
    "https://github.com/apache/lucene/issues/14716"
   ],
   "doc": "",
   "repro": "repro/LFV-788/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-325",
   "priority": "low",
   "priority_rank": 457,
   "novelty": "new",
   "withheld": false,
   "area": "monitor / query decomposition (QueryDecomposer.decomposeBoolean)",
   "title": "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",
   "summary": "You register with the Monitor a BooleanQuery that has one required clause and minimumNumberShouldMatch=1 but no SHOULD clause that can match, for example 'topic AND at least one of [list]' built from an empty list, (+text:alpha)~1. Core Lucene defines this query to match nothing (BooleanQuery.rewrite returns MatchNoDocsQuery and IndexSearcher counts 0 hits), so you expect the Monitor never to report it. Instead the default QueryDecomposer keeps such a query whole only when minimumNumberShouldMatch > 1 and otherwise replaces it by its lone required clause (plus its MUST_NOT exclusions), which the Monitor runs as the final matcher, so Monitor.match reports the query for every document containing alpha, for example 'alpha beta'.",
   "impact_class": "silent wrong results",
   "introduced_commit": "251dbe7cea8126cb7ecadc921ba444c63d06c618 on the main line and b8773d13ad8e249a045862249bf476c30a444461 on the 8.x line (identical QueryDecomposer.java), both 'LUCENE-8766: Add monitor subproject' by romseygeek (apache/lucene-solr#648, closed without a GitHub merge and committed directly; JIRA LUCENE-8766, fix version 8.2) [read]. Not a regression: present since the module's first release. Origin outside Lucene: the module is an import of the Luwak library, where commit 4230bb4d12 ('Allow single-valued conjunctions to be decomposed') added the single-MUST branch without revisiting the msm > 1 guard; the previous version 5d75003e4e returned any query with a MUST clause whole [read]",
   "introduced_date": "2019-06-13 (251dbe7cea8 and b8773d13ad8, author date); the Luwak origin 4230bb4d12 is dated 2014-10-17",
   "first_affected_version": "8.2.0 [exec] (first release with lucene-monitor; 8.1.1, the release before, has no Monitor API: lucene-monitor-8.1.1.jar does not exist on Maven Central (HTTP 404) and the main() check does not compile against 8.1.1 core)",
   "affected_versions": "every release that ships lucene-monitor: 8.2.0 to 8.11.4, 9.0.0 to 9.12.3, 10.0.0 to 10.6.0 (10.6.0 by reading), and main ea57360912ed. [exec] the follow-up's version-portable main() check (public API, IndexSearcher oracle) fails with exit 1 on 8.2.0 (-ea and -da), 8.5.0, 8.8.2, 8.11.4, 9.0.0 (-ea and -da), 9.5.0, 9.12.3, 10.0.0, 10.3.2, 10.5.2 (-ea and -da) and main (-ea and -da), always with the same three false positives and 0 misses; the finder's JUnit fails on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) (compile_error on 9.0.0, whose test framework is in another package); the independent reproduction's JUnit fails on 9.12.3, 10.5.2 (-ea and -da) and main (-ea and -da) and its main() form on 8.2.0, 8.11.4 and main; the intended-behaviour check's JUnit fails on 10.5.2 and main. [read] all other 8.x, 9.x and 10.x releases (the decomposeBoolean logic is unchanged per git log -S/-G/-L and a normalised body hash at the 8.2.0, 8.8.1, 9.0.0, 9.12.3 and 10.0.0 tags; not each run). Not fixed: no upstream commit after 251dbe7cea8 changes the logic (the newest commit touching the file is 54283150a816, 2026-06-14, a javadoc typo fix) and no open PR changes it (2026-10-26).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-325.html",
   "repro": "repro/LFV-325/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-853",
   "priority": "low",
   "priority_rank": 458,
   "novelty": "new",
   "withheld": false,
   "area": "monitor / query decomposition (QueryDecomposer.decomposeBoolean; ScoringMatch, ExplainingMatch)",
   "title": "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",
   "summary": "You register with the Monitor a BooleanQuery whose only required clause is a FILTER clause, for example '#body:apple' or '(#body:apple) body:banana', and ask for scores with ScoringMatch or ExplainingMatch; since FILTER clauses 'do not participate in scoring', you expect the score IndexSearcher gives the same query: 0 for '#body:apple' and 0.13076457 for the nested query on the document 'apple banana'. Instead the default QueryDecomposer treats the FILTER clause like a MUST clause and replaces the query by that clause as a plain scoring query, so ExplainingMatch and ScoringMatch report 0.13076457 for '#body:apple' (0.26152915 for '(#body:apple)^2') and 0.26152915, twice the true score, for the nested query. Matching is correct; only the reported scores and explanations are wrong.",
   "impact_class": "silent wrong results",
   "introduced_commit": "251dbe7cea8126cb7ecadc921ba444c63d06c618 on the main line and b8773d13ad8e249a045862249bf476c30a444461 on branch_8x, both 'LUCENE-8766: Add monitor subproject' by romseygeek (JIRA LUCENE-8766 = #9811; the review PR apache/lucene-solr#648 was closed unmerged and the code committed directly; CHANGES 8.2.0 New Features) [read]. Not a regression: present since the module's first commit. Origin outside Lucene: the 'MUST || FILTER' line was written in Luwak PR flaxsearch/luwak#151 (issue #150, commit 953e19748ea, a matching fix) and imported unchanged; before it a FILTER clause fell into the SHOULD branch, so a FILTER-only query was decomposed into a scoring part there as well [read]",
   "introduced_date": "2019-06-13 (author date of 251dbe7cea8 and b8773d13ad8); the Luwak line 953e19748ea is dated 2017-11-05 (PR #151 merged 2017-11-07)",
   "first_affected_version": "8.2.0 [exec] (the first release with lucene-monitor; 8.1.1 has no monitor module: lucene-monitor-8.1.1.jar does not exist on Maven Central (HTTP 404) and the repro fails to compile against 8.1.1 only on the Monitor classes)",
   "affected_versions": "Every release that ships lucene-monitor: 8.2.0 to 8.11.4, 9.0.0 to 9.12.3 and 10.0.0 to 10.5.2 (all 57 releases executed with -ea, and -da on 8.2.0, 8.11.4, 9.12.3 and 10.5.2), the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29; lucene-monitor compiled from the branch sources over the cached branch jars) and main a9779ef3c193 (-ea and -da) [exec]. Not fixed: no upstream commit after 54283150a81 (2026-06-14, typo fix) touches QueryDecomposer.java on main (head c5ab3e57b9b, 2026-10-28) or on branch_10_6/branch_10x after 89bd9f0ecd5 [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-853.html",
   "repro": "repro/LFV-853/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-773",
   "priority": "low",
   "priority_rank": 459,
   "novelty": "known",
   "withheld": false,
   "area": "monitor / read-only query index (ReadonlyQueryIndex.purgeCache refresh)",
   "title": "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",
   "summary": "You open a read-only Monitor over a query index that a writable Monitor updates, register and commit a new query with the writer, and call purgeCache() on the read-only Monitor, whose javadoc says read-only users 'MUST call it when you want new changes'. You expect the new query to match once the call returns. Instead, if another refresh of the same Monitor (its own background refresh, or another thread's purgeCache()) is already running and has read the older commit, purgeCache() calls the non-blocking SearcherManager.maybeRefresh(), which returns false at once, drops that result and still notifies the onPurge listeners; the running refresh then installs the older commit, so the new query is still unmatched after both have returned, until some later refresh.",
   "impact_class": "silent wrong results",
   "introduced_commit": "be9917895645f99573833859e0c5c0d1cfc5b6d8 on main ('LUCENE-10422: Read-only monitor implementation (#679)', author GitHub mogui, merged by romseygeek; first released in 10.0.0), backported the same day to branch_9x as 72cf36a2b8d8811536b74e742c75bf33331dc923 with the same content (first released in 9.2.0) [read]. It created ReadonlyQueryIndex with purgeCache() = manager.maybeRefresh() (result ignored) followed by an unconditional onPurge, scheduled the same purgeCache() at the purge frequency, and added the Monitor.purgeCache javadoc 'When Monitor is in read-only mode, cache is NEVER purged automatically you MUST call it when you want new changes'. The defect is in the first version of the code, so it is not a regression; later commits to the file (9ecf566cca1, 8dad226afa8, 40f674c5d3d, be513cf5154, 3798b540a74) do not touch purgeCache",
   "introduced_date": "2022-03-21 (merge of #679 on main and the branch_9x backport, same day)",
   "first_affected_version": "9.2.0 [exec] (the first release with the read-only Monitor; 9.1.0 has no read-only Monitor API and the repro does not compile there)",
   "affected_versions": "Every release with the read-only Monitor: 9.2.0 to 9.12.3 (19 releases), 10.0.0 to 10.5.2 (12 releases) and 10.6.0 (by reading), plus main a9779ef3c193; not fixed upstream. [exec] the finder's JUnit (two purgeCache() callers) and the intended-behaviour check's JUnit (one application call against the Monitor's own scheduled refresh) fail on 9.2.0, 9.12.3, 10.0.0, 10.5.2 and main (seed DEADBEEF, -ea; the finder's also with -da on 9.2.0 and main, the intended-behaviour check's also with -da on main); the independent reproduction's JUnit fails on 9.2.0, 9.12.3 and 10.5.2 (-ea) and on main (-ea and -da); with maybeRefreshBlocking() shadowed into the ReadonlyQueryIndex of 9.2.0 and of main the tests pass. [read] the purgeCache body and the single scheduleAtFixedRate are identical in every release tag 9.2.0..10.5.2; upstream main f7bcc0abd816, branch_10x and branch_10_6 (line 109) and branch_9_12 (line 93) still call maybeRefresh(). Not affected: 8.2.0 to 9.1.0 (no read-only Monitor; the writable purgeCache(CachePopulator) is synchronized). Not executed: x86, and the releases between the executed ones (affected by code identity).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15831",
    "https://github.com/apache/lucene/issues/15985",
    "https://github.com/apache/lucene/issues/16152",
    "https://github.com/apache/lucene/issues/16911",
    "https://github.com/apache/lucene/issues/16032",
    "https://github.com/apache/lucene/issues/5098"
   ],
   "doc": "",
   "repro": "repro/LFV-773/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-856",
   "priority": "low",
   "priority_rank": 460,
   "novelty": "new",
   "withheld": false,
   "area": "monitor / query decomposition and match scoring (QueryDecomposer Set<Query> parts, ScoringMatch/ExplainingMatch resolve)",
   "title": "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",
   "summary": "You register a query such as '(red apple) (green apple)' or 'apple apple' in a Monitor and match the document 'red green apple' with ScoringMatch or ExplainingMatch, expecting the score the query itself gives that document, which is what IndexSearcher returns, because BooleanQuery counts a repeated clause at every occurrence (0.5230583 and 0.26152915). Instead the Monitor reports 0.39229372 and 0.13076457: the default QueryDecomposer collects the query's parts in a Set, which keeps equal parts once, and the scoring matchers add up the scores of the distinct parts, so the shared 'apple' is counted once. Which queries match is not affected; only the scores and explanations of such queries are too low.",
   "impact_class": "silent wrong results",
   "introduced_commit": "251dbe7cea8126cb7ecadc921ba444c63d06c618 on the main line and b8773d13ad8e249a045862249bf476c30a444461 on branch_8x (its QueryDecomposer.java and ScoringMatch.java are byte-identical), both 'LUCENE-8766: Add monitor subproject' by romseygeek (JIRA LUCENE-8766, now GitHub #9811; review PR apache/lucene-solr#648, closed without a GitHub merge, code committed directly) [read]. Not a regression: present since the module's first release. Origin outside Lucene [read]: Luwak's QueryDecomposer (flaxsearch/luwak master 7d78a434fe6) kept the parts in Lists (ArrayList/LinkedList) and its ScoringMatcher/ExplainingMatcher resolve kept the larger match, so a repeated part could not change a Luwak score; the port switched to a Set and to a summing resolve in the same commit",
   "introduced_date": "2019-06-13 (251dbe7cea8 and b8773d13ad8, author date 2019-06-13T09:40:57+01:00)",
   "first_affected_version": "8.2.0 [exec] (first release with lucene-monitor; 8.1.1, the release before, has no lucene-monitor artifact on Maven Central (HTTP 404) and the repro does not compile without it, so no earlier release is unaffected: the API did not exist)",
   "affected_versions": "every release that ships lucene-monitor: all 57 published releases from 8.2.0 to 10.5.2, plus the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193. [exec] the finder's JUnit fails 3 of 4 with identical values (0.39229372 vs 0.5230583, 0.13076457 vs 0.26152915 twice; the all-distinct control passes) on each of the 57 releases with -da (follow-up sweep), with -ea on 8.2.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.2.2, 10.3.0 and 10.5.2, on branch_10_6 4ae946e5a9b (monitor jar compiled from the branch sources, the other jars cached branch jars) and on main (-ea and -da); the independent reproduction's JUnit fails 5 of 6 on main (-ea and -da), 10.5.2, 9.12.3 and 8.2.0; the intended-behaviour check ran the finder JUnit on main (-ea and -da) and 10.5.2. #14885 (HashSet to LinkedHashSet, first release 10.3.0) changes only the order: 10.2.2 and 10.3.0 fail identically. The IndexSearcher reference values are identical on all releases and on main. Not fixed: no upstream commit after 251dbe7cea8 changes the Set or the summing resolve (the newest commits touching QueryDecomposer.java are #16255 on main, 2026-06-14, typo tooling, and #14885 on branch_10_6), and no open PR changes them (2026-10-28).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-856.html",
   "repro": "repro/LFV-856/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-915",
   "priority": "low",
   "priority_rank": 461,
   "novelty": "new",
   "withheld": false,
   "area": "monitor / HighlightsMatch hit set (Hit.compareTo used as TreeSet identity)",
   "title": "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",
   "summary": "You register a query such as wi OR \"wi fi\" (or the prefix query wi*, or guinea OR cavy with a 'guinea pig => cavy' synonym rule) in a Monitor whose analyzer stacks tokens at one position, match a document with HighlightsMatch.MATCHER, and expect both hits that Weight#matches reports: for 'wi fi' with ShingleFilter(2,2) and unigrams these are 0(0)->0(2) for 'wi' and 0(0)->0(5) for 'wi fi'. Instead HighlightsMatch keeps only one of them and getHitCount() is 1, because Hit.compareTo compares start and end positions only and the hits are kept in TreeSets, which treat compareTo == 0 as a duplicate, although Hit's own equals (a record over all four fields) says the two hits differ. Which hit survives depends on clause order, and the same root cause makes getHits(field).contains(...) ignore offsets and lets HighlightsMatch.equals return true for two objects whose hashCodes differ.",
   "impact_class": "silent wrong results",
   "introduced_commit": "251dbe7cea8126cb7ecadc921ba444c63d06c618 on master and b8773d13ad8e249a045862249bf476c30a444461 on branch_8x (both 'LUCENE-8766: Add monitor subproject', the import of the Luwak library; issue apache/lucene#9811, review PR apache/lucene-solr#648, committed directly; the branch_8x commit shipped in 8.2.0) [read]. Pre-Lucene origin: Luwak commit 95e9eaf5b6 (2015-10-05, 'Decompose DisjunctionQueries, and ensure highlights are only reported once') switched the hit lists from ArrayList to TreeSet while compareTo stayed position-only [read]",
   "introduced_date": "2019-06-13 (251dbe7cea8 authored and committed; b8773d13ad8 committed the same day); 2015-10-05 for the Luwak TreeSet change before the donation",
   "first_affected_version": "8.2.0 [exec] (the first lucene-monitor release; there is no earlier good Lucene version). On 8.2.0-8.5.2 a single document was indexed through IndexWriter, so the loss shows there only for fields that index offsets; from 8.6.0 (LUCENE-9314, MemoryIndex with offsets) it also shows with a plain TextField",
   "affected_versions": "Every lucene-monitor release, 8.2.0 to 10.5.2 (57 releases per Maven Central metadata), 10.6.0 (the branch_10_6 head 4ae946e5a9b, the RC1 revision) and main a9779ef3c193. [exec] The version-portable history repro (5 tests, offsets-indexed field, Weight#matches on an IndexWriter index as reference) fails 5 of 5 on 8.2.0 (-ea, -da), 8.5.2, 8.6.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (-ea, -da) and main (-ea, -da), its 2 controls pass on 8.2.0, 9.12.3, 10.5.2 and main, and the compareTo tie-break alone turns 8.2.0 and main into 5 of 5 pass; seeds 716DB29A012ECD30, 5F754D1745C2048A, 1, 2 and 3 on 8.6.0 and main also fail 5 of 5; the finder's JUnit fails on main (-ea, -da), branch_10_6 and 10.5.2, the independent reproduction's on main (-ea, -da), 10.5.2 and 9.12.3, the intended-behaviour check's probe on main (-ea, -da) and 10.5.2. [read] The other releases by code identity (the compareTo body and both TreeSet uses are unchanged in every release tag checked). Plain TextField on single documents: 8.6.0 and later [exec]; on 8.2.0-8.5.2 such a document carried offsets -1 and the collapsed hits were truly identical [exec]. Not applicable before 8.2.0 (no monitor module). Not fixed upstream: the last upstream commit to HighlightsMatch.java is b59848c7049 (2026-04-02, instanceof refactor) and upstream main c5ab3e57b9ba (2026-10-28) has no commit to lucene/monitor since 2026-10-20 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-915.html",
   "repro": "repro/LFV-915/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-337",
   "priority": "low",
   "priority_rank": 462,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / WordDelimiterGraphFilter catenation runs (CATENATE_WORDS, CATENATE_NUMBERS; WordDelimiterIterator character types; factory 'types' option; term-level half shared with the deprecated WordDelimiterFilter)",
   "title": "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)",
   "summary": "You run WordDelimiterGraphFilter with CATENATE_WORDS or CATENATE_NUMBERS on a token such as 'U+20000-ab-12' (a supplementary character at the start) or '@x-ab-12' with '@' mapped to ALPHANUM, and expect catenations only of adjacent subwords of one kind, each placed over exactly the parts it contains, as the ASCII control 'x-ab-12' gets (xab at [0,2), no number catenation). Instead, because such a subword is typed ALPHA|DIGIT and a run started by it is never ended by a subword it does not absorb, the filter emits catenations of non-adjacent parts ('U+20000 12', '@x12', 'U+20000abcd' across '12') and catenations whose position length also covers the skipped part ('U+20000ab' at [0,3), over '12'). At search time QueryBuilder turns that graph into a phrase query with a bare-term alternative, so the phrase 'U+20000hot-sale-50' also matches a document 'U+20000hot-sale-49' (executed).",
   "impact_class": "silent wrong results",
   "introduced_commit": "637915b890d9 (LUCENE-7619, 'add WordDelimiterGraphFilter (replacing WordDelimiterFilter)', master; branch_6x backport 4e4ec082caa7 the same day; committed from JIRA patches, no GitHub PR; the issue is now #8670) [read]. The run logic it copied is older: the WordDelimiterFilter rewrite 65a21459a258 (svn r922957, 2010-03-14, credited to SOLR-1657 and SOLR-1706) made a run's type the type of its first subword and ended a run only when (concat.type & wordType) == 0; the SURROGATE -> ALPHA|DIGIT typing came from 79414d2b7263 (SOLR-1078, 2009-05-08, 'prevent splitting'), harmless under the pre-2010 run algorithm [read]; the factory 'types' option accepting ALPHANUM from SOLR-2059 (33cc5a041e8 / 878a697766c, 2010-08-28)",
   "introduced_date": "2017-01-17 (LUCENE-7619, the WDGF graph/position-length half); 2010-03-14 (r922957, the shared run logic and the term-level half); 2009-05-08 (SOLR-1078, surrogate typing); 2010-08-28 (SOLR-2059, ALPHANUM types option)",
   "first_affected_version": "6.5.0 [exec] (first release with WordDelimiterGraphFilter; 6.4.2 does not have the class); the term-level half (non-adjacent CATENATE_NUMBERS output) in the deprecated WordDelimiterFilter since 4.0.0 [exec], the first Lucene release with WDF (Solr 3.1-3.6 by code reading only)",
   "affected_versions": "every WordDelimiterGraphFilter release, 6.5.0 through 10.5.2, and main ea57360912ed (not fixed). Executed with a version-independent WDGF probe (4 of 4 trigger cases violate the catenation-span oracle, 3 of 3 ASCII controls pass) on 6.5.0 (also --da), 6.5.1, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and --da) [exec]; finder JUnit fails on main (-ea, --da, 5 run / 4 failed), 10.5.2 (5/4) and 9.12.3 (9.x variant, 4/3); the independent reproduction JUnit fails 10 run / 7 failed on main (-ea, --da), 10.5.2, 9.12.3 and 10.0.0 [exec]; the three root-cause lines are present in all 74 tagged releases from 6.5.0 to 10.5.2 [read]. Deprecated WordDelimiterFilter (term-level half only, it has no position lengths): fails on 4.0.0, 4.10.4, 5.5.5, 6.4.2, 6.5.0, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main [exec]; flush line in all 123 tagged releases from 4.0.0-ALPHA [read]. The search-time false positive was executed on 9.12.3, 10.0.0, 10.5.2 and main only (inferred for 6.5-9.x). Upstream main e1c4184cb98 (2026-10-26) has no change to the three files since 2024-08-16 (formatting only) [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-337.html",
   "repro": "repro/LFV-337/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-876",
   "priority": "low",
   "priority_rank": 463,
   "novelty": "new",
   "withheld": false,
   "area": "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)",
   "title": "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",
   "summary": "You index Thai text with the default ThaiAnalyzer, which runs ThaiCharFilter before the tokenizer, and expect a word typed with two of the typos the filter documents fixing (ที่ with its tone mark typed twice and before the vowel, ท่่ี, or แมว written as two Sara E with an invisible zero-width joiner between them) to be indexed like the clean word, because the filter's javadoc says it removes zero-width characters, deduplicates repeated tone marks, reorders a tone mark typed before an above/below vowel, joins double Sara E and recomposes decomposed Sara Am precisely so that the BreakIterator does not merge adjacent words. ThaiCharFilter makes one pass and tests its multi-character patterns against the raw next characters, while zero-width removal and deduplication act only on the character at the front of its buffer, after the earlier character has already been emitted, so the output still holds the tone-before-vowel, double Sara E or decomposed Sara Am sequence (ท่ี, เเมว, ทํา), which a second pass of the same filter would clean. The BreakIterator then merges words: ฉันทำงานท่่ีบ้าน is indexed as [ฉัน, ทำ, งาน, ที่บ้าน] instead of [ฉัน, ทำ, งาน, บ้าน], ฉันรักเ + ZWJ + เมวมาก as [ฉัน, รักแมวมาก], and a TermQuery for บ้าน or แมว finds 0 documents.",
   "impact_class": "silent wrong results",
   "introduced_commit": "e64ae25dcd894019125d0a0bd723133b633b009e on main (apache/lucene#16717 'Add ThaiCharFilter, ThaiNormalizationFilter, and ThaiNormalizer (#16716)', closes feature issue #16716, author kamthorn; one comment, no review comments) and its backport 405116dd0e1 (branch_10_6 and branch_10x, committed 2026-09-28T15:36:16Z, same author date). Born with the class, not a regression [read]",
   "introduced_date": "2026-09-27 (author date 2026-09-28T04:09:27+07:00 = 2026-09-27T21:09:27Z; merged to main at the same time); backport 405116dd0e1 committed 2026-09-28",
   "first_affected_version": "10.6.0 (released 2026-10-29) is the first release. The 10.6.0 RC1 (rev 4ae946e5a9b, released as 10.6.0 on 2026-10-29) contains it: the finder JUnit fails 10 of 10 with -ea and -da on 10.6.0-SNAPSHOT jars built at that revision [exec]. 10.5.2, 9.12.3 and every earlier release lack the class [exec]",
   "affected_versions": "main / 11.0.0-SNAPSHOT since e64ae25dcd8 [exec]; branch_10_6 since 405116dd0e1 [exec]; branch_10x [read]; the introducing commit e64ae25dcd8 [exec]. In no release before 10.6.0: 10.5.2, 9.12.3 and older lack the class [exec]. All runs on Linux aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-876.html",
   "repro": "repro/LFV-876/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b, jars built at that revision): 10 of 10 fail with -ea and -da; 10.5.2 does not have ThaiCharFilter."
  },
  {
   "id": "LFV-873",
   "priority": "low",
   "priority_rank": 464,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / Thai (ThaiNormalizer.normalize rule order; ThaiNormalizationFilter, the 'thaiNormalization' factory and the default ThaiAnalyzer as consumers; new in 10.6.0)",
   "title": "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",
   "summary": "You index Thai text with the default ThaiAnalyzer (or ThaiNormalizationFilter) in which the word น้ำ ('water') is typed with a decomposed Sara Am and an extra tone mark inside it, น + Nikhahit + Mai Ek + Mai Tho + Sara Aa, and you expect the term น้ำ, because ThaiNormalizer documents that it recomposes Nikhahit + tone + Sara Aa into Sara Am and (per its code comment and upstream test) keeps the last of two different tone marks. ThaiNormalizer tests for the decomposed Sara Am in one forward pass over the raw characters, before it converts a following Lakkhangyao and before its last step removes the extra or repeated tone mark, and it never checks again, so the output is นํ้า (U+0E19 U+0E4D U+0E49 U+0E32), still the decomposed form; a query for น้ำ misses the document, while a second normalize() call, or the same two tone marks typed in the other order, gives น้ำ. When the token filter runs without ThaiCharFilter, ท + Nikhahit + Lakkhangyao likewise gives ทํา instead of ทำ, and a doubled tone mark inside the decomposed form gives นํ้า.",
   "impact_class": "silent wrong results",
   "introduced_commit": "e64ae25dcd894019125d0a0bd723133b633b009e on main (apache/lucene#16717 'Add ThaiCharFilter, ThaiNormalizationFilter, and ThaiNormalizer (#16716)', closes feature issue #16716, author kamthorn, merged by rmuir; 0 reviews, 1 comment) and its backport 405116dd0e10a4921d8269bfaa7b74c69992f3e6 (branch_10_6 and branch_10x, committed 2026-09-28T15:36:16Z, same author date). Born with the class, not a regression: the single-pass rule order is in the first and only commit of ThaiNormalizer.java [read]",
   "introduced_date": "2026-09-27 (author date 2026-09-27T21:09:27Z, i.e. 2026-09-28T04:09:27+07:00; merged to main at the same time); backport 405116dd0e1 committed 2026-09-28",
   "first_affected_version": "10.6.0 (released 2026-10-29) is the first release. The 10.6.0 RC1 (rev 4ae946e5a9b, released as 10.6.0 on 2026-10-29) contains it: the finder JUnit fails 6 of 6 with -ea and -da and the independent reproduction's fails 8 of 9 with -da on 10.6.0-SNAPSHOT jars built at that revision [exec]. 10.5.2, 9.12.3 and every earlier release lack the API [exec]",
   "affected_versions": "main / 11.0.0-SNAPSHOT since e64ae25dcd8 [exec]; branch_10_6 since 405116dd0e1 [exec]; branch_10x [read]. In no release before 10.6.0: 10.5.2, 9.12.3 and older lack the class [exec]. All runs on aarch64 Linux with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-873.html",
   "repro": "repro/LFV-873/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b, jars built at that revision): 6 of 6 fail with -ea and -da; 10.5.2 does not have ThaiNormalizer."
  },
  {
   "id": "LFV-621",
   "priority": "low",
   "priority_rank": 465,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-opennlp / sentence-aware filters (SentenceAttributeExtractor.extractSentenceAttributes, shared by OpenNLPPOSFilter, OpenNLPChunkerFilter and OpenNLPLemmatizerFilter; factories opennlpPOS, opennlpChunker, opennlplemmatizer)",
   "title": "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",
   "summary": "You build an OpenNLP chain that removes some tokens before a sentence-aware filter, for example tokenizer -> POS tagger -> TypeTokenFilter keeping only nouns -> lemmatizer, and analyze 'He did not come back. They sent him running in the evening.', expecting the lemmatized nouns of the second sentence, [they, evening], as you get for that sentence alone. Instead the whole value yields no token: SentenceAttributeExtractor starts with currSentence = 0, so when the first token it receives already belongs to sentence 1 it returns an empty first sentence, and the POS, chunker and lemmatizer filters all treat an empty sentence as the end of the stream. A fully removed sentence in the middle of the text is handled correctly; only the first one is not.",
   "impact_class": "silent wrong results",
   "introduced_commit": "3a04aa44c22aad7c63f806b436a79515285c6ea9 on main ('Fix repeating token sentence boundary bug (#11734)', apache/lucene#11734 by kotman12, co-authored and merged by dweiss), which added SentenceAttributeExtractor with 'private int currSentence = 0;' (line 40, and 'currSentence = 0;' in reset() at line 78) and moved the three filters onto it with the nextSentence().isEmpty() end-of-stream check; the 9.x line got it through the branch_9x backport b253e4353f091dc53d2167985ba09fd40954d0c3 (an earlier backport b79edbb54ac was reverted the same day by 64b124349ba and re-applied as b253e4353f0; the class is identical in all three). A regression introduced by a fix: #11734 fixed GITHUB#11735 and #11771 (tokens lost when the last token of a sentence was repeated or removed). [read]",
   "introduced_date": "2022-09-23 (main, 3a04aa44c22, PR merged 10:59:46Z); 2022-09-24 (branch_9x backport b253e4353f0); first release 9.5.0, tagged 2023-01-30",
   "first_affected_version": "9.5.0 [exec]; last unaffected: 9.4.2 [exec]. 7.3.0 (the module's first release, LUCENE-2899) to 9.4.2 used the older end-of-sentence-flag logic and do not have this bug [exec]; they lose tokens in the mirror case instead (the last sentence removed), a different root cause that #11734 fixed",
   "affected_versions": "Every release from 9.5.0 through 10.6.0 (9.5.0-9.12.3 and 10.0.0-10.5.2, 26 releases, and 10.6.0 by reading) and main a9779ef3c193; never fixed. [exec] the follow-up's history test (oracle: chain(FIRST + ' ' + SECOND) equals chain(SECOND) in terms and types, with its preconditions asserted) fails 3 of 3 on all 26 releases, each with its own jars and its own release-tag test models (-ea; 9.5.0 also -da), and on main (-ea and -da); it passes on 7.3.0, 7.7.3, 8.0.0, 8.8.1, 8.11.4, 9.0.0, 9.1.0, 9.2.0, 9.3.0, 9.4.0, 9.4.1 and 9.4.2 and on main with the fix shadowed. The finder's JUnit fails 3 of 3 on main (-ea and -da), 10.5.2, 9.12.3 and 9.5.0 (it also fails on 9.4.2, but only through the older trailing-removal mechanism, because its inputs end with a removed '.'); the independent reproduction's JUnit fails 4 of 5 on main (-ea and -da), 10.5.2, 9.12.3 and 9.5.0 and fails differently on 9.4.2. [read] on upstream main (a95c754ee00, 2026-10-26), branch_10x and branch_10_6 the last change to SentenceAttributeExtractor.java is still 3a04aa44c22, so 10.6.0 (released 2026-10-29) and the unreleased 11.0 line are affected (branch heads not executed); the 7 commits ea57360912ed..a9779ef3c193 do not touch lucene/analysis/opennlp. Not executed: x86 (pure Java logic). JDK 25.0.3, aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-621.html",
   "repro": "repro/LFV-621/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-616",
   "priority": "low",
   "priority_rank": 466,
   "novelty": "known",
   "withheld": false,
   "area": "analysis / kuromoji JapaneseTokenizer n-best output (analysis-common morph.ViterbiNBest.fixupPendingList)",
   "title": "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",
   "summary": "You enable n-best output on JapaneseTokenizer (for example setNBestCost(2000)), keep the default discardPunctuation=true, analyze アイワ・コーポ東京支店 (a company name followed by 'Tokyo branch'), and expect a valid token graph in which the dictionary word アイワ・コーポ ends where 東京 starts, as it does with discardPunctuation=false. Instead ViterbiNBest.fixupPendingList counts the dropped ・ as an extra position, so アイワ・コーポ gets position length 3 instead of 2 and ends where 東京 ends, which breaks the analysis package rule that tokens with the same end position must have the same end offset. QueryBuilder then builds +((+アイワ +コーポ +東京) アイワ・コーポ) +支店 for an all-words query, and that query also matches a document about the Osaka branch (アイワ・コーポの大阪支店), which has no 東京.",
   "impact_class": "silent wrong results",
   "introduced_commit": "df9c6a835f65fdc42ba43838d40a37f991ef025b ('Add n-best output to JapaneseTokenizer (LUCENE-6837)', GitHub issue #7895; an SVN-era JIRA patch, trunk r1717713, no pull request) [read]. Not a regression: later commits are refactors only (c89f8a7ea1e7 LUCENE-10493 #805, c28f575b6db1 LUCENE-10493 #846 moving the code to analysis-common, 7db9c8c9bda7 #13368, and 7f8b7ffbcad LUCENE-9570 reformat on 9.x). Caveat: the introducing commit and its parent were not built (2015 build); the attribution rests on blame and log, the 5.5.x (no n-best API) versus 6.0.0 (fails) release boundary, and identical failing output on every later line",
   "introduced_date": "2015-12-03",
   "first_affected_version": "6.0.0 [exec]; 5.5.0 and 5.5.5 have no n-best API (setNBestCost absent) [exec], and the introducing commit is in no 5.x tag",
   "affected_versions": "every release from 6.0.0 through 10.6.0 (6.0.0-6.6.6, 7.0.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.6.0; 10.6.0 by reading) and main a9779ef3c193; never fixed. [exec] the follow-up's main() probe fails on 6.0.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main with identical tokens while its controls (1-best, discardPunctuation=false) stay linked; the finder's JUnit fails 2 of 3 on main (-ea and -da), 10.5.2 and 9.12.3, and the finder's main() probe fails on 8.11.2, 7.7.3 and 6.6.6; the independent reproduction's JUnit fails 3 of 5 on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's framework-oracle JUnit fails 2 of 5 on main (-ea and -da), 10.5.2 and 9.12.3. [read] releases between the executed ones are presumed affected (the defective lines are unchanged); upstream main a95c754ee003, branch_10x and branch_10_6 leave fixupPendingList unchanged (2026-10-26); the 7 commits ea57360912ed..a9779ef3c193 do not touch lucene/analysis. All runs on JDK 25, aarch64",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene-solr/pull/1577",
    "https://issues.apache.org/jira/browse/LUCENE-9390",
    "https://github.com/apache/lucene/issues/10430",
    "https://github.com/apache/lucene/issues/7895",
    "https://issues.apache.org/jira/browse/LUCENE-6837",
    "https://github.com/apache/lucene/issues/5013"
   ],
   "doc": "",
   "repro": "repro/LFV-616/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-354",
   "priority": "low",
   "priority_rank": 467,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / WordDelimiterGraphFilter final position increment (end of stream, accumPosInc)",
   "title": "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)",
   "summary": "You analyse 'foo --' (or 'foo the --' behind a StopFilter) with a whitespace tokenizer and WordDelimiterGraphFilter at its default flags, and expect the swallowed punctuation-only token to leave a hole that end() reports as a final position increment of 1 (2 with the stop word), as the filter does mid-stream ('foo -- bar' puts bar at +2, which upstream tests assert) and as StopFilter does for 'foo the'. Instead the filter keeps that hole in an internal accumulator that only a later emitted token applies and has no end() override, so the final increment is 0. In a multi-valued field with the default gap 0 the next value 'bar' then lands at position 1 instead of 2: PhraseQuery(foo, bar) matches the values 'foo --' | 'bar' while the StopFilter control 'foo the' | 'bar' does not, and the phrase QueryBuilder builds for 'foo -- bar' matches the single value 'foo -- bar' but not the two values (both executed).",
   "impact_class": "silent wrong results",
   "introduced_commit": "637915b890d9 (LUCENE-7619 'Add WordDelimiterGraphFilter', by GitHub mikemccand, master; identical branch_6x backport 4e4ec082caa7 the same day; committed from JIRA patches, no GitHub PR; the issue is now #8670): the class never had an end() override [read]; the accumulation line (main :359) was carried over from WordDelimiterFilter [read]",
   "introduced_date": "2017-01-17",
   "first_affected_version": "6.5.0 [exec] (first release with WordDelimiterGraphFilter; 6.4.2 does not have the class, executed compile_error)",
   "affected_versions": "every WordDelimiterGraphFilter release, 6.5.0 through 10.6.0 (10.6.0 by reading), plus branch_10_6, branch_10x and main ea57360912ed (not fixed). Executed with the finder repro or its version ports (3 of 4 fail identically, control passes): 6.5.0 (-ea and -da), 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) [exec]; the independent reproduction's suite fails on main (-ea, -da), 10.5.2 (-ea, -da) and 9.12.3, the intended-behaviour check's cross-value phrase test on main (-ea, -da) and 10.5.2 [exec]; the swallow branch and accumulation without an end() are in all 66 release tags 6.5.0 to 10.5.2 of the history clone [read]; 8.9.0 to 8.11.3 (released from the separate lucene-solr repository) inferred. The file blob is identical in 9.12.3, 10.5.2, main and upstream main, branch_10x and branch_10_6 (fetched 2026-10-24) [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-354.html",
   "repro": "repro/LFV-354/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-532",
   "priority": "low",
   "priority_rank": 468,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / common n-gram token filters (NGramTokenFilter, EdgeNGramTokenFilter: final position increment in end())",
   "title": "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)",
   "summary": "You analyse 'abc the' with a whitespace tokenizer, StopFilter and then NGramTokenFilter(3,3) or EdgeNGramTokenFilter(1,3); StopFilter reports the removed trailing 'the' as a final position increment of 1 in end(), and because the n-gram filter drops nothing here you expect end() to still report 1. Instead both filters call super.end() and then replace that value with only the increments of tokens they dropped themselves, so end() reports 0 ('abc x the' gives 1 instead of 2) and the trailing hole is lost. In a multi-valued field with Lucene's default gap 0, the second value 'def' of ['abc the', 'def'] is then indexed at position 1 instead of 2, and PhraseQuery('abc','def') matches the document (1 hit) where the same chain without the n-gram filter gives 0 hits (executed).",
   "impact_class": "silent wrong results",
   "introduced_commit": "d1dc874d90bc (LUCENE-8360 'NGram filters should set posIncAtt in end()', by romseygeek with a +1 from jpountz, master; the branch_7_4 backport b03b527a312 is what 7.4.0 ships, branch_7x backport a045344b254; committed from a JIRA patch, no GitHub PR; the issue is now #9407) [exec]; precondition [read]: LUCENE-7960 (2c1ab31b4e5, 2018-06-04, not released on its own) replaced NGramTokenFilter's CodepointCountFilter wrapper, whose end() adds its skipped positions, with the filter's own curPosIncr counting",
   "introduced_date": "2018-06-17 (author date; committed 2018-06-18)",
   "first_affected_version": "7.4.0 [exec] (released 2018-06-27; the last unaffected release 7.3.1 keeps the trailing hole in both filters [exec])",
   "affected_versions": "every release from 7.4.0 through 10.5.2, plus main ea57360912ed and the newer main a9779ef3c193 (not fixed; upstream main ffa9d816eeb4 of 2026-10-26 still has the overwrite at NGramTokenFilter.java:160 [read]). Executed (fail, final increment 0 instead of 1 for both filters): 7.4.0, 7.5.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main with a release-portable public-API main() (main also with -da) [exec]; the finder JUnit fails on main (-ea, -da), 10.5.2, 9.12.3 and a9779ef3c193, the independent reproduction's suite on main (-ea, -da), 10.5.2 and 9.12.3, the intended-behaviour check's probe on main (-ea, -da) and 10.5.2 [exec]; 7.3.1 passes [exec]; the overwrite is in both filters at every release tag 7.4.0..8.8.1 and 9.0.0..10.5.2 of the history clone [read]; 8.9.0 to 8.11.3 inferred (8.11.4 executed). For EdgeNGramTokenFilter, 7.3.1 had the opposite end() defect that LUCENE-8360 fixed (the filter's own dropped trailing tokens were lost); for NGramTokenFilter 7.4.0 is a plain regression [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-532.html",
   "repro": "repro/LFV-532/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-542",
   "priority": "low",
   "priority_rank": 469,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / common miscellaneous (ConditionalTokenFilter#end and OneTimeWrapper#end: final position increment on the delegate branch)",
   "title": "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)",
   "summary": "You analyse 'abc the' with WhitespaceTokenizer, a StopFilter that removes 'the', and a ProtectedTermFilter that wraps a LowerCaseFilter (or the CustomAnalyzer equivalent whenTerm(...).addTokenFilter(\"lowercase\").endwhen()), and expect end() to report the removed stop word as a final position increment of 1, as the same chain does without the condition and as the class itself does when the last token is protected ('x the' gives 1). Instead it reports 0 whenever the last token went through the wrapped filter, although LowerCaseFilter never touches positions: end() keeps the wrapped chain's end state, and the internal wrapper that feeds that chain resets the increment to 0. In a multi-valued field ['abc the', 'def'] with the default gap 0, 'def' is then indexed at position 1 instead of 2, so the PhraseQuery \"abc def\" matches the document (1 hit) where the plain chain gives 0 (executed).",
   "impact_class": "silent wrong results",
   "introduced_commit": "b1ee23c525a64017242148bca43111168fe1be3a (master, 'LUCENE-8273: Fix end() and posInc handling', by GitHub romseygeek; LUCENE-8273 = apache/lucene#9320, JIRA patch workflow, no PR), shipped in 7.4.0 through the identical branch_7x copy 443bd2ac526a40079e9028a5e7d8ad2f24ca6a4b (same ConditionalTokenFilter.java blob): it made OneTimeWrapper.end() 'imitate Tokenizer.end() call - endAttributes, set final offset', so the position increment becomes 0 and only the final offset is restored, while ConditionalTokenFilter.end() keeps the delegate's end state when lastTokenFiltered [exec] [read]. The two hole-keeping versions existed for one week on master and branch_7x and never shipped; b1ee23c525a was written to fix other end() problems found by TestRandomChains, so the hole loss is a side effect of that fix",
   "introduced_date": "2018-05-18",
   "first_affected_version": "7.4.0 [exec] (the first release with ConditionalTokenFilter, ProtectedTermFilter and CustomAnalyzer when()/whenTerm(); 7.3.1 does not have the API [exec]); no release ever had the correct behaviour",
   "affected_versions": "every release before 10.6.0 that has the class: 7.4.0, 7.5.0, 7.6.0, 7.7.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2 and main ea57360912ed; not fixed. [exec] the release-portable main() (final increment 0 through a pass-through delegate; its 2 controls give 1) fails on 7.4.0, 7.5.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main; the finder's JUnit fails 3 of 5 on main (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 5 of 8 on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's probe fails 4 of 10 on main (-ea and -da) and 10.5.2. [read] git tag --contains on the history clone lists 58 release tags from 7.4.0 to 10.5.2 (8.8.2, 8.9.0 and 8.10-8.11 are untagged there; 8.11.4 was executed); ConditionalTokenFilter.java is byte-identical in 9.0.0, 9.12.3, 10.5.2 and main; upstream main a95c754ee003 (read 2026-10-26) last changed the file on 2020-12-28 (formatting only) and no open PR touches it. Executed only on aarch64 Linux with JDK 25 (plain Java logic)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-542.html",
   "repro": "repro/LFV-542/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-488",
   "priority": "low",
   "priority_rank": 470,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / common miscellaneous (ConcatenatingTokenStream#incrementToken and #end: carry-over of child final position increments)",
   "title": "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",
   "summary": "You build one field from several token streams with ConcatenatingTokenStream, for example the values 'alpha the', '' and 'beta', each run through a StopFilter that removes 'the'. You expect the hole left by the removed 'the' to survive, as it does when no empty value sits in between and as IndexWriter keeps it for the same values in a multi-valued field, because LUCENE-8650 (7.7.0) made the class carry each source's final position increment over to the next token. Instead each exhausted source overwrites the pending increment instead of adding to it, and end() reports only the last source's own increment, so a source with no tokens erases the hole: 'beta' is indexed directly after 'alpha', the exact phrase \"alpha beta\" matches this document but not the single value 'alpha the beta', and with an empty last source end() reports 0 instead of 1.",
   "impact_class": "silent wrong results",
   "introduced_commit": "7713a4f2458c77de08193dc548807b9e90214aaf (LUCENE-8650 = apache/lucene#9696 'ConcatenatingTokenStream does not end() nor reset() properly'; commit 'LUCENE-8650: Fix end() and reset() in ConcatenatingTokenStream' by romseygeek; JIRA patch workflow, no PR; backports branch_7x 874ff046dfd0 and branch_8x f062a18ae716): it added the carry-over of child final position increments as an assignment (ConcatenatingTokenStream.java:92) and an end() that reads only the last source (:115) [read] [exec]. An incomplete fix, not a regression: the class itself dates from LUCENE-7877 (a948e1714609, #8928, 2017-06-22, first released in 7.0.0)",
   "introduced_date": "2019-01-22 (authored), 2019-01-28 (committed)",
   "first_affected_version": "7.7.0 [exec] (the first release with the LUCENE-8650 carry-over; 7.0.0-7.6.0 have the class but propagate no child final increment at all, so the same inputs were already wrong there for that older and broader root cause, which LUCENE-8650 fixed [exec]; 6.6.6 and older do not have the class [exec])",
   "affected_versions": "7.7.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2 (the last release before 10.6.0) and main ea57360912ed. [exec] a portable main() probe (4 controls and 4 empty-source cases) fails with only the empty-source cases on 7.7.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da), and passes on main with the fix shadowed; the finder's JUnit fails 3 of 4 on main (-ea, -da), 10.5.2 and 9.12.3 (it cannot compile on 9.0.0 because of the test-framework package move in 9.1.0); the independent reproduction's JUnit fails 4 of 6 on main, 10.5.2 and 9.12.3 (-ea and -da); the finder's main() probe fails on 8.11.4 and 7.7.3. [read] the release tags hold only three versions of the file (7.0.0-7.6.0 original, 7.7.0-8.8.1 LUCENE-8650, 9.0.0-10.5.2 reformatted and identical to main); 8.9-8.11 are not tagged in the local history, 8.11.4 was executed. Not fixed upstream: upstream main a9779ef3c193 (2026-10-26) still has the assignment at line 92, and no open PR changes the logic [read]. Executed only on aarch64 Linux with JDK 25 (plain Java logic)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-488.html",
   "repro": "repro/LFV-488/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-517",
   "priority": "low",
   "priority_rank": 471,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / ConcatenateGraphFilter and ConcatenateGraphFilterFactory (custom tokenSeparator)",
   "title": "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)",
   "summary": "You join tokens with ConcatenateGraphFilter (or the concatenateGraph factory) and a custom tokenSeparator, and expect what the javadoc says, every token joined with that separator: the single token 'e-mail' stays 'e-mail', 'e-mail' and 'x' joined with '-' give 'e-mail-x', and 'new' and 'york' joined with U+2013 give the UTF-8 bytes of new, U+2013, york. Instead the filter passes the custom separator to an escaper written for its internal one-byte label U+001F, so every occurrence of an ASCII separator inside a token is doubled ('e--mail', 'e--mail-x', and 'new york' for a keyword token with a space separator). A non-ASCII separator fails the escaper's assertion with -ea and, with -da, is cut to its low byte: U+2013 gives 'new' U+0013 'york', and U+00B7 gives the invalid UTF-8 term [6e 65 77 b7 79 6f 72 6b].",
   "impact_class": "silent wrong results",
   "introduced_commit": "e466d622c8161038d4e0730e2925474a0a05d596 (LUCENE-9018, 'Separator for ConcatenateGraphFilterFactory', now apache/lucene#10061; a JIRA patch committed by dsmiley, no pull request; the branch_8x cherry-pick e5f2b2380b6e93d48df5f1733113c6b6c0bc090c is the commit in 8.4.0) [read]. It replaced 'boolean preserveSep' with 'Character tokenSeparator', changed toAutomaton from new EscapingTokenStreamToAutomaton(SEP_LABEL) to new EscapingTokenStreamToAutomaton(tokenSeparator), and made replaceSep emit the custom separator as one transition label. The escaper, its 'assert sepLabel <= Byte.MAX_VALUE' and its byte cast date from f9f5e837450 (LUCENE-8332, 7.4.0), when only the internal SEP_LABEL U+001F was ever passed. Neither endpoint was built from source; the commit is bracketed by 8.3.1 (API absent) and 8.4.0 (fails) [exec]",
   "introduced_date": "2019-11-14",
   "first_affected_version": "8.4.0 [exec] (the first release with the Character tokenSeparator API). 8.3.1 [exec] has only the boolean preserveSep constructor, and its factory rejects tokenSeparator as an unknown parameter, so the bug cannot be triggered there; on the main line the first affected release is 9.0.0",
   "affected_versions": "every release from 8.4.0 through 10.5.2, and main ea57360912ed; never fixed. [exec] the follow-up's version-neutral main() probe fails 6 of 6 on 8.4.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main with -ea and -da, and on 8.8.2, 8.9.0, 8.10.0, 8.10.1 and 8.11.0-8.11.3 with -da, with default-separator controls passing on every version from 7.4.0; the finder's JUnit fails 6 of 6 on main, 10.5.2 (-ea and -da) and 9.12.3; the independent reproduction's JUnit fails 6 of 9 (two controls and one diagnostic pass) on main, 10.5.2 and 9.12.3 with -ea and -da, and the independent reproduction's main() variant fails on 8.4.0 and 8.11.4. [read] tag ancestry and the code check cover the releases in between; later edits to the file (LUCENE-9570 reformat, LUCENE-9856, LUCENE-9981, a typo fix, and 1ddb01044a0 in 10.0.0, which removed only the factory's pre-8.4 preserveSep fallback) did not change the behaviour, and no open PR touches the file. Not executed: branch_10_6, x86, other JDKs (aarch64 Linux with JDK 25 only)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-517.html",
   "repro": "repro/LFV-517/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-522",
   "priority": "low",
   "priority_rank": 472,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / document (NRT) suggester (ContextSuggestField context validation; the context then passes through ConcatenateGraphFilter's SEP_LABEL escaping and HOLE removal)",
   "title": "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')",
   "summary": "You index one suggestion under context 'ab' and another under context 'a<U+001E>b' with ContextSuggestField, and expect an IllegalArgumentException, because the constructor javadoc says it throws one 'if value or contexts contains any reserved characters' and U+001E and U+001F are exactly the characters that SuggestField and CompletionQuery reject as reserved (or, at the least, a context that round-trips). Instead both documents are indexed: ContextQuery.addContext(\"ab\") returns both and reports both with context 'ab', addContext(\"a<U+001E>b\") returns nothing, and a context 'a<U+001F>b' is also accepted, its exact query returns nothing and addAllContexts() reports it as 'a<U+001F><U+001F>b'. The cause: ContextSuggestField.validate checks a context only for U+001D (CONTEXT_SEPARATOR); the context then goes through ConcatenateGraphFilter, which turns a U+001E byte into an epsilon and escapes U+001F by doubling it, while ContextQuery builds its automaton from the raw characters, so the index side and the query side disagree.",
   "impact_class": "silent wrong results",
   "introduced_commit": "be4d58c7740bea4e797eb1acff6355eb260e7c93 (LUCENE-6459 'add common suggest API for document based NRT suggester', patch by Areek Zillur (@areek), committed by Mike McCandless (@mikemccand), trunk svn r1682158, SVN era with no pull request; review on JIRA LUCENE-6459, now apache/lucene#7518), released through the branch_5x copy 380bb29f39595de1c3947075296d1d0a36f02fd8 (r1682170, the same day; the commit in 5.3.0-5.5.5) [read]. The commit created ContextSuggestField with the 'reserved characters' @throws javadoc and a validate() that rejects only CONTEXT_SEPARATOR U+001D, and in the same commit added SuggestField.isReserved (U+001F, U+001E, U+0000) for values and CompletionQuery.validate, which rejects U+001E and U+001F in query text as 'reserved'; so the defect is as old as the API, not a regression. Later commits kept the U+001D-only check: cecebbc7506 (LUCENE-6515), f8ae631751a (LUCENE-6702, moved the context check into wrapTokenStream), 4e2d9deff4a (LUCENE-6858), f9f5e837450 / 9b61121ffb6 (LUCENE-8332, analysis moved to ConcatenateGraphFilter), 2cbf261032d (LUCENE-9570 reformat), 135f3fab412 (#11942), 378ca8d1bbf (#15573, javadoc markup)",
   "introduced_date": "2015-05-28 (be4d58c7740 on trunk and 380bb29f395 on branch_5x)",
   "first_affected_version": "5.3.0 [exec] (tag 2015-08-20, the first release with ContextSuggestField: the portable public-API probe shows the bug with -ea and -da, and a 5.x port of the finder's JUnit fails 3 of 3 with the same messages as on main); 5.2.1 has no ContextSuggestField, ContextQuery or CompletionQuery, so the probe does not compile [exec]. Correction to the finder's first take ('since 5.2'), as the intended-behaviour check, the adjudication and the history step found (CHANGES lists LUCENE-6459 under 5.3.0)",
   "affected_versions": "every release from 5.3.0 through 10.5.2 (all 103 releases on Maven Central) and main ea57360912ed; not fixed upstream (upstream main a9779ef3c19, branch_10x and branch_10_6 read on 2026-10-26: validate() and ContextQuery.addContext still check only U+001D; no open PR touches the files). [exec]. Caveats: probe v1 picked an absent completion format on 10.3.0-10.3.2 (a probe error), so those three ran with probe v2, which agrees with v1 wherever both ran; 8.8.2-8.11.3 have no tag in the history clone but were executed; the preserveSep=false variant (U+001F removed, merging into 'ab') holds from 5.4.0 on, because in 5.3.x context queries on a CompletionAnalyzer index return nothing at all (the separate, fixed LUCENE-6858); all runs on Linux aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-522.html",
   "repro": "repro/LFV-522/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-601",
   "priority": "low",
   "priority_rank": 473,
   "novelty": "known",
   "withheld": false,
   "area": "suggest / analyzing suggester (AnalyzingSuggester FST input encoding: analyzed form + END_BYTE 0x00 + dedup byte, inherited by FuzzySuggester; Util.TopNSearcher result path)",
   "title": "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",
   "summary": "You build an AnalyzingSuggester (or a FuzzySuggester) with its default constructor and KeywordAnalyzer from two entries, 'cat' with weight 1 and 'cat\\u0000\\u0000s' with weight 5, and call lookup('cat', 5); you expect each entry once with the exact match 'cat' first, which is what you get when the second entry uses U+0001 instead of U+0000. Instead you get [cat/1, cat\\u0000\\u0000s/5, cat/1]: the suggester stores each entry as its analyzed bytes, then a 0x00 end marker, then a dedup byte, without escaping a 0x00 that belongs to the text, so the stored input of 'cat' is a prefix of the stored input of 'cat\\u0000\\u0000s', and the FST top-N search returns 'cat' a second time through a path that skips the suggester's duplicate filter. The same collision makes lookup('foo\\u0000') return 'foo' and lets a longer U+0000-extended entry take the EXACT_FIRST exact-match slot.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f2f91bae46cbc4a883324521767e4701fbbbc14a (trunk, svn r1391683) and its branch_4x twin 0c89e05d765ff2c15065cadfe11ca5d052ba8cf5 (svn r1391686; byte-identical AnalyzingSuggester.java; this is the commit the 4.x and 5.x release tags contain): LUCENE-3842 'add AnalyzingSuggester', committed by Michael McCandless (GitHub mikemccand), CHANGES credit Robert Muir, Sudarshan Gaikaiwari, Mike McCandless. It created AnalyzingSuggester with the FST input 'analyzed bytes + END_BYTE 0x00 + dedup byte', escaping only 0xff (then SEP_LABEL) inside the analyzed bytes, and with the EXACT_FIRST rule 'an END_BYTE arc leaving the node reached by the key is an exact match' [read]. The design was first written on the unreleased feature branch lucene3842 in bc0d717c8f6 (2012-09-23, 'LUCENE-3842: get escaping working; fix exactFirst to mean exact surface form'), which was squash-committed to trunk as f2f91bae46c. Second step: LUCENE-4534 (2537836d4ab trunk / a299cc65772 branch_4x, 2012-11-05, 'handle 0 byte values in lookup keys') made dictionaries whose analyzed forms contain 0x00 buildable (decoded sort comparator) but kept the encoding, which exposed the duplicate and EXACT_FIRST symptoms [exec]. Both steps are in 4.1.0, the first release of the API.",
   "introduced_date": "2012-09-28 (LUCENE-3842: f2f91bae46c on trunk, 0c89e05d765 on branch_4x); the LUCENE-4534 step that made the dictionary-side symptoms reachable is 2012-11-05 (2537836d4ab / a299cc65772); both are in 4.1.0",
   "first_affected_version": "4.1.0: the first release with AnalyzingSuggester and FuzzySuggester. git tag --contains lists releases/lucene-solr/4.1.0 as the first release tag for both 0c89e05d765 and a299cc65772 [read]; 4.1.0 fails 6/6 [exec]. 4.0.0, the last release before it, has no org.apache.lucene.search.suggest.analyzing package (lucene-suggest-4.0.0.jar, SHA-1-checked) and the probe reports API_ABSENT [exec].",
   "affected_versions": "every release from 4.1.0 through 10.6.0 (10.6.0 by reading) and main a9779ef3c193; never fixed. [exec] all 129 lucene-core releases from 4.1.0 to 10.5.2 in Maven Central give the same 6/6 wrong U+0000 results and 6/6 correct controls with -ea, and so do 4.1.0, 9.12.3, 10.5.2 and main with -da; 4.0.0 has no analyzing package. [exec] the finder's JUnit fails 3/4 on 9.1.0, 9.12.3, 10.5.2 and main (main with -ea and -da; it needs the 9.1+ test framework); the independent reproduction's JUnit fails 5/5 on 8.11.4, 9.12.3, 10.5.2 and main (main with -ea and -da). [exec] with the suggester sources from just before LUCENE-4534 only the key-side symptoms appear and a U+0000 dictionary fails to build under -ea; with LUCENE-4534's sources all 6 appear. [read] all 120 tagged releases from 4.1.0 to 10.5.2 contain both commits, END_BYTE = 0x0 and no lookup check for U+0000; AnalyzingSuggester.java and Util.java are unchanged on upstream main a95c754ee003, branch_10x and branch_10_6 (2026-10-26).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/5600",
    "https://issues.apache.org/jira/browse/LUCENE-4534",
    "https://github.com/apache/lucene/issues/4915",
    "https://issues.apache.org/jira/browse/LUCENE-3842",
    "https://github.com/apache/lucene/issues/5547",
    "https://issues.apache.org/jira/browse/LUCENE-4481"
   ],
   "doc": "",
   "repro": "repro/LFV-601/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-982",
   "priority": "low",
   "priority_rank": 474,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / FreeTextSuggester (n-gram suggester; build() failure atomicity of the unigram token total)",
   "title": "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",
   "summary": "You build a FreeTextSuggester (bigram model) from {foo bar baz, foo bar, foo bee, fun}, so lookup('f') scores foo 3/8 and fun 1/8 and lookup('foo b') ranks 'foo bar' (2/3) and 'foo bee' (1/3) above the backed-off unigram baz (0.4 x 1/8); then you rebuild the same instance from an empty dictionary, or one whose next() throws IOException, catch the exception and keep using it. You expect the previous model to be untouched, as its FST and getCount() are, because build() publishes those only after success. Instead build() has already set the unigram token total to 0, so foo and fun both score Long.MAX_VALUE (1.0), baz jumps to first place at 1.0 ahead of both real bigram predictions, and store() writes the zero total so a reloaded copy is damaged the same way.",
   "impact_class": "silent wrong results",
   "introduced_commit": "b50a2edbb2389797a7354775414052df91b108f6 (trunk, svn r1528517) and its branch_4x backport 9494be7ec2ae84e88b6fc07046c35cac15e790d2 (svn r1528521, the commit that shipped in 4.6.0): LUCENE-5214 'Add new FreeTextSuggester, to handle \"long tail\" suggestions' (migrated issue apache/lucene#6278; author Michael McCandless; before GitHub pull requests, so no PR) [read]: the class's first build() resets totTokens before it reads the input and replaces fst only at the end. Later changes to the same method that left the reset in place: LUCENE-5404 (b5926da2d67 / branch_4x fdf4595051a, 4.7.0; added count with the same early reset), LUCENE-10292 (a8d86ea6e8b / branch_9x 65f5a3bcc5a, apache/lucene#11328, 9.2.0; published fst and count only after success, left 'totTokens = 0'), #15134 (b85f030c6cc, 2025-10-09, main only; a refactor that moved the line)",
   "introduced_date": "2013-10-02 (b50a2edbb23, author and commit date)",
   "first_affected_version": "4.6.0 [exec], the first release with FreeTextSuggester; 4.5.1 has no FreeTextSuggester class [exec]",
   "affected_versions": "every release from 4.6.0 through 10.5.2, 10.6.0 (released 2026-10-29; branch_10_6 RC 4ae946e5a9b) and main a9779ef3c193; not fixed upstream (upstream main 645d4fe14a20 has no commit to FreeTextSuggester.java after 54283150a81, author date 2026-06-14; main and branch_11x still reset at :273, branch_10x and branch_10_6 at :274 [read]). [exec] the follow-up's portable check FreeTextFailedRebuildHistory (public API, scores only, -da) fails on 4.6.0, 4.6.1, 4.7.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.1.0, 9.2.0, 9.12.3, 10.0.0, 10.5.2 and main and passes on main with the fix shadowed; the finder's JUnit fails 5 of 5 on 9.1.0, 9.2.0, 9.12.3, 10.5.2 and main (-ea and -da on main) and its portable main() fails on 8.11.4 and 5.5.5; the independent reproduction's JUnit fails 5 of 7 (both controls pass) on main and 10.5.2 (-ea and -da) and 9.12.3 (-ea); the finder's translation validation fails on the branch_10_6 RC 4ae946e5a9b jars (-da). From 4.7.0 to 9.1.0 a failed build also reset getCount() (LUCENE-5404; LUCENE-10292 fixed that part in 9.2.0); from 9.2.0 on only the scores are wrong. Releases between the executed ones are inferred from the release tags in the history clone, which all keep the reset before the input loop (8.8.2-8.11.x tags are missing there; 8.11.4 was executed). Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-982.html",
   "repro": "repro/LFV-982/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-784",
   "priority": "low",
   "priority_rank": 475,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / analyzing suggester (AnalyzingSuggester.build failure atomicity: hasPayloads is published before the new FST; inherited by FuzzySuggester)",
   "title": "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",
   "summary": "You build an AnalyzingSuggester (or FuzzySuggester) from input with payloads, for example 'foo' with weight 10 and payload 'p1', then rebuild the same instance from a dictionary without payloads whose input throws an IOException partway through, and you expect lookups to keep returning the previous build ('foo', payload 'p1') or nothing. Instead lookup('fo') returns the text 'foo<U+001F>p1' with payload null, because build() stores the new input's payload flag at its start (AnalyzingSuggester.java:394) but replaces the FST only at its end (:589-590), so the old FST is read with the new flag; in the opposite direction (old build without payloads, failed rebuild with payloads) lookups return empty text with 'foo' as the payload, or trip the suggester's own assertion with -ea. A lookup made while such a rebuild is still reading its input sees the same mixture, and store() writes it to disk, so load() brings it back.",
   "impact_class": "silent wrong results",
   "introduced_commit": "234fa47dba438452a9952f748208ce8da6eea252 (LUCENE-4820 'add optional payload to Analyzing/FuzzySuggester', by GitHub mikemccand; trunk svn r1456095, 2013-03-13; branch_4x backport d11bc054c4e2f7239ddc74db3aa88722708af79f, svn r1456098, the same day; Subversion era, no pull request; issue now apache/lucene#5885). It added the hasPayloads field, assigned at the top of build() ('hasPayloads = payloads != null;', before the input loop, the offline sort and FST compilation), while the new FST is published only at the end [read] [exec]",
   "introduced_date": "2013-03-13",
   "first_affected_version": "4.3.0 [exec] (released 2013-05-06; the first release with suggester payloads, CHANGES 4.3.0 'LUCENE-4820: Add payloads to Analyzing/FuzzySuggester'); 4.1.0, 4.2.0 and 4.2.1 have no payload API (the probe does not compile on 4.2.1; their same-format control passes) [exec]",
   "affected_versions": "every release from 4.3.0 through 10.5.2, 10.6.0 (by reading) and main a9779ef3c193; not fixed upstream [exec] [read]. On 4.3.0 and 4.3.1 the in-memory symptom of the payloads-then-no-payloads case is 'foo' with the payload lost (the payload-mode decode then truncated the FST's cached output in place, fixed by LUCENE-5120 in 4.4.0); after store()+load() they show the same 'foo<U+001F>p1' as every later release.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-784.html",
   "repro": "repro/LFV-784/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-979",
   "priority": "low",
   "priority_rank": 476,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / Lookup persistence (load() failure atomicity: TSTLookup, AnalyzingSuggester, FuzzySuggester, FreeTextSuggester, FSTCompletionLookup, WFSTCompletionLookup)",
   "title": "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",
   "summary": "You build a TSTLookup from {aa, ab, ba, bb, cア}, then call load() with a stored copy of another model that is cut short or whose stream throws IOException part-way, and catch the exception. You expect the lookup to hold either its previous data or no data, but it reports the new model's getCount() and serves part of the new tree, and some lookups throw NullPointerException; the same happens when you load into a newly constructed TSTLookup. The other Lookups do the same in their own way, because each load() assigns count and model fields one after another as it reads: AnalyzingSuggester/FuzzySuggester can decode the new FST with the old payload flag (payload glued to the key), FreeTextSuggester scores the old FST with the new token total and changes getCount() even when it rejects a complete model saved with other grams/separator settings, and FST/WFSTCompletionLookup report the new count over the old FST.",
   "impact_class": "minor",
   "introduced_commit": "e71e68235205f962cf9ff3bbc2678c0084731109 (trunk, svn r1075804; branch_3x merge ab2691c7740632c94eb6477642e6ecfa65d1acf6, r1075841), JIRA SOLR-2375 'Store & Load functionality for Suggester Lookup implementations' (author Andrzej Bialecki; a Solr issue from before GitHub pull requests, not migrated to apache/lucene) [read]: it gave TSTLookup its first real load(), which replaces the tree with 'root = new TernaryTreeNode()' and only then fills it from the stream. Widened to all six fix sites by b5926da2d67820f5fdf8c8ec9b2e642b74d12070 (trunk r1565810; branch_4x fdf4595051ada90409a47f8259a6d6e17d4711be), LUCENE-5404 = apache/lucene#6467 (JIRA patch by Areek Zillur, no pull request) [read]: it made every load() start with 'count = input.readVLong()', which turned FST/WFSTCompletionLookup's single-assignment loads into mixed-state loads and put FreeTextSuggester's count ahead of its own separator/grams checks. Per site in between [read]: AnalyzingSuggester's trailer fields after the FST came with LUCENE-4481 (dc49949558d, 2012-10-21, apache/lucene#5547) and LUCENE-4820 (234fa47dba4, 2013-03-13, apache/lucene#5885, the hasPayloads byte); FreeTextSuggester's totTokens-before-FST order came with the class itself, LUCENE-5214 (b50a2edbb23, 2013-10-02, apache/lucene#6278)",
   "introduced_date": "2011-03-01 (e71e6823520, author and commit date; TSTLookup); 2012-10-21 and 2013-03-13 (AnalyzingSuggester trailer fields); 2013-10-02 (FreeTextSuggester); 2014-02-07 (b5926da2d67, LUCENE-5404, author and commit date: count first in every load())",
   "first_affected_version": "3.1.0 [exec] (Lucene/Solr 3.1.0, tag 2011-03-30; TSTLookup then lived in solr-core; the first Lucene artifact with it is lucene-spellchecker 3.3.0 [exec]). Per site: AnalyzingSuggester 4.1.0 (the payload symptom 4.3.0), FreeTextSuggester 4.6.0, FST/WFSTCompletionLookup and FreeTextSuggester's rejected-model case 4.7.0 [exec]; all six fix sites from 4.7.0; 4.6.1 is the last release whose FST/WFSTCompletionLookup.load are atomic [exec]",
   "affected_versions": "Every release that ships a Lookup with store/load: solr-core 3.1.0-3.2.0, lucene-spellchecker 3.3.0-3.6.2, all 132 lucene-suggest versions on Maven Central from 4.0.0-ALPHA to 10.5.2 (the last release before 10.6.0), 10.6.0 (branch_10_6 4ae946e5a9b) and main a9779ef3c193; not fixed upstream. [exec] the follow-up's version-portable harness LoadHistory (8 mirrored cases, public API, called by reflection over load(File), load(InputStream) and load(DataInput)) fails on solr-core 3.1.0, 3.3.0, 3.5.0, 3.6.0, 3.6.2, 4.0.0, 4.1.0, 4.2.1, 4.3.0, 4.5.1, 4.6.0, 4.6.1, 4.7.0, 4.10.4, 5.5.5, 6.0.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2, the branch_10_6 RC 4ae946e5a9b and main, with more failing cases in later releases (2 of 2 applicable in 3.x, 5 of 8 in 4.6.x, 8 of 8 from 4.7.0), and its fix control passes on main; the finder's JUnit fails 8 of 8 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main; the independent reproduction's JUnit fails 7 of 7 on 9.12.3, 10.5.2 and main; the translation validation finds 78 violating configurations on main and on the branch_10_6 RC jars. [read] the load() bodies in every release tag of the history clone; releases neither executed nor read in between are inferred from identical load() bodies on both sides. Upstream main 645d4fe14a20 (2026-10-28) has no commit under lucene/suggest after 2026-06-30 (author date). Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-979.html",
   "repro": "repro/LFV-979/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-763",
   "priority": "low",
   "priority_rank": 477,
   "novelty": "new",
   "withheld": false,
   "area": "classification / Naive Bayes classifiers (CachingNaiveBayesClassifier, SimpleNaiveBayesDocumentClassifier vs SimpleNaiveBayesClassifier, BM25NBClassifier)",
   "title": "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",
   "summary": "You index training documents where some carry an empty class value (for example StringField(\"cat\", \"\") for unlabelled rows) and build SimpleNaiveBayesClassifier, CachingNaiveBayesClassifier and SimpleNaiveBayesDocumentClassifier on the same reader, expecting the two subclasses to offer the same classes as their parent, which (like BM25NBClassifier) skips the empty class term with 'if (next.length > 0)'. Instead the caching and document classifiers list '' as a class: getClasses('car') gives ['', 'fruit', 'vehicle'] against the parent's ['fruit', 'vehicle'], and with two empty-class 'car bus' documents both assign '' to 'car bus' where the parent assigns 'vehicle'. Their class loops (CachingNaiveBayesClassifier.reInitCache and SimpleNaiveBayesDocumentClassifier.assignNormClasses) lack the parent's length check; whether the fix adds it there or removes it from the parent and BM25NBClassifier is open.",
   "impact_class": "minor",
   "introduced_commit": "8b2e0d937d58470edac86135c602ef70356c68b3 (caching variant: LUCENE-6479 / GitHub issue #7538 'improved cm testing, added stats, minor fixes', trunk; in one diff it adds the 'next.length > 0' guard to SimpleNaiveBayesClassifier.assignClassNormalizedList and changes CachingNaiveBayesClassifier.assignClassNormalizedList from private to protected, so the caching class's own class list, which reInitCache fills with every class term since LUCENE-5736 / 11a24cfbb86, goes live) and 71cea88773e8fe1086d0f2d7829b17b9c23bcc63 (document variant: LUCENE-6631 / #7689, trunk, adds SimpleNaiveBayesDocumentClassifier with a class loop without the guard; three later commits, 9534904c250, 8808cf53735 and c2c2e8a85e9, edited that loop and kept it unguarded) [read]; no GitHub PR (svn/JIRA era)",
   "introduced_date": "2015-09-02 (caching variant); 2015-10-20 (document variant)",
   "first_affected_version": "6.0.0 [exec]; last unaffected release 5.5.5 [exec]",
   "affected_versions": "Every release from 6.0.0 to 10.5.2, and main a9779ef3c193; never fixed (the class loops are unchanged at upstream main f7bcc0abd816 and branch_10x, and no open PR changes them; read 2026-10-27). [exec] a cross-version probe fails on 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main, each with -ea and -da, and the finder's JUnit fails on 10.0.0, 10.5.2 and main (-ea and -da); the independent reproduction's JUnit fails on 10.5.2 and 9.12.3, the intended-behaviour check's history check on 6.0.0. [read] all 83 release tags from 6.0.0 on in the history clone carry the guarded parent loop and the two unguarded variant loops; 8.8.2-8.11.4 are not tagged there (8.11.4 executed from the released jars). Not affected [exec]: 5.0.0, 5.3.2, 5.4.0, 5.5.5 (and 5.5.4, the intended-behaviour check): in 5.x the caching classifier's own path was unreachable, so it returned SimpleNaiveBayesClassifier's results (in 5.0.0-5.3.2 the parent itself still offered ''), and the document classifier did not exist. A regression in 6.0.0 relative to 5.x, released for about ten years.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-763.html",
   "repro": "repro/LFV-763/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-510",
   "priority": "low",
   "priority_rank": 478,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / common miscellaneous (ProtectedTermFilterFactory#populateInnerFilters: wrappedFilters factory construction; symptom in TruncateTokenFilterFactory prefixLength)",
   "title": "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",
   "summary": "You configure ProtectedTermFilterFactory with wrappedFilters=truncate and truncate.prefixLength=4 and pin luceneMatchVersion to 10.4.0 (in the factory args, or through CustomAnalyzer.withDefaultMatchVersion), on Lucene 10.5 or later. You expect the wrapped truncate to keep the legacy behaviour that the pinned version selects for back-compat, the first 4 UTF-16 chars, as an unwrapped truncate and the equivalent when()/endwhen() form do under the same version. Instead populateInnerFilters builds the wrapped factory from the 'truncate.*' arguments only, so it runs at Version.LATEST and keeps 4 code points: the token 'ab😀😀cd' becomes 'ab😀😀' instead of 'ab😀', with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "d91273ddf0b524e14ebcc2a90bbedd8d9ae319d4 (master) and its branch_7x backport 97490ac7c66313625c9526a466ab96981e249746, LUCENE-8273 (#9320 'Add a ConditionalTokenFilter'; JIRA-era patch, no GitHub PR; author sarowe), which added the wrappedFilters / filterName.argName parameters and populateInnerFilters [read] [exec]. The silent symptom with stock filters was enabled by #15900 (fixes #15899; 86ba05a598257883b4494307cae7ca00d0fb2d4d on main, b858e81d1be5ae9737e76c17fd1cb35a2c4e5222 on branch_10x; merged by msokolov, co-authored by uschindler), which made truncate prefixLength depend on luceneMatchVersion; #15900 itself is correct",
   "introduced_date": "2018-05-20 (defect, d91273ddf0b); 2026-04-06 (#15900 merged, which made it silently change output)",
   "first_affected_version": "7.4.0 for the defect (wrapped factories get Version.LATEST) [exec]; 10.5.0 for silent wrong analysis with stock Lucene filters (wrapped truncate prefixLength) [exec]; last release without the silent symptom 10.4.0 [exec]",
   "affected_versions": "defect in every release from 7.4.0: 7.4.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.6.0 (10.6.0 by reading) and main ea57360912ed [exec]. Silent wrong analysis with stock filters only in 10.5.0, 10.5.1, 10.5.2, 10.6.0 (by reading) and main [exec]. 8.4.0-9.12.3 had only a loud consequence: a wrapped concatenateGraph rejects preserveSep ('Unknown parameters') under luceneMatchVersion < 8.4.0 while the unwrapped filter accepts it [exec]. Intermediate releases by reading only (identical code); tags 8.8.2-8.11.3 are not in the local clone. branch_10x and branch_10_6 heads of 2026-10-24 lack the forwarding [read]. Not fixed upstream: upstream main ProtectedTermFilterFactory.java re-read 2026-10-26 is identical (last change 378ca8d1bbf3, javadoc only) and CHANGES.txt has no entry [read]. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-510.html",
   "repro": "repro/LFV-510/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-857",
   "priority": "low",
   "priority_rank": 479,
   "novelty": "new",
   "withheld": false,
   "area": "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)",
   "title": "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",
   "summary": "You normalize a keyword field with ICUFoldingFilter and index 'O´Brien' (an acute accent used as an apostrophe); you expect the term 'obrien', because Lucene's own folding table DiacriticFolding.txt deletes U+00B4 along with the other spacing diacritics, as every release up to 8.11.x did and as the filter still does for ` and ^. Since 9.0.0 the term is 'o brien': a 2021 build change (LUCENE-9900) started passing the data files to the gennorm2 compiler sorted by file name, which puts the standard NFKC files last, and in gennorm2 a later file overrides an earlier one, so ´ ¨ ¯ ¸ ˘ ˜ and other spacing accents now become a space and 236 modifier letters fold to their base letter instead of being removed. The change was meant only to make regeneration incremental and its review assumed the order did not matter; 292 entries of Lucene's tables are now dead, and 271 code points fold differently.",
   "impact_class": "silent wrong results",
   "introduced_commit": "010e3a1ba960ea0dcd7e5092073d2a55a21b0ac9 ('LUCENE-9900: Regenerate/ run ICU only if inputs changed (#61)', PR apache/lucene#61 by GitHub dweiss, JIRA LUCENE-9900 = #10939): a build-only change that replaced the explicit gennorm2 input list 'nfc.txt, nfkc.txt, nfkc_cf.txt, BasicFoldings.txt, DiacriticFolding.txt, DingbatFolding.txt, HanRadicalFolding.txt, NativeDigitFolding.txt' in gradle/generation/icu.gradle by the *.txt files sorted by name (upper-case names first, so Lucene's five tables now precede nfc, nfkc and nfkc_cf) and committed the regenerated utr30.nrm (58,720 -> 59,200 bytes); no data file changed [exec] [read]. A regression: Lucene's tables were the last inputs from 2010 (LUCENE-1343 ant build, nfc.txt prepended by LUCENE-3747 in 2012) through the first gradle port (LUCENE-9767, 2021-02-14) and are the first inputs since",
   "introduced_date": "2021-04-02 (author date = commit date 2021-04-02T09:46:43Z; PR #61 opened 08:26:43Z and merged 09:46:43Z the same day)",
   "first_affected_version": "9.0.0 [exec] (it ships the introducing commit's utr30.nrm blob 6409b872edf byte for byte); last unaffected release 8.11.4 [exec] (the 8.x line was built by the ant build with the old order and never got the commit); 8.8.1, the last release tagged before the commit date, is also unaffected [exec]",
   "affected_versions": "every release from 9.0.0 to 10.5.2 (git tag --contains 010e3a1ba96; their jars carry one of four utr30.nrm blobs, each regenerated at or after the commit with ICU 68.2, 70.1, 74.2 or 77.1, all four executed), the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193 [exec] [read]. Not affected: 8.11.4 and 8.8.1 [exec], every 8.x jar (old-order blobs 4ded6c97762 for 8.0.0-8.2.0 and 4c31f905077 for 8.3.0-8.11.4) [read], and the releases from 3.1.0 [read]. With the Unicode 13 data of 2021 the inversion changed 118 code points; with main's data the two orders differ on 271",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-857.html",
   "repro": "repro/LFV-857/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1119",
   "priority": "low",
   "priority_rank": 480,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / icu (ICUTransformFilterFactory: 'direction' parameter parsing through AbstractAnalysisFactory.get(..., caseSensitive=false))",
   "title": "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)",
   "summary": "You build an ICUTransformFilterFactory with id=Cyrillic-Latin and direction=\"Forward\", which the factory accepts because it checks direction case-insensitively, and analyze 'Российская Федерация'. You expect the forward Cyrillic-Latin transliteration [Rossijskaâ, Federaciâ], as with direction=\"forward\". You get the Cyrillic tokens back unchanged, with no error: the validation hands back the caller's own spelling, the factory then tests \"forward\".equals(direction), and every accepted spelling other than exact lower-case 'forward' builds the reverse (Latin-Cyrillic) transliterator.",
   "impact_class": "silent wrong results",
   "introduced_commit": "14a85ce98c91ed8b03b98379ac8e0db086d25120 (branch_4x, svn r1465225, Robert Muir, 'LUCENE-4877: additional improvements'; the copy that shipped first, in 4.3.0, and the one in every 4.x and 5.x release) and trunk commit 6de43dea0af9d0407d7c218d077c6025b04a4282 (svn r1463335, Steven Rowe, 'LUCENE-4877: more param parsing verbs'; in every release from 6.0.0), both for LUCENE-4877 'Fix analyzer factories to throw exception when arguments are invalid' (migrated as apache/lucene#5942; SVN commits, no GitHub PR). Both replaced the factory's own parsing (direction == null || direction.equalsIgnoreCase(\"forward\") -> FORWARD; equalsIgnoreCase(\"reverse\") -> REVERSE; else IAE) with get(args, \"direction\", [forward, reverse], \"forward\", false) plus \"forward\".equals(direction), and added that get() overload, which returns the caller's spelling on an equalsIgnoreCase match; the equals line is unchanged since [read]",
   "introduced_date": "2013-04-01 (author date of the trunk commit 6de43dea0af); 2013-04-06 (author date of the branch_4x commit 14a85ce98c9, which shipped first)",
   "first_affected_version": "4.3.0 [exec], so this is a regression of LUCENE-4877",
   "affected_versions": "every release from 4.3.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT): 118 release tags in the history clone, 4.3.0-5.5.5 through 14a85ce98c9 and 6.0.0-10.6.0 through 6de43dea0af [read]. Executed: the one-test JUnit fails on main (-ea and -da, also in the re-run), 10.6.0 (-ea and -da) and 9.12.3 (-ea and -da); the independent reproduction's SPI-path test fails on main (-ea and -da), 10.6.0, 10.5.2 and 9.12.3 (-ea); a main() history probe through the public factory API fails on 4.3.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.12.3, 10.6.0 and main and passes on 4.0.0 and 4.2.1 (-ea) [exec]. Lucene 4.0.0-4.2.1 are not affected; before 4.0 the factory was a Solr class. Not new in 10.6 (10.5.2 fails). Not fixed upstream: upstream main 1c2072f0284 (author date 2026-11-02) has ICUTransformFilterFactory.java and AbstractAnalysisFactory.java byte-identical to 5adff78bb168 (blobs 3880c4a6816 and 53a456aeaea, also at 10.6.0 and ea57360912ed), and the newest commit on the factory is 7f8b7ffbcad (author date 2021-01-03, reformatting) [read]. Executed on Linux aarch64 with JDK 25.0.3 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1119.html",
   "repro": "repro/LFV-1119/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-956",
   "priority": "low",
   "priority_rank": 481,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / synonym file loading (SynonymGraphFilterFactory and the deprecated SynonymFilterFactory loadSynonyms -> SolrSynonymParser, WordnetSynonymParser)",
   "title": "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",
   "summary": "You configure SynonymGraphFilterFactory (or SynonymFilterFactory) with a synonyms file that an editor saved as UTF-8 with a byte order mark (bytes EF BB BF) and expect the same rules as from the file without the mark, because Lucene's shared resource-line loader skips a leading BOM for the word-list factories that read through it (WordlistLoader.getLines, 'skip initial bom marker', SOLR-1865) and the synonym factory itself skipped it until 3.4.0. Instead the factory decodes the file with its own UTF-8 reader and SolrSynonymParser keeps U+FEFF glued to the first line: with the first rule 'foo, bar' the text 'foo' is no longer expanded (and 'bar' gains the invisible synonym '\\uFEFFfoo'), a first rule 'baz => qux' never fires, and a first line '#couch, sofa' is no longer a comment, so 'sofa' expands to '\\uFEFF#couch'. In WordNet format the fixed-column synset id (substring(2, 11)) is shifted by one character, so the first word ends up in a synset of its own; nothing reports an error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "015ecfa0a0255f053682bb2436b2b8dec5cb8283 (LUCENE-3233 'HuperDuperSynonymsFilter', apache/lucene#4306; trunk svn r1145158, author rmuir, message 'LUCENE-3233: improve ram/perf of SynonymFilter, add wordnet parsing, nuke contrib/wordnet'; no pull request, Subversion era) with the branch_3x backport a52015db05f790613906a9858531ff16e3d78b8a (r1145178), the one released in 3.4.0. The commit added FSTSynonymFilterFactory, which passes new InputStreamReader(loader.openResource(file), decoder) straight to the new SolrSynonymParser and WordnetSynonymParser, and made SynonymFilterFactory use it for luceneMatchVersion >= 3.4; before, SynonymFilterFactory.loadRules read the rules with SolrResourceLoader.getLines, which had skipped a leading U+FEFF before the '#' comment test since SOLR-1865 (f3c25f02d587, 3.x backport 7aaf7ed9a20, 2010-05-08). So this is a regression; no issue comment (body and 41 comments read), CHANGES entry or upgrade note mentions BOM or encoding handling, so the drop looks unintended (not provable). Never fixed: git log --all -G 'FEFF|[Bb][Oo][Mm]' over the synonym paths finds no commit on any branch, and the reader line was carried unchanged through LUCENE-4095 (bc3a3dc5d47), LUCENE-5219 (9d16038391b), LUCENE-5945 (3eb66fb19ca) and LUCENE-6664 (c0467bb9291, which added SynonymGraphFilterFactory). [read]",
   "introduced_date": "2011-07-11 (trunk and branch_3x; author and commit dates identical, Subversion import)",
   "first_affected_version": "3.4.0 [exec] (Solr SynonymFilterFactory with luceneMatchVersion >= 3.4, the value the 3.4.0 example solrconfig.xml ships; the parsers ship in Lucene contrib analyzers from 3.4.0 and the Lucene-module factory exists from 4.0.0-beta, LUCENE-4044). Last unaffected release: 3.3.0 [exec]. luceneMatchVersion < 3.4 kept the BOM-safe SlowSynonymFilterFactory through 4.10.4 [exec]; 5.0.0 removed it. format=wordnet was added by the introducing commit, so for that format no unaffected release exists.",
   "affected_versions": "Every release from 3.4.0 to 10.6.0 (branch_10_6 head 4ae946e5a9b9) and main a9779ef3c193 [exec]. SynonymGraphFilterFactory is affected since it was added in 6.4.0 [exec]. Not affected: 3.1-3.3, which read synonyms through getLines [3.3.0 exec]. Upstream main 645d4fe14a20 (2026-10-28) has no synonym-package or WordlistLoader commit after a9779ef3c193.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-956.html",
   "repro": "repro/LFV-956/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-950",
   "priority": "low",
   "priority_rank": 482,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-kuromoji + analysis-nori / user dictionary loading (UserDictionary.open, reached through the JapaneseTokenizerFactory / KoreanTokenizerFactory userDictionary argument)",
   "title": "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",
   "summary": "You give KoreanTokenizerFactory or JapaneseTokenizerFactory a user dictionary file that an editor saved as UTF-8 with a byte order mark (bytes EF BB BF), and expect the same dictionary as from the file without the mark, because Lucene's shared resource-line loader skips a leading BOM for the other file-based analysis factories (WordlistLoader.getLines, 'skip initial bom marker', SOLR-1865). Instead both factories decode the file themselves and pass it to UserDictionary.open, which keeps the invisible U+FEFF on line 1: in Nori the first entry becomes '\\uFEFF세종시', which no text contains, so 세종시 is segmented [세, 종시] instead of the user's [세종, 시] with no error. Kuromoji (9.0.0 and later) rejects the file with 'Illegal user dictionary entry \\uFEFF関西国際空港 - the concatenated segmentation (関西国際空港) does not match the surface form (\\uFEFF関西国際空港)', and when line 1 is a '#' comment or blank it throws ArrayIndexOutOfBoundsException 'Index 1 out of bounds for length 1', because the BOM hides the comment from its 'skip empty lines or comment lines' check.",
   "impact_class": "silent wrong results",
   "introduced_commit": "kuromoji: cd372bdc83836148a7ae2e2958407ff0a37b7fc2 (LUCENE-3305 'add Kuromoji Japanese morphological analyzer', apache/lucene#4378, trunk svn r1230748, author Robert Muir; the loop was first imported on the lucene3305 contribution branch in bee8224c049, unreleased) with the branch_3x backport 8c9485fb66427e54ff0dac9708fdcbe72ba62e94 (r1231536), the one released in 3.6.0. nori: e851b89cbeb1f55edc0f2c1276e2ae812eca2643 (LUCENE-8231, apache/lucene#9278, master, author Jim Ferenczi) with branch_7x 8651fbaa8bc65fdfec397ad4e7ebe2b5acf78d7b, released in 7.4.0; its open() loop was copied from kuromoji (git blame -w -M -C -C traces the loop lines to cd372bdc838). Neither loader has ever had BOM handling (git log -i -G 'feff|bom|byte.order' over both modules and the 3.x kuromoji sources: no commit), so this is an omission from the first commit, not a regression. [read]",
   "introduced_date": "2012-01-12 (kuromoji, trunk; branch_3x 2012-01-14; contribution-branch import 2012-01-03); 2018-04-13 (nori)",
   "first_affected_version": "3.6.0 [exec] for kuromoji (tagged 2012-04-11; UserDictionary loader; the Lucene JapaneseTokenizerFactory from 4.0.0 [exec], in 3.6 the factory was Solr-only); 7.4.0 [exec] for nori (tagged 2018-06-18; UserDictionary.open and KoreanTokenizerFactory). Neither API exists earlier: 3.5.0 has no kuromoji and 7.3.1 has no nori [exec].",
   "affected_versions": "Every release from 3.6.0 (kuromoji) and 7.4.0 (nori) to 10.5.2, 10.6.0 (by reading: branch_10_6 head 4ae946e5a9b9, below), and main a9779ef3c193 [exec]. Symptom by era [exec]: kuromoji BOM + entry on line 1 = that entry silently never matches in 3.6.0-8.11.4 (the 8.x backport of the LUCENE-8933 check only rejects longer segmentations), RuntimeException 'Illegal user dictionary entry' from 9.0.0 (strict LUCENE-8933 check, 73ba88a50de); kuromoji BOM + '#' comment or blank line 1 = ArrayIndexOutOfBoundsException in every release; nori BOM + entry on line 1 = that entry silently lost in every release. Not fixed upstream: no commit touches the four files after a9779ef3c193 (last commits dbf0d1426f13, author date 2026-05-14, and 378ca8d1bbf3, 2026-01-15, both unrelated); upstream main head 645d4fe14a20 (2026-10-28) and the branch_10_6 head 4ae946e5a9b9 have identical UserDictionary sources [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-950.html",
   "repro": "repro/LFV-950/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-990",
   "priority": "low",
   "priority_rank": 483,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / text-file dictionaries (FileDictionary feeding Lookup.build, PlainTextDictionary feeding SpellChecker.indexDictionary)",
   "title": "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",
   "summary": "You build a suggester or a spell checker from a UTF-8 text file whose first line is 'foo<TAB>5' (or just 'foo') but which an editor saved with a byte order mark (the bytes EF BB BF), passing it to FileDictionary(InputStream) or PlainTextDictionary(Path or InputStream), whose javadoc says 'NOTE: content is treated as UTF-8', and you expect the same entries as from the same file without the mark, because the mark is only an encoding signature and Lucene's own line loaders skip it (WordlistLoader.getLines, SOLR-1865; hunspell, LUCENE-5505). Instead these constructors decode the bytes with Java's UTF-8 decoder, which returns the mark as the character U+FEFF, and nothing removes it, so the first entry becomes '\\uFEFFfoo': WFSTCompletionLookup, FSTCompletionLookup and TSTLookup return nothing for lookup(\"fo\"), AnalyzingSuggester returns '\\uFEFFfoo', and a SpellChecker reports exist(\"foo\") = false. No error is raised and only the first line is affected.",
   "impact_class": "silent wrong results",
   "introduced_commit": "d69c73c0277acc00ed5f220b46070ee1996c09d7 (LUCENE-4199 'fix more default charset uses', svn r1358555 on the lucene4199 work branch, author Robert Muir; merged to trunk as e3813f80300b (r1359202) and to branch_4x as f7941ee03a3a (r1359229) by Uwe Schindler on 2012-07-09; migrated issue apache/lucene#5271 'Add ANT tool to track/disallow forbidden method invocations'; Subversion era, no pull request) [read]. It replaced the platform-charset readers in FileDictionary(InputStream), PlainTextDictionary(InputStream) and PlainTextDictionary(File) with IOUtils.getDecodingReader(..., UTF-8), so from then on Lucene itself decodes UTF-8 but nothing skips the UTF-8 signature; the issue's 32 comments never mention a BOM. Later constructors carry the same decoding: FileDictionary(InputStream, String) (LUCENE-5337, 4.7.0) and PlainTextDictionary(Path) (LUCENE-5945, 5.0.0). The javadoc 'NOTE: content is treated as UTF-8' came with d4aace10381 / 73693e1a9f7 (Robert Muir, 2012-09-21, first in 4.0.0). Not a regression of the symptom: before LUCENE-4199 the constructors used the JVM default charset, which showed the same U+FEFF when that default was UTF-8 and misdecoded the whole file otherwise (the platform-charset problem of LUCENE-1413).",
   "introduced_date": "2012-07-07 (author date of d69c73c0277 on the work branch; trunk and branch_4x merges 2012-07-09)",
   "first_affected_version": "4.0.0-BETA [exec] (pre-release, tag 2012-08-10; with file.encoding=ISO-8859-1 it still keeps U+FEFF and decodes an e-acute correctly, so the defect no longer depends on the platform); first final release 4.0.0 [exec]. Last unaffected as claimed: 4.0.0-ALPHA and the 3.x line (3.6.2) [exec], which used the JVM default charset: with a UTF-8 default they show the same U+FEFF, with ISO-8859-1 they misdecode the whole file instead.",
   "affected_versions": "Every release from 4.0.0-BETA to 10.5.2, 10.6.0 (released 2026-10-29; branch_10_6 4ae946e5a9b9) and main a9779ef3c193 [exec]. Upstream main 645d4fe14a20 (2026-10-28) has no commit on either file after ae82130c71b1 (2025-08-22) and b85f030c6cce (2025-10-09).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-990.html",
   "repro": "repro/LFV-990/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-718",
   "priority": "low",
   "priority_rank": 484,
   "novelty": "new",
   "withheld": false,
   "area": "core + analysis-common + suggest / words-file factories (format=\"snowball\" loader: AbstractAnalysisFactory.getSnowballWordSet, WordlistLoader.getSnowballWordSet)",
   "title": "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",
   "summary": "You configure StopFilterFactory (or KeepWordFilterFactory, CommonGramsFilterFactory, CommonGramsQueryFilterFactory or SuggestStopFilterFactory) with format=\"snowball\" and a UTF-8 words file that begins with a byte order mark, and expect the same words that the default \"wordset\" format reads from such a file, because that format skips a leading BOM (WordlistLoader.getLines, 'skip initial bom marker', a rule recorded in SOLR-1865). Instead the snowball loader keeps the invisible U+FEFF glued to the first word, so the set holds \"\\uFEFFthe\" instead of \"the\" (getStopWords() = [a, \\uFEFFthe, an]): StopFilter no longer removes 'the', KeepWordFilter drops the tokens of the first keep word, CommonGrams does not treat it as common, and a BOM before a comment or blank first line adds a stray \"\\uFEFF\" entry. No error is raised.",
   "impact_class": "silent wrong results",
   "introduced_commit": "c880ef064789401f1351af56755ea165b3e04444 (SOLR-1860 'support snowball format in stoplists', trunk r1240784, rmuir) with its branch_3x twin 1a752ccc41f38c92d3cbf82f6341fb1d9a378cd3 (r1240791). It added the factory method getSnowballWordSet(ResourceLoader, String, boolean) (then in Solr's BaseTokenStreamFactory), which decodes each words file with its own UTF-8 InputStreamReader and passes it to WordlistLoader.getSnowballWordSet(Reader, CharArraySet). The default format went through ResourceLoader.getLines, which had skipped a leading BOM since SOLR-1865 (f3c25f02d58, 2010-05-08). The code reached Lucene's own jars through the factory migration LUCENE-2510/LUCENE-4044: the base class on 2012-05-08 (0bad718d589) and StopFilterFactory, CommonGramsFilterFactory and CommonGramsQueryFilterFactory on branch_4x on 2012-07-25 (677846e6a0f, r1365673, uschindler; trunk 142d3c788fa). [read]",
   "introduced_date": "2012-02-05 (SOLR-1860 commit; the code reached Lucene's own jars on branch_4x on 2012-07-25)",
   "first_affected_version": "4.0.0-BETA [exec] (tagged 2012-08-10), the first Lucene release whose jars contain a factory with format=snowball; first GA release 4.0.0 [exec] (tagged 2012-10-11). 3.6.2 and 4.0.0-ALPHA do not have the API [exec]. Outside Lucene's artifacts the same code first shipped in Solr 3.6.0 [read].",
   "affected_versions": "Every Lucene release from 4.0.0-BETA to 10.5.2: 4.0.0-BETA plus all 130 x.y.z releases from 4.0.0 to 10.5.2 (every 4.x, 5.x, 6.x, 7.x, 8.x, 9.x and 10.x release in Maven Central), and main a9779ef3c193 [exec]. Not fixed upstream (no later commit touches either loader, including the 2 commits after a9779ef3c193 [read]). Factory reach grew over time [exec]: StopFilterFactory, CommonGramsFilterFactory (and CommonGramsQueryFilterFactory, subclass, [read]) from 4.0.0-BETA; SuggestStopFilterFactory from 5.0.0 (LUCENE-5820); KeepWordFilterFactory from 8.11.0 (LUCENE-10008, which gave it the format parameter).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-718.html",
   "repro": "repro/LFV-718/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-719",
   "priority": "low",
   "priority_rank": 485,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / ICU (ICUTokenizerFactory per-script rule files: rulefiles, parseRules)",
   "title": "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)",
   "summary": "You configure ICUTokenizerFactory with rulefiles=\"Latn:latin.rbbi\" and a rule file saved as UTF-8 with a byte order mark (BOM), as editors such as Windows Notepad often write and as ICU's own rule-file compiler genbrk accepts (it strips the BOM, and its man page recommends one), and expect the same tokens as with the same file without the BOM. Instead ICUTokenizerFactory.parseRules decodes the BOM to U+FEFF and passes it to ICU's RuleBasedBreakIterator(String) as rule text: a file that starts with the rule '.+ {200};' (alone or after '#' comment lines) compiles with U+FEFF as a literal prefix of that rule, so 'ab cd' gives no tokens at all instead of ['ab cd'], and a file that starts with a comment and '!!forward;' (the shape of Lucene's Latin-break-only-on-whitespace.rbbi) fails with 'IllegalArgumentException: Error 66052 at line 2 column 1'. Nothing on disk is corrupted, but in the silent case all text of the tailored script disappears from the analyzed output with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "6024e1465e02 (svn trunk r1416617, 2012-12-03, by sarowe), SOLR-4123 'Add per-script customizability to ICUTokenizerFactory via rule files in the ICU RuleBasedBreakIterator format' (Subversion and JIRA era, no PR; none of the 21 JIRA comments mentions a BOM or the file encoding); merged to branch_4x the same day as 9a23a0799e5e (r1416629), the commit that shipped in 4.1.0. It added the rulefiles argument and parseRules, which reads the file through a UTF-8 decoding reader, drops '#' lines and never removes a leading U+FEFF [read] [exec]. Later commits on parseRules changed no behaviour (2f8192f3c5a, LUCENE-5560, 2014, charset constant; 7f8b7ffbcad, LUCENE-9570, 2021, reformatting), and git log --all -G 'FEFF|bom' on the file finds no commit. Not a regression and not tied to an ICU4J version",
   "introduced_date": "2012-12-03",
   "first_affected_version": "4.1.0 [exec] (the first release with rulefiles; 4.0.0 has no inform(ResourceLoader) in this factory, ignores the argument and never opens the file [exec])",
   "affected_versions": "Every release from 4.1.0 to 10.5.2, 10.6.0 (by reading) and main a9779ef3c193; never fixed. [exec] the follow-up's portable public-API check fails with both outcomes on 4.1.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (BOM-less controls give the custom-rule tokens everywhere) and passes on main with the fix shadowed; the finder's JUnit fails 2 of 3 on 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da on main); the independent reproduction's JUnit fails 4 of 10 on main (-ea and -da), 10.5.2 (-ea and -da) and 9.12.3 (-ea); a separate test fails on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's probe fails 3 of 6 on main (-ea and -da) and 10.5.2. The bundled ICU4J versions from 49.1 to 78.3 all behave the same. [read] the normalized parseRules body is identical in every release tag of the history clone from 4.1.0 to 8.8.1 and from 9.0.0 to 10.5.2 (8.9-8.11 are untagged there; 8.11.4 was executed). Not fixed upstream: ICUTokenizerFactory.java has no BOM handling on upstream main a95c754ee003, branch_10x 1309534296e or branch_10_6 2763db11b0a, and lucene/analysis/icu is unchanged between a9779ef3c193 and a95c754ee003 (local fetch of 2026-10-26, read 2026-10-27). Not affected: 4.0.0 and older (no rulefiles feature). All runs on Linux aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-719.html",
   "repro": "repro/LFV-719/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-696",
   "priority": "low",
   "priority_rank": 486,
   "novelty": "new",
   "withheld": false,
   "area": "analysis/stempel / egothor stemmer trie reductions (Trie.reduce with Lift and Gener; the shared PolishAnalyzer.getDefaultTable() table)",
   "title": "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",
   "summary": "You call reduce(new Gener()) or reduce(new Lift(..)) on a stempel Trie, for example on PolishAnalyzer.getDefaultTable(), which is documented as 'an unmodifiable instance of the default stemmer table', and expect what Trie.reduce's javadoc says, 'the newly reduced Trie', with the input left as it was (Optimizer and Optimizer2 behave so). Instead Lift.optimize and Gener.optimize take the input's own row list and rewrite its cells in place (Lift moves commands up a level and clears references, Gener drops infrequent commands and references) before copying them into the result, so the input answers differently afterwards: after PolishAnalyzer.getDefaultTable().reduce(new Gener()) every new PolishAnalyzer stems 'książkami rzekami pracowali' to [książk, rzekami, pracowali] instead of [książek, rzekść, pracować], and a one-key trie {aa -> Da} reduced with Lift(false) starts to answer getLastOnPath('a') = Da instead of nothing. Copying the rows before the rewrite fixes it; upstream TestStemmer, which reduces one trie five times, then needs a fresh trie per reduction.",
   "impact_class": "silent wrong results",
   "introduced_commit": "98c47c57e0a54ab4aab9d91dd60c33edef130893 (trunk, SVN r940433, 'LUCENE-2298: Add stempel, an algorithmic stemmer with included Polish support', JIRA LUCENE-2298 'Polish Analyzer', now GitHub issue #3374; a JIRA patch by @rmuir of contributed code, CHANGES credits Andrzej Bialecki via Robert Muir; SVN era, no pull request), branch_3x backport 58328f0379049045b325d2082295836a7a50e9ce ('LUCENE-2298: backport', r941704, the copy that shipped in 3.1.0): the import already had Lift.optimize take 'orows = orig.rows' and liftUp rewrite those cells, and Gener.optimize/eat clear cells of the input in place [read]. The JVM-wide default-table consequence was enabled by 04f3188bf9b8ce059f72399bad721d9190ed2dc0 (trunk) / b3818670d3545bfc9abae3bcdf766da4ca7308c0 (branch_4x), SOLR-3737 by @rmuir, which added the public PolishAnalyzer.getDefaultTable() ('Returns an unmodifiable instance of the default stemmer table'), made StempelPolishStemFilterFactory share that one table and made Trie.add package-private, but did not touch reduce, Lift or Gener [read]. Not a regression: the in-place rewrite is as old as the module in Lucene, and the Lucene.NET port has the same code [read].",
   "introduced_date": "2010-05-03 (trunk 98c47c57e0a); branch_3x backport 2010-05-06 (58328f03790); default-table consequence 2012-08-17 (SOLR-3737, 04f3188bf9b / b3818670d35)",
   "first_affected_version": "3.1.0 [exec]; 3.0.3 has no stempel API (the probe does not compile) [exec], so no release has the API without the bug. The default-table form first in 4.0.0 [exec].",
   "affected_versions": "every release from 3.1.0 through 10.5.2 and main a9779ef3c193 (unreleased 11.0) [exec]. branch_10x and branch_10_6 have the same lines [read], so 10.6.0 (released 2026-10-29 from branch_10_6) is affected too. Not fixed upstream: upstream main a95c754ee003 (2026-10-26) has the same Lift/Gener lines, no commit after a9779ef3c193 touches lucene/analysis/stempel, and no open PR touches the fix site (2026-10-27) [read]. lucene/analysis/stempel is identical at ea57360912ed and a9779ef3c193 (empty git diff). Executed on Linux aarch64 with JDK 25 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-696.html",
   "repro": "repro/LFV-696/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-598",
   "priority": "low",
   "priority_rank": 487,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / analysis-common payloads (DelimitedPayloadTokenFilterFactory, PayloadEncoder, DelimitedPayloadTokenFilter)",
   "title": "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",
   "summary": "You configure DelimitedPayloadTokenFilterFactory with your own PayloadEncoder class whose encode() reuses one BytesRef, which is correct inside any single token stream because PayloadAttributeImpl deep-copies payloads, and you index from four threads; you expect every document to keep its own payload, as it does when each filter gets its own encoder through the public constructor. Instead the factory creates the encoder once in inform() and passes that one instance to every filter in create(), so the per-thread analyzer components share it and another thread's encode() overwrites a payload before the indexer reads it: on main, 384 to 7,153 of 20,000 documents end up with another document's payload, with no exception. PayloadEncoder, the factory and the analysis-factory javadocs say nothing about the encoder being shared or needing to be thread-safe, while the sibling PhoneticFilterFactory creates its class-loaded encoder per filter for exactly this reason.",
   "impact_class": "minor",
   "introduced_commit": "b5620d8614606e70241db30e117d32404010be84 (SOLR-1285 'Add DelimitedPayloadTokenFilterFactory, tests and short example', Grant Ingersoll, 2009-07-16, Solr trunk svn r794669) [read]. The factory entered a Lucene artifact unchanged with LUCENE-2510 (GitHub #3584, factories moved from Solr to the analysis module): branch commit fe2d1194fb6 ('apply movefactories.sh', Robert Muir, 2012-07-24), trunk merge 142d3c788fa and branch_4x merge 677846e6a0f (Uwe Schindler, 2012-07-25), the latter putting it into the 4.0 release line. No pull request (Subversion era)",
   "introduced_date": "2009-07-16 (Solr code, SOLR-1285); 2012-07-25 (moved unchanged into Lucene's analysis module and branch_4x, LUCENE-2510)",
   "first_affected_version": "Lucene 4.0.0-BETA [exec] (pre-release, tagged 2012-08-10; first GA release 4.0.0 [exec]); 4.0.0-ALPHA and earlier have the filter but not the factory [exec]; Solr 1.4.0 to 4.0.0-ALPHA shipped the same code as org.apache.solr.analysis.DelimitedPayloadTokenFilterFactory [read]",
   "affected_versions": "Every Lucene release from 4.0.0-BETA through 10.6.0 (10.6.0 by reading), and main a9779ef3c193; never fixed. [exec] the follow-up's version-portable stream check (two filters from one factory, one and two threads, controls: built-in float encoder through the factory and the custom encoder through the public constructor) is AFFECTED on 4.0.0-BETA, 4.0.0, 4.3.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main and passes with the fix shadowed; the index-level JUnit (4 threads x 5,000 documents) fails on 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea; -da on 10.5.2 and main), 4,003 to 7,116 of 20,000 documents wrong; the finder's JUnit fails 2 of 4 on main (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 3 of 5 on main (-ea and -da), 10.5.2 and 9.12.3; the security probe's facts hold on main (-ea, -da) and 10.5.2 (-da). [read] at every release tag in the history clone (lucene-solr 4.0.0-beta to 8.8.1, lucene 9.0.0 to 10.5.2) the factory has the same shape (one encoder field, set once in inform(), passed to every filter in create()); 8.8.2 to 8.11.x are not tagged in the clone (8.11.4 executed); the same factory blob is on origin/main a95c754ee00, and branch_10x and branch_10_6 carry the 10.x blob (refs fetched 2026-10-26). The 7 commits between ea57360912ed and a9779ef3c193 do not touch lucene/analysis. Built-in encoders were stateless at every point checked [read]. Runs on JDK 25.0.3, aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-598.html",
   "repro": "repro/LFV-598/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-605",
   "priority": "low",
   "priority_rank": 488,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / kuromoji romanization (ToStringUtil.getRomanization; JapaneseReadingFormFilter romaji mode)",
   "title": "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'",
   "summary": "You analyze Japanese text with JapaneseTokenizer and JapaneseReadingFormFilter(useRomaji=true), whose romanizer is documented as 'Romanize katakana with modified hepburn', and expect the small tsu ッ to double the next consonant, as the method already does for キット -> 'kitto' and マッチ -> 'matchi'. Instead the 'ッ' case appends a consonant only for the カ, サ, タ and パ rows and appends nothing otherwise, so バッグ 'bag' becomes 'bagu', the same term as バグ 'bug', ベッド becomes 'bedo' and スタッフ becomes 'sutafu'. Distinct words then match each other, and a romaji query 'baggu' finds no document that contains バッグ.",
   "impact_class": "silent wrong results",
   "introduced_commit": "cd372bdc83836148a7ae2e2958407ff0a37b7fc2 (trunk, svn r1230748, 2012-01-12, committed by GitHub rmuir: LUCENE-3305 'add Kuromoji Japanese morphological analyzer', now apache/lucene#4378, no PR) and its branch_3x copy 8c9485fb66427e54ff0dac9708fdcbe72ba62e94 (svn r1231536, 2012-01-14): they created ToStringUtil.getRomanization with the 'ッ' switch that appends only k/s/t/p [read]. The output reached indexed terms with c3ddb9dc67242b9dacbea753e28a27787d6d3305 (LUCENE-3915 / #4988, 2012-03-25, the reading form filter with useRomaji; branch_3x dd51f252c55) [read]. Not a regression: the method was born with the gap [exec]",
   "introduced_date": "2012-01-12 (romaji filter path added 2012-03-25)",
   "first_affected_version": "3.6.0 [exec], the first release with kuromoji (contrib lucene-kuromoji; there the useRomaji factory parameter is in the Solr factory, Lucene's own factory exists from 4.0.0 [read]); 3.5.0 has no kuromoji module, so no release is unaffected in the strict sense [exec]; on the trunk line 4.0.0-alpha [read] and 4.0.0 [exec]",
   "affected_versions": "every release from 3.6.0 through 10.5.2 (the last release before 10.6.0) and main a9779ef3c193. [exec] 7 of 7 loanwords lose the ッ, the filter turns バッグ into 'bagu' and the k/s/t/p controls pass on 3.6.0, 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); with the candidate fix shadowed in, the probe passes on main. [exec] the finder's JUnit fails 2/3 on main (-ea, -da), 10.5.2 and 10.0.0; the independent reproduction's JUnits fail 4/6 on main (-ea, -da) and 10.5.2 and 2/3 (filter test only) on 9.12.3. [read] releases in between were not executed; the 'ッ' block is unchanged since cd372bdc838 (git log -L) and tag containment covers them. Not fixed upstream: ToStringUtil.java is identical on ea57360912ed and a9779ef3c193, no commit after a9779ef touches lucene/analysis/kuromoji (upstream head a95c754ee00, 2026-10-26), and no open PR changes the ッ handling.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-605.html",
   "repro": "repro/LFV-605/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-850",
   "priority": "low",
   "priority_rank": 489,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / kuromoji (JapaneseCompletionFilter and JapaneseCompletionAnalyzer romanization data: the bundled table romaji_map.txt that KatakanaRomanizer reads)",
   "title": "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 ツァー",
   "summary": "You index ordinary loanwords such as チェック, イェール, ツァー, ディスク or ウォッカ with JapaneseCompletionAnalyzer and expect a user who types the usual romaji, che(kku), ye or tsa (or the IME keystrokes dhi, dhu, who), to get them as suggestions, because the analyzer lists (modified) Hepburn, Kunrei-shiki and Wapuro romanization as supported and its table already has these spellings for the sibling kana: シェ she, ジェ je, チャ cha, ティ thi, テュ thu, ウィ wi, ウェ we and even the doubled form ッイェ yye. Instead romaji_map.txt has no row for チェ, イェ, ツァ, ツィ, ツェ, ツォ, ディ, デュ or ウォ, so KatakanaRomanizer splits each into its base kana plus a small vowel (チ+ェ -> tixe/chixe, イ+ェ -> ixe, ツ+ァ -> tuxa/tsuxa, デ+ィ -> dexi, ウ+ォ -> uxo) and these raw-romaji queries suggest nothing. Queries typed in kana, including partly composed ones such as ちぇっk, still match, because the index and query sides use the same fallback.",
   "impact_class": "silent wrong results",
   "introduced_commit": "4e86df96c0385a7b552434d7e2a9bee69f18bd77 (apache/lucene#297, 'LUCENE-10102: Add JapaneseCompletionFilter for Input Method-aware auto-completion', issue #11140, by GitHub mocobeta, co-authored by rmuir; reviewers johtani and rmuir) [read] [exec]. Present since the table was written, so not a regression; the table author's 2020 precursor table (a public gist) already had the same gap",
   "introduced_date": "2021-09-17 (author date 2021-09-17T13:37:12Z; merged 2021-09-17T13:37:13Z)",
   "first_affected_version": "9.0.0 [exec] (the first release with JapaneseCompletionFilter; CHANGES lists LUCENE-10102 under 9.0.0 New Features; 8.11.4 [exec]: the repro does not compile, because the API is absent)",
   "affected_versions": "every release from 9.0.0 to 10.5.2 (33 releases), 10.6.0 (the branch_10_6 head 4ae946e5a9b) and main [exec] [read]; not applicable to 8.x and older (API absent [exec]). All runs: JDK 25.0.3, Linux aarch64, release jars SHA-1 checked",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-850.html",
   "repro": "repro/LFV-850/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-848",
   "priority": "low",
   "priority_rank": 490,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / kuromoji (JapaneseCompletionFilter and JapaneseCompletionAnalyzer romanization table romaji_map.txt, read by KatakanaRomanizer)",
   "title": "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'",
   "summary": "You index the katakana name ヨッヘン with JapaneseCompletionAnalyzer and type its romaji 'yohhen' into a suggester, and expect the name to be suggested, just as ヨッハン is suggested for 'yohhan'. Instead nothing is suggested: the table row meant for ッヘ, 'ッへ,hhe' (romaji_map.txt line 219), has the look-alike HIRAGANA LETTER HE (U+3078) in its key, and romanize() only ever receives katakana or a-z, so the row can never match and ッヘ falls back to 'ッ'->'xtu' plus 'ヘ'->'he' (indexed as 'yoxtuhen'). The same table gives ッスォ the undoubled spelling 'suxo' (line 281, the spelling of スォ) and ッドゥ the spelling 'ddoxi' (line 289, copied from ッドィ) instead of 'ssuxo' and 'ddoxu'; a three-character table edit fixes all three.",
   "impact_class": "silent wrong results",
   "introduced_commit": "4e86df96c0385a7b552434d7e2a9bee69f18bd77 (apache/lucene#297, LUCENE-10102 / GitHub issue #11140 'Add JapaneseCompletionFilter for Input Method-aware auto-completion', by GitHub mocobeta, co-authored by rmuir) [read] [exec]. Present since the file was created, so not a regression",
   "introduced_date": "2021-09-17 (merged 2021-09-17T13:37:13Z; the rows were first written in PR commit dff3942eed5, 2021-09-13)",
   "first_affected_version": "9.0.0 [exec] (the first release with JapaneseCompletionFilter; CHANGES.txt lists LUCENE-10102 under 9.0.0 New Features; no 8.x release has the completion package: 8.11.4 executed, the history harness does not compile; the 8.10.1, 8.11.0 and 8.11.4 kuromoji jars contain no completion classes and no romaji_map.txt; the parent commit de45b68c909 has no table)",
   "affected_versions": "every published release that has the filter: 10.6.0 (revision 4ae946e5a9b, below) and all 33 from 9.0.0 to 10.5.2 [exec: history harness RomajiMapMalformedRowsHistory (main(), -ea), each 'bug-present (4 defects)'; the candidate JUnit also fails on 9.1.0, 9.12.3, 10.0.0 and 10.5.2 [exec] (it does not compile on 9.0.0, whose test framework predates the org.apache.lucene.tests package; the history harness covers 9.0.0 with -ea and -da); the independent reproduction's JUnit fails on 10.5.2 and 9.12.3 [exec]; the introducing commit 4e86df96c03 [exec]; the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) [exec; its kuromoji jar compiled with javac from that commit's sources, because the cached snapshot jar set has none]; main a9779ef3c193 [exec, -ea and -da]; upstream main 20ced71c1e6 and origin/branch_10_6 carry the same table blob 8136668e708 [read]. The 9.x releases ship blob 4a803a469ad1 and the 10.x releases blob 8136668e708; they differ only in comment lines and the final newline (#12047), the data rows are identical [read, confirmed by execution]. Not applicable to 8.x and older (API absent) [exec: 8.11.4]. Negative controls: 9.0.0 with the introducing table plus the 3-line fix, and main with the fixed table, pass [exec]. All runs: OpenJDK 25.0.3, Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-848.html",
   "repro": "repro/LFV-848/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-854",
   "priority": "low",
   "priority_rank": 491,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / kuromoji completion (JapaneseCompletionFilter QUERY-mode handling of mid-IME composition; the partial-input rows of romaji_map.txt, read by KatakanaRomanizer)",
   "title": "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 ('まっｃ' while typing maccha for 抹茶, 'ばっｊ' for bajji, 'すたっｆ' 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)",
   "summary": "You build Japanese autocomplete with JapaneseCompletionAnalyzer, whose QUERY mode is documented as 'Input Method aware romanization' and joins a kana token with a still-pending romaji letter ('サッ' + 'k' => 'サッk', so 'さっｋ' keeps suggesting サッカー), and expect the same while a user types 'maccha' and the input method shows 'まっｃ'. Instead 'まっｃ' is romanized 'maxtuc' and nothing is suggested, and the same happens for 'ばっｊ' (bajji, バッジ) and 'ばっｆ' (baffa, バッファ), because the bundled romaji_map.txt has partial-input rows (small tsu plus one pending letter) only for k, g, s, z, t, d, h, b, p, m, y, r and w, although its own full rows double c, j, f and v (ッチャ ccha, ッジ jji, ッフ ffu, ッヴ vvu). The suggestions return one or two keystrokes later, when the input method converts the pending letters to kana.",
   "impact_class": "minor",
   "introduced_commit": "4e86df96c0385a7b552434d7e2a9bee69f18bd77 (LUCENE-10102 / issue #11140, PR #297, 'Add JapaneseCompletionFilter for Input Method-aware auto-completion', by GitHub mocobeta, co-authored by rmuir) [read]. Inside the PR, its first commit dff3942eed5 (2021-09-13) already had the 13 partial rows ッk..ッw next to the full rows ッチャ ccha, ッフ ffu and ッヴ vvu, and review commit fc90e452474 (2021-09-17) added jji/jja/jju/jjo to the full ッジ rows at a reviewer's request without a ッj partial row [read]. Present since the feature was written; not a regression. The only later commit to the file, 4676a735c18 (#12047, 2023), changed header comments only",
   "introduced_date": "2021-09-17 (author date 2021-09-17T13:37:12Z; merged 2021-09-17T13:37:13Z)",
   "first_affected_version": "9.0.0 [exec] (the first release with JapaneseCompletionFilter; CHANGES lists LUCENE-10102 under 9.0.0 only; on 8.10.1, 8.11.0 and 8.11.4 [exec] the probe does not compile because the completion API is absent)",
   "affected_versions": "Every release from 9.0.0 to 10.5.2 (33 releases), the branch_10_6 head 4ae946e5a9b9 (10.6.0, released 2026-10-29) and main a9779ef3c193 [exec] [read]. Not applicable to 8.x and older (API absent). No fix exists upstream. All runs: JDK 25.0.3, Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-854.html",
   "repro": "repro/LFV-854/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-607",
   "priority": "low",
   "priority_rank": 492,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-kuromoji / Japanese char filters (JapaneseIterationMarkCharFilter kana iteration marks ゝ/ヽ: isHiraganaDakuten / isKatakanaDakuten over the h2d / k2d voicing tables, used by normalizedHiragana / normalizedKatakana; JapaneseIterationMarkCharFilterFactory 'japaneseIterationMark')",
   "title": "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",
   "summary": "You put JapaneseIterationMarkCharFilter in front of an analyzer and index なゝめ, the older spelling of ななめ ('diagonal'), and expect the filter to replace the iteration mark ゝ with the repeated kana, as its javadoc promises ('normalizes ... iteration marks to their expanded form'). Instead it emits などめ, so the index holds a different word and a search for ななめ finds nothing; the same happens for 19 more kana (のゝ becomes のね, ぱゝ becomes ぱば, っゝ becomes っぢ, and the katakana forms with ヽ). The filter decides whether the preceding kana is voiced by checking whether it maps to itself in its voicing table, but the kana that have no voiced form (っ, な..の, ぱ ぴ ぷ ぺ) are stored there as self-mappings too, so it strips a dakuten they never had and emits the preceding code point.",
   "impact_class": "silent wrong results",
   "introduced_commit": "a15331043f9823eaee675f45012f93071f1e21fb (trunk, svn r1359613, 'Added JapaneseIterationMarkCharFilter (LUCENE-4201)', author cmoen) and its branch_4x backport 2f1a3e4bad811fe027c3c25f4b3206ace37ddedf (svn r1359645, same day), which the 4.x and 5.x release tags contain; no PR (the change predates GitHub; JIRA LUCENE-4201, now GitHub issue #5273). The bug came with the class, it is not a regression [read]. Later commits to the file (LUCENE-4228, LUCENE-4393, javadoc and license fixes, LUCENE-9570 reformatting, LUCENE-10352 @IgnoreRandomChains, #14228 'static final') do not touch the logic",
   "introduced_date": "2012-07-10 (trunk commit and branch_4x backport, same day)",
   "first_affected_version": "4.0.0-BETA [exec] (first GA release 4.0.0 [exec]); last unaffected: 4.0.0-ALPHA [exec]; 3.6.x and earlier never had the class [read]",
   "affected_versions": "Every release from 4.0.0-BETA through 10.6.0 (10.6.0 by reading; up to 10.5.2, 122 release tags contain the introducing commit [read]; 8.8.2 to 8.11.4 were cut from branch_8x after the repository split and are not tagged in the clone, 8.11.2 and 8.11.4 executed) and main a9779ef3c193, never fixed. [exec] the follow-up's version-neutral main() probe (public Reader constructor, default flags) gives the same wrong output for all 20 pairs, with its upstream-asserted controls correct, on 4.0.0-BETA (-ea and -da), 4.0.0, 4.1.0, 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da), and passes on main with the fix shadowed; the finder's JUnit fails 2 of 3 on main (-ea and -da), 10.5.2 and 9.12.3 and its main() variant fails on 8.11.2, 7.7.3, 5.5.5 and 4.0.0; the independent reproduction's JUnit fails 3 of 4 on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's fails 3 of 4 on main (-ea and -da) and 10.5.2. [read] the 10.5.2 class source is byte-identical to main; on upstream main (a95c754ee003, 2026-10-26), branch_10x and branch_10_6 the last commit touching the file is the 2025-02-24 #14228 'static final' change (ce50d3a135d on main, 1d55d2383ce on the branches), so 10.6.0 (released 2026-10-29) and the unreleased 11.0 line are affected (not executed). Not executed: x86 (pure Java char logic). JDK 25.0.3, aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-607.html",
   "repro": "repro/LFV-607/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-819",
   "priority": "low",
   "priority_rank": 493,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / ASCIIFoldingFilter mapping table (foldToASCII switch)",
   "title": "ASCIIFoldingFilter folds the ligature ﬆ (U+FB06) to 'st' but has no entry for its sibling ﬅ (U+FB05 LATIN SMALL LIGATURE LONG S T, NFKD 'st'), so 'faﬅ' is indexed unchanged and the ASCII query 'fast' does not find it",
   "summary": "You fold text with ASCIIFoldingFilter, whose javadoc says it converts characters 'into their ASCII equivalents, if one exists' and lists the Alphabetic Presentation Forms block, and you search in plain ASCII. You expect 'faﬅ' (with the long-s-t ligature U+FB05, whose NFKD is 'st') to be indexed as 'fast', just as 'faﬆ' (U+FB06) and 'faſt' (long s U+017F) are; instead the table has cases for U+FB00-FB04 and U+FB06 but none for U+FB05, so the character passes through unchanged, the term stays 'faﬅ' and the query 'fast' finds nothing. The fix is one case label (U+FB05 added to the U+FB06 'st' group) plus the matching row of the generated testAllFoldings array.",
   "impact_class": "minor",
   "introduced_commit": "8660ccb303f6 (LUCENE-1390 'Added ASCIIFoldingFilter ...', SVN trunk r724053, credited in CHANGES as 'Andi Vajda, Steven Rowe via Mark Miller'; JIRA issue migrated as #2464, no PR); the table was born without U+FB05 (the final patch in the JIRA archive already lacks it), and for users of the class it replaced it was a regression: ISOLatin1AccentFilter had folded U+FB05 (to 'ft') since LUCENE-1351 (dd066edcf19, 2008-08-05, first released in 2.4.0, filed under bug fixes), LUCENE-1390 deprecated that filter in favour of ASCIIFoldingFilter, whose 2.9.0-3.6.2 javadoc called its conversions 'a superset of' the old filter's, and U+FB05 is the only one of the old filter's 72 mappings that ASCIIFoldingFilter lacks [read]",
   "introduced_date": "2008-12-06 (author and committer date of 8660ccb303f6, 2008-12-06T23:25:42Z; LUCENE-1390 opened 2008-09-17, resolved 2008-12-06)",
   "first_affected_version": "2.9.0 [exec] (first release with ASCIIFoldingFilter; 2.4.1, cut from the 2.4 branch, has no such class: compile error [exec]; in 2.4.x the then-current ISOLatin1AccentFilter folded U+FB05 to 'ft' [exec])",
   "affected_versions": "every release from 2.9.0 to 10.5.2, 10.6.0 (by reading) and main a9779ef3c193. [exec] all 147 final lucene-core releases that Maven Central lists from 2.9.0 on fail (147 of 147, none skipped), with era-specific public-API main() repros: the filter over KeywordTokenizer for 2.9-3.6 and the public static foldToASCII, the table incrementToken uses, from 4.0 on; the finder's JUnit fails on 9.12.3, 10.0.0, 10.5.2 and main with -ea and on 9.12.3, 10.5.2 and main with -da (9.0.0: the test framework package does not exist yet, a harness limit); the independent reproduction's JUnit fails on 9.12.3, 10.5.2 and main; the intended-behaviour check's BMP scan fails on 3.6.2; all runs on JDK 25, Linux aarch64 only. [read] the 136 release tags of the history clone that contain the introducing commit (incl. 4.0.0-alpha/beta) have the U+FB06 case and no U+FB05 case; the upstream main head 20ced71c1e6 has the same file blob as a9779ef3c193 and the branch_10_6 head 4ae946e5a9b the same blob as 10.5.2, so 10.6.0 (released 2026-10-29) ships it.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-819.html",
   "repro": "repro/LFV-819/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-877",
   "priority": "low",
   "priority_rank": 494,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / icu (ICUFoldingFilter UTR#30 folding data: the hand-written 'Rule: verbatim' Cyrillic block of DiacriticFolding.txt, compiled into utr30.nrm)",
   "title": "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",
   "summary": "You index Abkhaz text in the older spelling 'аҧсуа' with ICUFoldingFilter, whose javadoc lists 'Diacritic removal (including stroke, hook, descender)' and which folds ҧ (U+04A7) to п, and you expect the modern spelling 'аԥсуа', written with ԥ (U+0525, the modern-orthography counterpart of U+04A7), to find it. Instead the hand-copied Cyrillic table in DiacriticFolding.txt, taken from the 2004 UTR#30 draft data for Unicode 4.0 and never extended, has no line for ԥ or for any of the other 23 hook, stroke or descender letters added in Unicode 4.1-7.0 (ӷ ӻ ӽ ӿ ԓ ԡ ԣ ꚋ ԧ ԩ ԯ and the capitals), so they are only case-folded and keep the mark, and the query finds 0 documents. All 48 older letters of the same kind lose the mark (46 fold to their base letter; ҷ/Ҷ fold to a wrong letter, the separate bug LFV-855).",
   "impact_class": "minor",
   "introduced_commit": "3599d0c60b17e395b9cd3a3f745187a5d32bb8be (svn trunk r936657, 'LUCENE-1343: Add ICUFoldingFilter, normalizes unicode text for search', issue LUCENE-1343 = #2420, by GitHub rmuir; no PR), backported to branch_3x as 534809c2eae7addcd93ede794e1e42d72a87e105 (r941694, 'LUCENE-1343: backport'), the commit that shipped in 3.1.0 [read] [exec]. Wrong from the start, so not a regression",
   "introduced_date": "2010-04-22 (trunk author date 2010-04-22T08:47:49Z; branch_3x backport 2010-05-06)",
   "first_affected_version": "3.1.0 [exec] (the first release with ICUFoldingFilter; its ICU4J 4.6 = Unicode 6.0 assigns 20 of the 24 letters; the 4 Unicode 7.0 letters U+0528/0529/052E/052F are assigned, and unfolded, from 5.0.0 with ICU4J 54.1, before which they were unassigned code points that pass through unchanged anyway; 3.0.3 [exec]: API absent, no lucene-icu artifact on Maven Central)",
   "affected_versions": "every release from 3.1.0 to 10.5.2, 10.6.0 (by reading) and main a9779ef3c193 [exec] [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-877.html",
   "repro": "repro/LFV-877/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-688",
   "priority": "low",
   "priority_rank": 495,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-common / es (SpanishPluralStemmer special-case list, SpanishPluralStemFilter)",
   "title": "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",
   "summary": "You stem Spanish text with SpanishPluralStemFilter, which CHANGES describes as 'precise stemming of Spanish plurals', and expect the plural 'contrarrelojes' to reduce to 'contrarreloj' and the singular 'contrarreloj' to stay as it is, as 'relojes' -> 'reloj' and 'bojes' -> 'boj' do. Instead the singular becomes 'contrarrel' and the plural 'contrarreloje', so a document containing 'contrarrelojes' is not found by the query 'contrarreloj'. The cause is one entry of the hand-written special-case list (SpanishPluralStemmer.java:163): the 12 other entries are plurals in -es whose last two letters stem() removes (:173, 'return len - 2'), but this entry is the singular, and the missing plural falls through to the generic 'remove the final s' rule (:222-224).",
   "impact_class": "silent wrong results",
   "introduced_commit": "edb936f09055cc16a71b5b037bef77177786759b (main, 'LUCENE-10248: Spanish Plural Stemmer (#461)', by xaviersanchez, merged by rmuir on 2021-11-30; issue #11284 / LUCENE-10248, PR #461): the commit that added the class already has 'contrarreloj' in specialCasesList (the entry is in the PR's first commit 16a383f090c, 2021-10-07; the PR commit 176bd5a6eb7 only reflowed the list); the branch_9x backport 0293fc896dc0adf915c76aba9ebf6901d07adf9d (same day) put it into 9.1.0. Not a regression: the entry is as old as the API. Later commits to the file (a26ea57ec74 #508 invariants dedup, 694d797526a #883 visibility, 54283150a81 #16255 variable rename) leave the list untouched [read]",
   "introduced_date": "2021-11-30 (main edb936f0905 and branch_9x backport 0293fc896dc, same day)",
   "first_affected_version": "9.1.0 [exec] (tagged 2022-03-16; the first release with SpanishPluralStemFilter, SpanishPluralStemFilterFactory and SpanishPluralStemmer). There is no last unaffected release with the API: 9.0.0 has no such class [exec] because it was released from branch_9_0, which never got the backport [read].",
   "affected_versions": "Every release that has the class, 9.1.0 to 10.5.2 (32 releases: 9.1.0, 9.2.0, 9.3.0, 9.4.0-9.4.2, 9.5.0, 9.6.0, 9.7.0, 9.8.0, 9.9.0-9.9.2, 9.10.0, 9.11.0-9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2) [exec], and main a9779ef3c193 [exec]; the independent reproduction's own test also fails on 10.5.2, 9.12.3 and 9.1.0 [exec]; not fixed: upstream main a95c754ee003 (2026-10-26) still lists 'contrarreloj' at SpanishPluralStemmer.java:163 [read], so 10.6.0, released on 2026-10-29, very likely carries it too [inference]; not affected: 9.0.0 and older (no class) [exec].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/11284",
    "https://issues.apache.org/jira/browse/LUCENE-10248",
    "https://github.com/apache/lucene/issues/461",
    "https://github.com/apache/lucene/issues/11309",
    "https://github.com/apache/lucene/issues/497",
    "https://github.com/apache/lucene/issues/508"
   ],
   "doc": "",
   "repro": "repro/LFV-688/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-669",
   "priority": "low",
   "priority_rank": 496,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / Telugu normalizer (TeluguNormalizer.normalize; TeluguNormalizationFilter and the 'teluguNormalization' factory)",
   "title": "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",
   "summary": "You analyze Telugu text with TeluguNormalizationFilter (or the 'teluguNormalization' factory) without IndicNormalizationFilter in front of it, as in the factory javadoc example. The normalizer folds the letter AU (ఔ, U+0C14) to OO (ఓ, U+0C13), a rule the upstream test pins, and it also recognizes the two-character spelling ఒ + ౌ (U+0C12 U+0C4C) as AU, so both spellings of a word such as ఔషధం ('medicine') should give the same term. Instead the composition writes AU at a position that the single left-to-right pass never visits again, so ఒౌషధం keeps AU (term ఔషధం) while ఔషధం becomes ఓషధం, and the two spellings silently stop matching each other.",
   "impact_class": "minor",
   "introduced_commit": "544dbbea46878b49be5c4c4e82d9b06a5679c891 (LUCENE-10083 'Analyzer and stemmer for Telugu language', apache/lucene PR #275, issue #11121, squash-merged on 2021-09-02; backported to branch_8x as lucene-solr 114c9dff46c) [read]: the file's first commit, so both rules arrive together and no version ever had them consistent. Inside PR #275 the composition to U+0C14 was already in the first commit c143ef618e (2021-08-13), and commit 6c0c09933f 'added long to short vowel conversion' (2021-09-01) added the AU -> OO fold in the same single-pass switch without changing the composition (in that commit the e + ai composition result was corrected, the AU one was not); that this was an oversight is an inference from the commit sequence, no record says so. Not a regression: the later commits on the file (694d797526a LUCENE-10561 visibility, f99deb58b74 #13661 formatting, 54283150a81 #16255 a comment typo) do not change behaviour.",
   "introduced_date": "2021-09-02 (squash-merged on main and backported to branch_8x the same day; first released in 8.10.0)",
   "first_affected_version": "8.10.0 [exec] (the first release with the org.apache.lucene.analysis.te package; the follow-up's history repro fails there, and the independent reproduction's JUnit fails there too). 8.9.0, the last release before it, has no Telugu analysis API [exec]. On the main line the first affected release is 9.0.0.",
   "affected_versions": "Every release that ships the Telugu analysis API, 8.10.0 through 10.5.2, and main a9779ef3c193; not fixed. [exec] the follow-up's version-independent public-API main() (TeluguNormalizationFilter, and CustomAnalyzer standard + teluguNormalization) fails on 8.10.0, 8.10.1, 8.11.0, 8.11.4, 9.0.0, 9.9.2, 9.10.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da), and passes on main with the fix shadowed; the finder's JUnit fails 3 of 4 on main (-ea and -da), 10.5.2 and 9.12.3 (it needs org.apache.lucene.tests.analysis, so it does not compile on 9.0.0); the independent reproduction's JUnit fails 3 of 7 on main (-ea and -da), 10.5.2, 9.12.3, 8.11.4 and 8.10.0; the intended-behaviour check's fails 3 of 8 on main, 10.5.2, 9.12.3 and 9.10.0 and 4 of 8 on 9.9.2. The stock TeluguAnalyzer token stream is unaffected on every version (IndicNormalizationFilter composes the pair first); its normalize() path (multi-term query terms) was affected in 8.10.0-9.9.x [exec] until GITHUB#13059 (9.10.0) stopped it from discarding IndicNormalizationFilter. [read] upstream main a95c754ee003 (2026-10-26) and branch_10x still write U+0C14 at TeluguNormalizer.java:104 (read 2026-10-27).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-669.html",
   "repro": "repro/LFV-669/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-459",
   "priority": "low",
   "priority_rank": 497,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / kuromoji and nori Viterbi unknown-word length cap (JapaneseTokenizer and the 'japanese' factory; KoreanTokenizer, KoreanAnalyzer and the 'korean' factory)",
   "title": "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",
   "summary": "You analyze a long run of text that kuromoji or nori treat as one unknown word, for example 1,200 chars of Thai without spaces through the 'japanese' tokenizer, or 400 x (U+1F441 U+FE0F) emoji through the default KoreanAnalyzer, and the run holds an emoji or a rare ideograph such as U+20000; you expect every term to consist of whole characters, as it does when that character sits one position earlier or later. Instead both tokenizers stop the unknown word at exactly 1024 UTF-16 chars without checking for a surrogate pair, so when the character's first half is char 1023, term 0 ends in a lone high surrogate and term 1 starts with the lone low surrogate. The index silently stores both halves as U+FFFD, and in the unigram modes a TermQuery for the character finds 0 documents instead of 1.",
   "impact_class": "silent wrong results",
   "introduced_commit": "430365f7cce48e54b3d92cbf427d4b93a0b2bccb (trunk, svn r1296805; LUCENE-3767 / GitHub #4840, commit 'Kuromoji now produces both compound words and the segmentation of those words in search mode'; CHANGES credit Robert Muir, Mike McCandless via Christian Moen; pre-GitHub, no PR), which added MAX_UNKNOWN_WORD_LENGTH = 1024 ('For safety') and the unknown-word loop without a surrogate check to the kuromoji tokenizer, and its branch_3x backport e7ab11a9ddf4e89705aab7daf4186f58f17e4a44 (svn r1299213), which shipped in 3.6.0; for KoreanTokenizer, e851b89cbeb1f55edc0f2c1276e2ae812eca2643 (master, LUCENE-8231, nori added with the loop copied from kuromoji) and its branch_7x copy 8651fbaa8bc65fdfec397ad4e7ebe2b5acf78d7b, which shipped in 7.4.0 [read]",
   "introduced_date": "2012-03-04 (trunk commit); 2012-03-10 (branch_3x backport); 2018-04-13 (nori copy, master and branch_7x)",
   "first_affected_version": "3.6.0 [exec] for JapaneseTokenizer (kuromoji's first release; 3.5.0 has no kuromoji [exec]); 7.4.0 [exec] for KoreanTokenizer and KoreanAnalyzer (nori's first release; 7.3.1 has no nori [exec])",
   "affected_versions": "JapaneseTokenizer: every release from 3.6.0 to 10.5.2, 10.6.0 (by reading, see the end) and main ea57360912ed (unreleased 11.0): a public-API main() probe is affected on 3.6.0, 3.6.2, 4.0.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.3.1, 7.4.0, 7.6.0, 7.7.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (8 of 8 bug checks, controls clean) [exec]. KoreanTokenizer and KoreanAnalyzer: every release from 7.4.0 to 10.5.2 and main: the probe is affected on 7.4.0, 7.6.0, 7.7.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main [exec]; 7.4.0-7.6.0 also split pairs in Thai runs, while from 7.7.0 (LUCENE-8548, Unicode-script grouping) only the emoji + U+FE0F run triggers. The finder's JUnit fails 5 of 6 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (main with -ea and -da) [exec]; the independent reproduction's JUnit fails 8 of 12 on main (-ea and -da), 10.5.2 and 9.12.3 [exec]. Releases not run are inferred from the code: every change to the loop between releases (LUCENE-3940 in 3.6.1/4.0.0, LUCENE-8548 in 7.7.0, LUCENE-8966 in 8.3.0, LUCENE-10493 in 10.0.0) is bracketed by executed versions, and none added a surrogate check [read]. Not affected: 3.5.0 (no kuromoji) and, for nori, 7.3.1 (no nori) [exec]. Not fixed upstream: the loops are unchanged on upstream main 49483e82b357 and branch_10x as of 2026-10-26 [read]; at the 10.6.0 tag commit 4ae946e5a9b the files with the loops (ja/ViterbiNBest.java, ko/Viterbi.java) are identical to main ea57360912ed [read], so the released 10.6.0 is affected.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-459.html",
   "repro": "repro/LFV-459/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-749",
   "priority": "low",
   "priority_rank": 498,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / kuromoji and nori Viterbi tokenizers, discardPunctuation (ja.ViterbiNBest.isPunctuation and its three discard sites, ko.Viterbi.shouldFilterToken)",
   "title": "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)",
   "summary": "You tokenize '日本 😀 日本' or '한국 𐄀 한국' (U+1F600, U+10100) with JapaneseTokenizer or KoreanTokenizer and discardPunctuation=true, the default, and expect [日本, 日本] and [한국, 한국], because the javadoc says punctuation tokens are dropped and both tokenizers drop every BMP character of the same Unicode general category (Po U+3001, So U+2605, Sm U+2207). Instead the supplementary character is kept as a token ([日本, 😀, 日本], [한국, 𐄀, 한국]): isPunctuation(char) calls Character.getType on the high surrogate alone, whose type is SURROGATE, so the discard test at the token start never sees the real category. No error is raised; the default KoreanAnalyzer indexes the extra token, and the default JapaneseAnalyzer removes it only later, through its part-of-speech stop filter, which leaves a position gap.",
   "impact_class": "silent wrong results",
   "introduced_commit": "6d830c7da67373339589c60f0222041c1dccb2b8 (LUCENE-3305 development branch, 2012-01-10, by rmuir: 'option omit punctuation', which added the char-wise isPunctuation(char ch) test on the token's first UTF-16 unit), landed on trunk as cd372bdc8383 (2012-01-12) and on branch_3x as 8c9485fb6642 (2012-01-14); kept in the released streaming design by LUCENE-3767 (trunk 430365f7cce4, branch_3x e7ab11a9ddf4, 2012-03), which wrote the backtrace and EXTENDED-unigram checks on fragment[offset] / fragment[offset + i], and copied into the n-best path by LUCENE-6837 (df9c6a835f65, 2015-12-03). For KoreanTokenizer: e851b89cbeb1 (LUCENE-8231, 2018-04-13, by jimczi; branch_7x 8651fbaa8bc6), which copied the predicate into shouldFilterToken, wrapped by the documented option in a556925eb8aa (LUCENE-8784, 2019-05-24). c89f8a7ea1e7 (LUCENE-10493, PR #805, 2022-04-25) moved the code unchanged into ja/ViterbiNBest.java and ko/Viterbi.java [read]. No pull request exists for either introduction (JIRA patch and SVN era). Not a regression: the predicate has classified one UTF-16 unit since its first version.",
   "introduced_date": "2012-01-10 (kuromoji, development branch; trunk 2012-01-12, branch_3x 2012-01-14); 2018-04-13 (nori)",
   "first_affected_version": "3.6.0 for JapaneseTokenizer (tagged 2012-04-11) [exec]; 6.0.0 for its n-best path [exec]; 7.4.0 for KoreanTokenizer (tagged 2018-06-22) [exec], whose documented discardPunctuation option exists from 8.2.0 (7.4.0-8.1.1 always dropped punctuation, with the same plane-dependent result). 3.5.0 and 7.3.1 have no kuromoji or nori artifact [exec], so no release with either tokenizer is unaffected",
   "affected_versions": "every release with kuromoji (3.6.0 through 10.6.0) or nori (7.4.0 through 10.6.0), 10.6.0 by reading, and main a9779ef3c193 (unreleased 11.0); never fixed. [exec] test-framework-free main() probes ('X c X' for four BMP/supplementary pairs of the same general category, U+3001/U+10100 Po, U+FF01/U+1E95E Po, U+2605/U+1F600 So, U+2207/U+1D6C1 Sm; the BMP control was dropped in every run) report the bug for JapaneseTokenizer (NORMAL, SEARCH, EXTENDED) on 3.6.0, 3.6.2, 4.0.0, 4.10.4, 5.0.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); for its n-best path (setNBestCost(2000)) on 6.0.0, 9.12.3, 10.0.0, 10.5.2 and main; and for KoreanTokenizer() on 7.4.0, 8.1.1, 8.2.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); on main with the candidate's full fix shadowed every probe passes. The finder's JUnit fails 3 of 4 on main (-ea and -da), 10.5.2 and 9.12.3 (it does not compile on 9.0.0 because the test framework moved packages); the independent reproduction's JUnit fails 3 of 8 on main (-ea and -da), 10.5.2 and 9.12.3. [read] every other release tag from 3.6.0 to 10.5.2 in the history clone has the same char-wise isPunctuation(char ch) and no code-point variant (8.8.2-8.11.3 are not tagged there; 8.11.4 was executed); upstream main f7bcc0abd816 (2026-10-27), branch_10x and branch_10_6 are unchanged. All runs with JDK 25 on aarch64; the defect does not depend on the JDK's Unicode version, since a surrogate unit has type SURROGATE on every JDK (U+10100 is Po since Unicode 4.0).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-749.html",
   "repro": "repro/LFV-749/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-720",
   "priority": "low",
   "priority_rank": 499,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / ICU (DefaultICUTokenizerConfig syllable rules MyanmarSyllable.rbbi / MyanmarSyllable.brk, used for Myanmar text when myanmarAsWords=false; ICUTokenizerFactory 'icu' with myanmarAsWords=\"false\")",
   "title": "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",
   "summary": "You tokenize Myanmar-script text with ICUTokenizer in syllable mode (new DefaultICUTokenizerConfig(true, false), or ICUTokenizerFactory with myanmarAsWords=\"false\"), whose only documented effect is that Myanmar text 'will be tokenized as syllables', and expect every letter to end up in some token, as in the default mode, where 'ကꧦ' (KA + U+A9E6 MYANMAR MODIFIER LETTER SHAN REDUPLICATION) gives [ကꧦ] and 'ကꩰ' (KA + U+AA70 MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION) gives [ကꩰ]. Instead syllable mode gives [က] for both, a mark on its own gives no token, and 'ကောင်း µm' gives [ကောင်း, m] (the space and µ are Common script, so the script iterator keeps them in the Myanmar run), all without an error. The cause is the rule file: MyanmarSyllable.rbbi gives a non-zero rule status only to syllables built on a consonant, consonant placeholder or independent vowel ({200}) and to numbers ({100}), and ICUTokenizer skips every segment with status 0.",
   "impact_class": "silent wrong results",
   "introduced_commit": "5d88b242057177410a90a2ea74b07d6e25b4ac84 (branch_6x, first released in 6.2.0); the same change on master is 58f0fbd3767af649da1d47ea62f6f35b1ae28c19 (first released in 7.0.0). LUCENE-7393 = GitHub #8446 'restore old myanmar syllable tokenization as an option', by rmuir, committed from a JIRA patch with no pull request. It added the option and restored, unchanged apart from whitespace, the Myanmar.rbbi rules of LUCENE-2414 (5abbf3429cf, 2010, first in 3.1), which were the default Myanmar tokenization in 3.1-4.10.4 and dropped the same letters until LUCENE-5995 (7a50635bc4c, 5.0) removed them. #13239 (54a2e11434d / 56d4578b253, 9.11.0) redefined $Cons through Indic_Syllabic_Category and left the outcome unchanged, because U+A9E6 and U+AA70 are gc=Lm and ISC=Other. Not a regression of the option [read]",
   "introduced_date": "2016-07-28 (5d88b242057 and 58f0fbd3767; the 6.2.0 tag commit is dated 2016-08-20)",
   "first_affected_version": "6.2.0 [exec] (the first release with myanmarAsWords; 6.1.0 [exec] has no DefaultICUTokenizerConfig(boolean, boolean) constructor and its factory rejects myanmarAsWords=false as an unknown parameter)",
   "affected_versions": "Every release from 6.2.0 through 10.5.2 and main a9779ef3c193 (unreleased 11.0) [exec]. By reading, the rule file has two versions with the same status rules, the original (6.2.0-9.10.0) and the #13239 rewrite (9.11.0-10.5.2), and both were executed. Precursor on a different API path: the same rules were the default Myanmar tokenization in 3.1 through 4.10.4 and drop U+AA70 and MICRO SIGN the same way [exec]; 5.0.0 to 6.1.0 have neither the rules nor the option [exec]. Not fixed: the two upstream main commits after a9779ef3c193 (a95c754ee003, ffa9d816eeb4) touch no analysis-icu file, and no open PR changes the rule file (only #16911, which deletes branch_10x) [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-720.html",
   "repro": "repro/LFV-720/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-738",
   "priority": "low",
   "priority_rank": 500,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / UAX29URLEmailTokenizer JFlex URL rules (FTPurl production; analysis-common)",
   "title": "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",
   "summary": "You run text such as 'get it from ftp://ftp.example.com today' or 'ftp://localhost' through UAX29URLEmailTokenizer, whose javadoc says URLs are 'tokenized according to the relevant RFCs', and expect each ftp URL as one <URL> token, because RFC 1738 (section 3.2.2: 'The whole url-path may be omitted, including the \"/\" delimiting it') and RFC 3986 (an empty path after an authority) allow it, and the same tokenizer already keeps 'http://localhost' whole. Instead it emits 'ftp' as <ALPHANUM> followed by the rest on its own ('ftp.example.com' as <URL>, 'localhost' as <ALPHANUM>, '192.0.2.10' as <NUM>, '//anonymous@ftp.example.org' as <EMAIL>), because the grammar's FTPurl rule makes the '/'-led FTPorFILEpath mandatory while the http rule beside it makes its path optional. With a trailing slash ('ftp://ftp.example.com/') the URL is one token, and nothing reports an error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "3c26a9167cc3a4f5d338e9b74d0af61d6de9d773 (LUCENE-2167 'Implement StandardTokenizer with the UAX#29 Standard', apache/lucene#3243; trunk svn r1002032 by sarowe, Subversion era, no pull request; branch_3x backport ec0e73cd04f940d6caf8308207577313e78a9009, svn r1002468, 2010-09-29, the copy that first shipped): it added FTPorFILEpath = \"/\" {FTPorFILEsegment} ... and FTPurl = {FTPscheme} {URIauthorityLoose} {FTPorFILEpath} {FTPtype}? {URIfragment}?, while HTTPurlFull already had {HTTPpath}?; LUCENE-2763 (apache/lucene#3837; trunk 2b9726ae8169, branch_3x 543849ca43fd, 2010-12-07) moved the URL and e-mail grammar unchanged into the new UAX29URLEmailTokenizer before any release. Not a regression: the FTPurl and FTPorFILEpath lines are byte-identical in all 13 commits that add or remove them (back-compat copies, moves, deletions) [read]",
   "introduced_date": "2010-09-28 (trunk; branch_3x backport 2010-09-29; first release 3.1.0, tag dated 2011-03-30)",
   "first_affected_version": "3.1.0 [exec] (the first release with UAX29URLEmailTokenizer; the follow-up's version-portable probe fails 3 of 3 bug cases with 3 of 3 controls passing on it; 3.0.3, the release before, has no UAX29URLEmailTokenizer class and its StandardTokenizer has no <URL> type [exec])",
   "affected_versions": "Every release that has UAX29URLEmailTokenizer, 3.1.0 through 10.5.2 and 10.6.0 (by reading), including 9.12.3 (latest 9.x), and main a9779ef3c193 (unreleased 11.0); never fixed. [exec] The follow-up's version-portable reflection probe (3 bug cases: 'ftp://ftp.example.com', 'ftp://localhost' and the host inside a sentence; 3 controls: an ftp URL with '/', 'http://localhost' and the sentence with '/') fails 3 of 3 with 3 of 3 controls passing on stock, SHA-1-checked jars of all 138 releases 3.1.0-3.6.2, 4.0.0-4.10.4, 5.0.0-5.5.5, 6.0.0-6.6.6, 7.0.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3 and 10.0.0-10.5.2, and on main with -ea and -da; the finder's JUnit fails 2 of 4 (both controls pass) on 9.1.0, 9.12.3, 10.5.2 and main (-ea and -da; it does not compile on 9.0.0 and older because of the test-framework package change); the independent reproduction's test fails 6 of 11 (all 5 controls pass) on main (-ea, -da), 10.5.2 (-ea, -da) and 9.12.3 (-ea). One secondary detail varies: in 4.7.0-7.3.1 a bare 'ftp://ftp.example.com' at the end of the input leaves the host typed <ALPHANUM> rather than <URL> (LUCENE-8278, a different issue fixed in 7.4.0); no version emits one <URL> token. [read] The FTPurl line is byte-identical on main, branch_10x and branch_10_6 and at upstream main a95c754ee003 (2026-10-26). All runs with JDK 25 on aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-738.html",
   "repro": "repro/LFV-738/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-895",
   "priority": "low",
   "priority_rank": 501,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / util CSVUtil (CSV line parsing for the kuromoji user dictionary and the kuromoji/nori dictionary builders)",
   "title": "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",
   "summary": "You parse a CSV line whose last field is quoted, for example CSVUtil.parse(\"x,\" + CSVUtil.quoteEscape(\"To be, or not to be\")), or load a kuromoji user dictionary written with every field quoted, and expect the quoted value to be decoded the same way as in any other position, as parse does for every field followed by a comma. Instead the last field comes back raw, enclosing quotes and doubled inner quotes included: parse(\"\\\"a,b\\\",\\\"c,d\\\"\") returns [a,b, \"c,d\"], and the dictionary line \"abcd\",\"a b cd\",\"foo1 foo2 foo3\",\"bar\" yields tokens whose part-of-speech is \"bar\" with the quotes. The cause is one line: parse passes each comma-terminated field through unQuoteUnEscape (CSVUtil.java:56) but adds the final field as sb.toString() (:65).",
   "impact_class": "silent wrong results",
   "introduced_commit": "cd372bdc8383 (LUCENE-3305 'add Kuromoji Japanese morphological analyzer', committed by rmuir from the Kuromoji code donation, migrated as apache/lucene#4378; svn trunk r1230748, svn era with no GitHub PR; branch_3x backport 8c9485fb6642, r1231536; first in the repository on the svn feature branch lucene3305 as bee8224c049c, which is not an ancestor of main) [read]",
   "introduced_date": "2012-01-12 (trunk commit cd372bdc8383, author date = commit date, svn era); 2012-01-14 (branch_3x backport 8c9485fb6642); 2012-01-03 (feature branch bee8224c049c)",
   "first_affected_version": "3.6.0 [exec] (first release with CSVUtil, then org.apache.lucene.analysis.ja.util.CSVUtil in the kuromoji module; 3.5.0 [exec] has no CSVUtil and no kuromoji module, so there is no earlier unaffected release; on the trunk line 4.0.0-alpha, 4.0.0 executed)",
   "affected_versions": "every release from 3.6.0 to 10.5.2, branch_10_6 4ae946e5a9b9 (10.6.0, released 2026-10-29) and main a9779ef3c193; not fixed upstream. [read] all 126 release tags 3.6.0-10.5.2 in the full-history clone carry the unfixed line in every CSVUtil copy (8.9.0-8.11.4 are not tagged there; 8.11.4 was executed from release jars); upstream main c5ab3e57b9ba, branch_10x and branch_10_6 still have it (the last CSVUtil.java commit is #16056, author date = commit date 2026-05-14). [exec] the follow-up's portable main() probes (CSVUtil: 4 of 4 bug checks keep the quotes on the last field, 2 controls pass; kuromoji: an all-quoted user-dictionary line gives the part-of-speech \"bar\" with quotes on every token, the unquoted control gives bar) fail on 3.6.0, 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.4.0, 7.7.3, 8.11.4, 9.0.0, 9.8.0, 9.9.0, 9.12.3, 10.0.0, 10.5.2, branch_10_6 (CSVUtil only) and main, and pass with the fix shadowed on main; from 7.4.0 to 9.8.0 the nori copy org.apache.lucene.analysis.ko.util.CSVUtil (used only by nori's dictionary builders) fails its 3 checks too. The finder's JUnits fail on main (-ea and -da), branch_10_6, 10.5.2, 10.0.0, 9.12.3 and 9.9.0 (they do not compile on 8.11.4, which predates the analysis.util package and the tests.* framework); the independent reproduction's fail on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's on main (-ea and -da) and 10.5.2. The class lived in kuromoji (ja.util) for 3.6.0-9.8.0 and in analysis-common (org.apache.lucene.analysis.util) from 9.9.0 (#12390/#12774), each move carrying the line unchanged.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-895.html",
   "repro": "repro/LFV-895/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-889",
   "priority": "low",
   "priority_rank": 502,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-common / util CSVUtil (CSV line parsing for the kuromoji user dictionary and the kuromoji/nori dictionary builders)",
   "title": "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",
   "summary": "You encode a value that holds both a comma and a double quote with CSVUtil.quoteEscape, which doubles the quotes and wraps the value in quotes (the exact output Lucene's own TestCSVUtil.testQuoteEscapeQuotesAndComma expects), put it before another field in a CSV line, and expect CSVUtil.parse to give the value back, as it does for values with only a comma or only a quote. Instead parse unescapes the inner quotes but keeps the enclosing ones: the value a \"b\", c is encoded as \"a \"\"b\"\", c\" and parse returns \"a \"b\", c\" with the outer quotes still on it. The cause is the unquote regex ^\"([^\"]+)\"$ (CSVUtil.java:29), which strips enclosing quotes only from a field that has no quote inside.",
   "impact_class": "silent wrong results",
   "introduced_commit": "cd372bdc8383 (LUCENE-3305 'add Kuromoji Japanese morphological analyzer', committed by rmuir from the Kuromoji code donation, apache/lucene#4378; svn trunk r1230748, svn era with no GitHub PR; branch_3x backport 8c9485fb6642; first in the repository on the svn feature branch lucene3305 as bee8224c049c) [read]",
   "introduced_date": "2012-01-12 (trunk commit cd372bdc8383, author date = commit date, svn era); 2012-01-14 (branch_3x backport 8c9485fb6642); 2012-01-03 (feature branch bee8224c049c)",
   "first_affected_version": "3.6.0 [exec] (first release with CSVUtil, then org.apache.lucene.analysis.ja.util.CSVUtil in the kuromoji module; 3.5.0 [exec] has no CSVUtil; on the trunk line 4.0.0-alpha, 4.0.0 executed)",
   "affected_versions": "every release from 3.6.0 to 10.6.0 (10.6.0 executed as the branch_10_6 head 4ae946e5a9b9), branch_10x and main. [read] 124 release tags in the full-history clone contain the regex. [exec] the follow-up's version-independent probe (loads CSVUtil by reflection from whichever package the release uses) fails on all 60 releases executed from 3.6.0 to 10.5.2 with its plain, comma-only and quote-only controls passing, and on main a9779ef3c193; 8.8.2, 8.10.0, 8.11.1 and 8.11.3 are inferred from executed neighbours. JUnit runs fail on main a9779ef3c193 (-ea and -da), the branch_10_6 head 4ae946e5a9b9, 10.5.2, 9.12.3 and 9.9.0, and the independent reproduction ran the pre-move class on 9.8.0 and 8.11.4 (fail). The class lived in kuromoji (org.apache.lucene.analysis.ja.util) for 3.6.0-9.8.0, a copy without quoteEscape in nori (ko/util) for 7.4.0-9.8.0, and analysis-common (org.apache.lucene.analysis.util) from 9.9.0. In 3.6.0-6.1.x quoteEscape also failed to double quotes (fixed by SOLR-9413 in 6.2.0), so the round trip failed for two reasons; from 6.2.0 the parser alone causes it. Upstream origin/main c5ab3e57b9ba, branch_10x and branch_10_6 carry the same CSVUtil blob (unfixed).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/6913",
    "https://issues.apache.org/jira/browse/LUCENE-5851",
    "https://github.com/apache/lucene/issues/6569",
    "https://issues.apache.org/jira/browse/LUCENE-5506",
    "https://github.com/apache/lucene/issues/4770",
    "https://issues.apache.org/jira/browse/LUCENE-3696"
   ],
   "doc": "",
   "repro": "repro/LFV-889/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-712",
   "priority": "low",
   "priority_rank": 503,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / kuromoji system dictionary builder (ja.dict.TokenInfoDictionaryEntryWriter reading and pronunciation length bytes; TokenInfoMorphData decoding; custom dictionaries built with DictionaryBuilder)",
   "title": "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)",
   "summary": "You build a custom kuromoji system dictionary with DictionaryBuilder from an IPADIC-format CSV that has a row whose reading is 128 katakana chars long (or, more naturally, a 64-char proper noun with a 136-char reading), and you expect either an IllegalArgumentException at build time, as the builder throws for a stored base form of 16 or more chars that its compact format cannot hold, or the reading back unchanged. Instead the build succeeds, because putEntry writes each length as (byte) (length << 1 | kanaFlag) with no check, so the stored length is the real length mod 128: getReading and JapaneseTokenizer's ReadingAttribute return \"\" for the 128-char reading and only the first 8 chars of the 136-char one, a 128-char pronunciation comes back empty, a pronunciation stored after a wrapped reading is decoded from the reading's own bytes (a 4-char pronunciation came back as the single char U+0304), and JapaneseReadingFormFilter indexes the empty or truncated reading as the term.",
   "impact_class": "silent wrong results",
   "introduced_commit": "cd372bdc8383 (svn r1230748, trunk, 2012-01-12, LUCENE-3305 'add Kuromoji Japanese morphological analyzer', GitHub #4378, by rmuir; Subversion era, no pull request), the squash-merge of the lucene3305 development branch, where the 1-byte reading/pronunciation length header was written in 63700e75cb3a (svn r1228000, 2012-01-06, 'more efficient tokeninfodictionary', replacing a 16-bit total feature-size field); its branch_3x backport 8c9485fb6642 (svn r1231536, 2012-01-14) is the commit in 3.6.0 [read]. Not a regression: the reading and pronunciation lengths never had an assert or a check (the original import had 'assert baseForm.length() < 128' for the base form only); LUCENE-8863 (4502065f0365 on main, bdaf10ffa826 on branch_8x, in 8.2.0) turned only the base-form and id asserts into IllegalArgumentException, and LUCENE-10393 (bd22f199dec5, #740) moved the lines unchanged into TokenInfoDictionaryEntryWriter",
   "introduced_date": "2012-01-12 (trunk cd372bdc8383; the development-branch commit 63700e75cb3a is from 2012-01-06 and the branch_3x commit 8c9485fb6642 that shipped in 3.6.0 from 2012-01-14)",
   "first_affected_version": "3.6.0 [exec] (first release with Kuromoji; 3.5.0 has none). From 3.6.0 to 8.1.1 the builder shipped only as a build tool in the source release (not in the jar [exec]); 8.2.0 [exec] is the first release with DictionaryBuilder as public API in the kuromoji jar (LUCENE-8871)",
   "affected_versions": "Every release from 3.6.0 through 10.5.2, and main a9779ef3c193 (unreleased 11.0); never fixed. [exec] 3.6.0 and 8.1.1 (builder tool compiled from the release source, dictionary on the classpath), 8.2.0, 8.11.4 and 9.0.0 (public DictionaryBuilder, classpath), 9.12.3 (9.x JUnit variant), 10.0.0, 10.5.2 and main (-ea and -da): all fail the same way (a 128-char reading comes back as \"\"), and the 127-char controls round-trip. [read] 4.x-7.x not executed; the encoding lines are unchanged (blame -M -C -C, log -G). Upstream main a95c754ee003 and branch_10x still have the unchecked lines (read 2026-10-27).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-712.html",
   "repro": "repro/LFV-712/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-717",
   "priority": "low",
   "priority_rank": 504,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / nori system dictionary builder (DictionaryBuilder, TokenInfoDictionaryEntryWriter; custom system dictionaries)",
   "title": "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",
   "summary": "You compile a custom nori system dictionary with DictionaryBuilder from MeCab-format rows in which the noun 가 (NNG) and the particle 는 (JX) share left context id 1, and expect the builder either to reject the source (the compiled format keeps only one part of speech per left id, and kuromoji's builder throws 'Multiple entries found for leftID' for the same case) or each word to keep its own part of speech. Instead, with assertions off, the builder overwrites the single slot for left id 1 with the part of speech of the row it writes last, because the only check is an assert (TokenInfoDictionaryEntryWriter.java:100): 가 then reports left POS JX, and KoreanTokenizer followed by KoreanPartOfSpeechStopFilter with DEFAULT_STOP_TAGS returns no token instead of [가]. With -ea the build fails with a bare AssertionError rather than an IllegalArgumentException that names the problem.",
   "impact_class": "silent wrong results",
   "introduced_commit": "e851b89cbeb1f55edc0f2c1276e2ae812eca2643 (LUCENE-8231 'Nori, a Korean analyzer based on mecab-ko-dic', by jimczi; JIRA patch workflow, no pull request; the issue is now apache/lucene#9278) and its same-day branch_7x backport 8651fbaa8bc65fdfec397ad4e7ebe2b5acf78d7b, which shipped in 7.4.0 [read]. Not a regression: the assert-only check dates from the module's first commit",
   "introduced_date": "2018-04-13",
   "first_affected_version": "7.4.0 [exec] (nori's first release; 7.3.1 has no nori module [exec]). Reach by version: 7.4.0-8.2.0 ship the builder only as source (src/tools), and the documented ant build-dict target ran it with assertions on, so on that path a collision failed with AssertionError instead of silently [read]; 8.3.0 puts DictionaryBuilder in the jar (LUCENE-8934), where a call without -ea is silent; 8.5.0 adds the public custom-dictionary KoreanTokenizer constructor (LUCENE-9253); from 9.0.0 the project's gradle regenerate task runs the builder with only -Xmx1G, assertions off [read]",
   "affected_versions": "Every release from 7.4.0 through 10.5.2 (67 releases; latest 9.x 9.12.3), 10.6.0 (by reading) and main a9779ef3c193; never fixed. [exec] the uniform history sweep (release DictionaryBuilder.main builds a two-row colliding source, then the default KoreanTokenizer loads it from the classpath and DEFAULT_STOP_TAGS is applied) fails on 20 releases and main: 7.4.0, 7.7.3 and 8.2.0 (builder compiled from the tag's unmodified tool sources), 8.3.0, 8.4.1, 8.5.0, 8.8.2, 8.9.0, 8.10.0, 8.10.1, 8.11.0-8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-da build accepted, the noun reports the particle's tag J or JX and is dropped; -ea build stops with AssertionError), each with a passing distinct-left-id control; the public-API JUnit fails 2 of 2 with -ea and -da on 9.1.0, 9.12.3 (9.x variant), 10.0.0, 10.5.2 and main; the independent reproduction's test fails 3 of 5 on 10.5.2 and 9.12.3 (-ea and -da). [read] every release tag from 7.4.0 to 10.5.2 in the history clone (58 tags) has the assert-only check; 8.8.2-8.11.4 are not tagged locally and were executed instead. TokenInfoDictionaryEntryWriter.java is unchanged on upstream main a95c754ee003 (2026-10-26), branch_10x and branch_10_6, and lucene/analysis/nori is identical at ea57360912ed. All runs on JDK 25, aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-717.html",
   "repro": "repro/LFV-717/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-710",
   "priority": "low",
   "priority_rank": 505,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / nori system dictionary builder (DictionaryBuilder, TokenInfoDictionaryEntryWriter; custom system dictionaries)",
   "title": "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",
   "summary": "You compile a custom nori system dictionary with DictionaryBuilder from MeCab-format sources in which a lexicon row (or an unk.def row) has right context id 16385, with a matrix.def that declares 16386 right ids, and expect the row either to be rejected, as a left id of 8192 is ('leftId >= 8192'), or to read back as 16385. Instead the builder accepts it and packs the id into a 14-bit field without any check (TokenInfoDictionaryEntryWriter.java:137), so Dictionary.getRightId returns 1 and KoreanTokenizer uses the connection costs of right id 1: in the repro '가나다' is split [가나, 다] instead of [가, 나다]. A right id in [8192, 16383] decodes to about 1.07 billion, and tokenizing any text that contains the word throws IndexOutOfBoundsException from ConnectionCosts.get.",
   "impact_class": "silent wrong results",
   "introduced_commit": "e851b89cbeb1f55edc0f2c1276e2ae812eca2643 (LUCENE-8231 'Add a new analysis module (nori) similar to Kuromoji but to handle Korean', by jimczi; JIRA patch workflow, no pull request; the issue is now apache/lucene#9278) and its same-day branch_7x backport 8651fbaa8bc65fdfec397ad4e7ebe2b5acf78d7b, which shipped in 7.4.0 [read]. Not a regression: the gap dates from the module's first commit",
   "introduced_date": "2018-04-13",
   "first_affected_version": "7.4.0 [exec] (nori's first release; 7.3.1 has no nori module [exec]). Reach by version: 7.4.0-8.2.0 ship the builder only as a source-release tool, and a custom dictionary can be loaded only by putting it on the classpath ahead of the jar; 8.3.0 puts DictionaryBuilder in the jar (LUCENE-8934); 8.5.0 adds the public custom-dictionary KoreanTokenizer constructor (LUCENE-9253), the first fully public path",
   "affected_versions": "Every release from 7.4.0 through 10.5.2 (latest 9.x 9.12.3), 10.6.0 (by reading) and main a9779ef3c193; never fixed. [exec] fails on 7.4.0 (-ea and -da; history driver with the 7.4.0 source-release builder; there the left id is also only assert-checked, so with -da a left id of 8192 is accepted too), 8.3.0 (-ea and -da; history driver), 8.5.0 (-ea and -da), 8.11.4, 9.0.0 (-ea and -da), 9.1.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da): from 8.5.0 on a public-API JUnit variant fails 3 of 4 with its left-id control passing; the independent reproduction's test fails 4 of 7 on main, 10.5.2 and 9.12.3. [read] every local release tag from 7.4.0 to 8.8.1 and from 9.0.0 to 10.5.2 has the unchecked write; 8.8.2-8.11.3 are not tagged locally (between 8.8.1 [read] and 8.11.4 [exec], both affected). TokenInfoDictionaryEntryWriter.java is byte-identical on upstream main a95c754ee003 (2026-10-26), branch_10x and branch_10_6, and no open PR touches it. All runs on JDK 25, aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-710.html",
   "repro": "repro/LFV-710/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-545",
   "priority": "low",
   "priority_rank": 506,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / pattern tokenizers (analysis-common: SimplePatternTokenizer, SimplePatternSplitTokenizer and their simplePattern / simplePatternSplit factories)",
   "title": "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",
   "summary": "You tokenize 'E x', where E is an emoji such as U+1F525, with SimplePatternTokenizer and the pattern E[a-z]+|[^E ]+ (E followed by letters, or a run of characters other than E and space) and expect the single token 'x' [3,4): the attempt at E dies at the space, and the tokenizer, which steps its automaton over code points, should move on to the next code point (PatternTokenizer and java.util.regex give exactly [x]). Instead it also emits a token made of E's lone low surrogate U+DD25 at offsets [1,2), which the index stores as U+FFFD, because the failed-attempt branch pushes back all but one UTF-16 unit and so restarts in the middle of the pair. SimplePatternSplitTokenizer has the same step: separator Ea|[^Ea ]+ on 'Eb' yields the lone high surrogate [0,1) instead of the token 'E' [0,2), and with separator [^a-zE]+|E! the text 'abEcd' becomes 'ab' plus a lone high surrogate, then 'cd', instead of the one token 'abEcd'; nothing throws.",
   "impact_class": "silent wrong results",
   "introduced_commit": "93fa72f77bd024aa09eef043c65c64a6524613dc (LUCENE-7465 'add SimplePatternTokenizer and SimpleSplitPatternTokenizer, for tokenization using Lucene's regexp/automaton implementation', by GitHub mikemccand; JIRA patch, no pull request; issue migrated as apache/lucene#8517; branch_6x backport c24e03e6bf4d09e6f31eee8192bb6c0c4b2b6d27 with byte-identical tokenizer files) [read]. Not a regression: the line is as old as the classes",
   "introduced_date": "2017-02-13 (master 93fa72f and branch_6x c24e03e6bf4)",
   "first_affected_version": "6.5.0 [exec] (6.4.2 has no SimplePattern* classes [exec])",
   "affected_versions": "6.5.0 through 10.5.2 (the last release before 10.6.0; latest 9.x 9.12.3, latest 8.x 8.11.4) and main ea57360912ed; never fixed. [exec] the candidate JUnit (fails 2 of 2) and a portable main() probe (both bug cases wrong with byte-identical output, both controls correct) on 10 releases, 6.5.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0 and 10.5.2, and on main, with -da also on 6.5.0, 9.12.3, 10.5.2 and main (JUnit import adapted for 6.5.0-9.0.0, JUnitCore runner for 6.5.0-7.0.0); the independent reproduction's JUnit fails 6 of 8 on main (-ea, -da), 10.5.2 and 9.12.3. [read] the false-alarm line is in both files at every release tag 6.5.0-10.5.2 of the history clone (8.8.2-8.11.4 are untagged there; 8.8.1 read, 8.11.4 executed), and upstream main, branch_10x and branch_10_6 still have it (contents API, 2026-10-26).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-545.html",
   "repro": "repro/LFV-545/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-685",
   "priority": "low",
   "priority_rank": 507,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / ga (IrishLowerCaseFilter and IrishAnalyzer case mapping)",
   "title": "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",
   "summary": "You index text with IrishAnalyzer (or put IrishLowerCaseFilter in a chain), whose filter is documented to 'normalise token text to lower case', and expect a capitalised word to match its lower-case form, as it does with LowerCaseFilter. For letters outside the BMP it does not: the Adlam capital U+1E900 stays U+1E900 instead of becoming U+1E922 (the Deseret capital U+10400 likewise stays, also after n-eclipsis), so a document holding the Adlam word U+1E900 U+1E923 is not found by U+1E922 U+1E923 (0 hits instead of 1). The loop at IrishLowerCaseFilter.java:55 passes one UTF-16 char to Character.toLowerCase, which returns a surrogate unit unchanged; BMP letters in the same token are lower-cased and nothing is thrown.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f597b9a1cc4d9ad326ade156c630a90063fb8c5f (trunk, 'LUCENE-3883: Irish Analyzer', svn r1304836; LUCENE-3883 = #4956, committed from a JIRA patch, no pull request): the class's first commit already has the char-wise loop 'i += Character.toChars(Character.toLowerCase(chArray[i]), chArray, i)'; the branch_3x backport 69321091b9e56d5a672f014c552e8d7d47178a79 (svn r1304845, same file content) put it into 3.6.0 [read]; the line is unchanged since (later commits only moved the file, changed licence headers and reformatted)",
   "introduced_date": "2012-03-24 (trunk f597b9a1cc4 and branch_3x backport 69321091b9e, same day)",
   "first_affected_version": "3.6.0 [exec] (the first release with IrishLowerCaseFilter and IrishAnalyzer; 3.5.0 has no such class [exec]); the 'irishLowercase' factory is in Lucene's analysis module from 4.0.0 (in 3.6 it was Solr's class), and IrishAnalyzer.normalize runs the filter from 6.2.0 (LUCENE-7355) [read]",
   "affected_versions": "every release from 3.6.0 to 10.5.2 [exec] and main a9779ef3c193 [exec]; the finder's JUnit fails 3 of 4 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main; not fixed upstream: upstream main a95c754ee003 has byte-identical IrishLowerCaseFilter, IrishAnalyzer and IrishLowerCaseFilterFactory [read]; unaffected: 3.5.0 and earlier (no class) [exec]; the prereleases 4.0.0-ALPHA and 4.0.0-BETA contain the commit but were not run",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-685.html",
   "repro": "repro/LFV-685/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-477",
   "priority": "low",
   "priority_rank": 508,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / phonetic (DoubleMetaphoneFilter#incrementToken alternate-code branch; DoubleMetaphoneFilterFactory, SPI name doubleMetaphone)",
   "title": "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",
   "summary": "You run text through DoubleMetaphoneFilter, documented as 'supporting secondary codes', and expect the token 'JR' to get the same codes as 'jr', because the encoder is case-insensitive and gives both the primary code JR and the alternate code AR. Instead, when a token's text already equals its own primary code, the filter keeps the token as the primary but never emits the alternate: 'jr' gives JR and AR, 'JR' gives only JR, in both inject modes and at every maxCodeLength where the token equals its code. A document containing 'JR' is then missed by a query that matches only through AR (executed: TermQuery AR matches the document 'jr' but not the document 'JR'), while matches through the primary code still work.",
   "impact_class": "minor",
   "introduced_commit": "551e52f899aa6bf751ffb6dfe49be30e1ad638e5 (Solr trunk, svn r803971), SOLR-1359 'DoubleMetaphone filter could skip or reorder tokens, fix and update to new API' (JIRA era, no PR; committed by yonik): the rewrite added '!primaryPhoneticValue.equals(v)' to both the primary and the alternate branch [read] [exec]",
   "introduced_date": "2009-08-13",
   "first_affected_version": "Solr 1.4.0 [exec] (org.apache.solr.analysis.DoubleMetaphoneFilter, the first release after the commit); the first Lucene release that ships org.apache.lucene.analysis.phonetic.DoubleMetaphoneFilter is 3.6.0 [exec]. No release was ever unaffected: the filter was added by SOLR-813 (180ff531e1a, 2008-10-18) after Solr 1.3.0, and the guard-free code existed only on unreleased Solr trunk",
   "affected_versions": "Every release that ships the class: Solr 1.4.0, Lucene/Solr 3.1-3.5 (Solr package only), Lucene 3.6.0 through 10.5.2, and main ea57360912ed (11.0.0-SNAPSHOT). [exec] with a portable public-API probe (J, JR, JFK, SMS against lower case, maxCodeLength 4, both inject modes), identical output on each: Solr 1.4.0, Lucene 3.6.0, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the finder's JUnit fails on main (-ea, -da), 10.5.2, 10.0.0 and 9.12.3; the independent reproduction's JUnit fails on main (-ea, -da), 10.5.2 and 9.12.3. [read] all 132 release tags in the history clone that ship the class contain the guard; releases between the executed points are affected by [read] only. The encoder output for the probe words is identical across commons-codec 1.3 to 1.23.0, so the difference is in the Lucene filter alone. Not fixed upstream: the last change to the file (#15704, 2026) only swaps LinkedList for ArrayDeque. Executed only on aarch64 Linux with JDK 25 (plain Java string logic)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-477.html",
   "repro": "repro/LFV-477/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-535",
   "priority": "low",
   "priority_rank": 509,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-common / miscellaneous (CapitalizationFilter, CapitalizationFilterFactory)",
   "title": "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')",
   "summary": "You put CapitalizationFilter with onlyFirstWord=false after a KeywordTokenizer and index 'dr. jekyll' or 'new york' (two spaces), and expect 'Dr. Jekyll' and 'New York', because the filter splits words at spaces and periods (a single one works: 'st.louis' -> 'St.Louis') and its javadoc says it makes 'the first letter capital and the rest lower case'. Instead you get 'Dr. jekyll' and 'New york': after the delimiter that ends a word the loop skips the next character, so a second delimiter becomes the first character of the next word, the filter 'capitalizes' that delimiter and lower-cases the real first letter, and a keep word such as 'USA' after two spaces becomes 'usa'. With the default settings a token that starts with a space or a period (' hello world', '.net') keeps its first word lower case, and nothing throws.",
   "impact_class": "silent wrong results",
   "introduced_commit": "ac58a1a4dd4bdb3353df42f48bc20c9b5bb9e432 (SOLR-468 'CapitalizationFilterFactory keep semantics are inconsistent', svn r630572, committed by gsingers from a JIRA patch, no pull request): it rewrote the String-based word loop of SOLR-248 (777e0c81608, 2007, which appended every delimiter and processed only non-empty words) into the in-place char[] loop with 'lastWordStart = i + 1; i++;' inside 'if (len > 0)' [exec]; SOLR-1353 (bb761272256) moved the loop unchanged into incrementToken and LUCENE-2413 (8f71031ac88) moved the class into Lucene. Not a regression of any release",
   "introduced_date": "2008-02-24",
   "first_affected_version": "4.0.0-ALPHA [exec] (the first Lucene release with the class, through LUCENE-2413; first GA release 4.0.0 [exec]); Solr's own copy shipped from Solr 1.3.0 (2008-09-15) [exec]. The correct String-based code was on Solr trunk only (2007-07-14 to 2008-02-24) and was never released, so no release has ever behaved correctly",
   "affected_versions": "every Lucene release with the class, 4.0.0-ALPHA through 10.5.2, and main ea57360912ed; [exec] the finder's release-portable main() fails the 3 delimiter-run cases, with both single-delimiter controls passing, on 4.0.0-ALPHA, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main, and on Solr 1.3.0; the finder's JUnit fails 4 of 5 on main -ea and -da; the independent reproduction's JUnit fails 7 of 10 on main -ea/-da, 10.5.2 and 9.12.3; the intended-behaviour check's JUnit fails 6 of 9 on main -ea/-da, 10.5.2 and 9.12.3; [read] the whitespace-normalized loop is identical in all 123 Lucene release tags 4.0.0-alpha..10.5.2 in the history clone, and upstream main ffa9d816eeb4 (2026-10-26) still has it; aarch64 with JDK 25 only (pure char logic)",
   "security": "none",
   "upstream_links": [
    "https://lists.apache.org/thread/5sy1zrhqqs7vo4k088s4nxjm99kjtq6d",
    "https://github.com/apache/lucene/issues/6621",
    "https://issues.apache.org/jira/browse/LUCENE-5559",
    "https://github.com/apache/lucene/issues/16911"
   ],
   "doc": "",
   "repro": "repro/LFV-535/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-533",
   "priority": "low",
   "priority_rank": 510,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / miscellaneous (CapitalizationFilter case mapping)",
   "title": "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",
   "summary": "You add CapitalizationFilter, documented to 'make the first letter capital and the rest lower case', and give it a word in a cased script outside the BMP, for example the Adlam word U+1E922 U+1E923 (two small letters), and expect U+1E900 U+1E923 (capital first letter). Instead every supplementary letter keeps its case: U+1E922 U+1E923 comes out unchanged, U+1E900 U+1E901 is not lower-cased to U+1E900 U+1E923, and 'aB' followed by the Osage capital U+104B0 gives 'Ab' + U+104B0, because processWord applies Character.toUpperCase(char) and toLowerCase(char) to single UTF-16 units and a surrogate unit maps to itself. BMP letters in the same token are mapped, nothing is thrown, and the onlyFirstWord and keep-word forceFirstLetter paths behave the same way.",
   "impact_class": "silent wrong results",
   "introduced_commit": "777e0c81608b331e766c9d283778186e8fb4c7ab (Solr, JIRA SOLR-248, svn r556196; the first version of the filter, with char-wise first-letter, rest-of-word and keep-word case mapping); the four statements now on main come from ac58a1a4dd4b (SOLR-468, svn r630572, the in-place char[] rewrite, which also made the onlyFirstWord later-words path char-wise) and were copied verbatim into Lucene by 8f71031ac88e (LUCENE-2413 = #3488, svn r957162) [read]; svn era, no pull request; never changed since (later commits touched only the path, argument validation, an import, license headers and formatting)",
   "introduced_date": "2007-07-14 (Solr origin; current line form 2008-02-24; moved into Lucene 2010-06-23)",
   "first_affected_version": "4.0.0-ALPHA [exec] (the first Lucene release with the class, 2012-06-29; first GA release 4.0.0 [exec]); the same code shipped earlier as Solr's own class from Solr 1.3.0 [exec]; Lucene 3.6.2 has no such class [exec]",
   "affected_versions": "every Lucene release before 10.6.0 with the class, 4.0.0-ALPHA through 10.5.2, and main ea57360912ed: JUnit fails on main (-ea and -da), 10.5.2 and 9.12.3 [exec], and a release-portable main() fails on 8.11.4, 4.0.0 [exec] and 4.0.0-ALPHA and Solr 1.3.0 [exec]; the four char-wise statements are unchanged in all 133 release-tag file versions scanned (Solr 1.3.0-3.6.2, Lucene 4.0.0-ALPHA-10.5.2) [read]; not fixed upstream: upstream main ffa9d816eeb4 has a byte-identical file and branch_10x, branch_10_6 and branch_10_5 have the same lines [read]; unaffected: Lucene before 4.0.0-ALPHA (no class) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-533.html",
   "repro": "repro/LFV-533/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-752",
   "priority": "low",
   "priority_rank": 511,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / Sorani normalizer (SoraniNormalizer.normalize; SoraniNormalizationFilter, SoraniAnalyzer and the 'soraniNormalization' factory)",
   "title": "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",
   "summary": "You analyze Sorani Kurdish text with the stock SoraniAnalyzer or SoraniNormalizationFilter. The normalizer's javadoc says formatting characters are removed, and it does remove BMP ones such as the right-to-left mark, so کورد + X + ستان should become کوردستان for any invisible format character X. Instead it calls Character.getType on one UTF-16 char at a time, so a format character outside the BMP (for example U+E0001 or a tag character), which Java stores as two surrogate chars, is never recognized: it stays in the term, and the word no longer matches the same word without it, with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "2140f4368ade00f1d3b6f2bb25ecaf257c639c3d (trunk, Subversion r1555359, 'LUCENE-5379: Kurdish Analyzer' by rmuir; JIRA LUCENE-5379, migrated as apache/lucene#6442; no PR, pre-GitHub) with its same-day branch_4x backport a670b8d5b22 (r1555360, identical SoraniNormalizer.java), the copy that shipped in 4.7.0 [read]: the char-wise 'Character.getType(s[i]) == Character.FORMAT' test and the javadoc sentence 'Harakat, tatweel, and formatting characters such as directional controls are removed.' were in the first version of the file. Not a regression: the four later commits on the file (813ca77250d LUCENE-7013 license header, 8ef6a0da568 LUCENE-9570 reformat, 8ac26737913 LUCENE-10003 array syntax, 694d797526a LUCENE-10561 package-private) leave this logic unchanged.",
   "introduced_date": "2014-01-04 (trunk and branch_4x; first released in 4.7.0)",
   "first_affected_version": "4.7.0 [exec] (the first release with the org.apache.lucene.analysis.ckb package; the follow-up's 4.x-API main() repro reports the bug there: U+E0001, U+E0067 and U+1BCA0 are kept by SoraniNormalizationFilter while the BMP control U+200F, U+200E, U+2066 is removed). 4.6.1, the last release before it, has no Sorani analysis API [exec], so no release ever removed supplementary format characters.",
   "affected_versions": "Every release that ships the Sorani analysis API, 4.7.0 through 10.5.2, and main a9779ef3c193; not fixed. [exec] the follow-up's cross-version main() repro (4.x and 5.0+ API variants) reports the bug on 4.7.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 10.5.2 and main; the finder's JUnit fails 2 of 3 (its BMP control passes) on 9.12.3, 10.0.0 and 10.5.2 (-ea) and on main (-ea and -da); the independent reproduction's JUnit fails 3 of 4 on 9.12.3 and 10.5.2 (-ea) and on main (-ea and -da); the intended-behaviour check's probe keeps all 127 supplementary Cf code points and removes all 43 BMP Cf code points on 9.12.3 and 10.5.2 (-da) and on main (-ea and -da). [read] the code is unchanged since the introducing commit, so the releases between the sampled ones are affected by code reading; upstream main f7bcc0abd816 (2026-10-27) and branch_10x still have line 121 unchanged. All runs used JDK 25.0.3; the result does not depend on the JDK, because each half of a supplementary code point is a surrogate and never FORMAT.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-752.html",
   "repro": "repro/LFV-752/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-350",
   "priority": "low",
   "priority_rank": 512,
   "novelty": "known",
   "withheld": false,
   "area": "suggest / spell checking (LuceneLevenshteinDistance.getDistance, the StringDistance class behind DirectSpellChecker.INTERNAL_LEVENSHTEIN)",
   "title": "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)",
   "summary": "LuceneLevenshteinDistance is documented as a similarity (StringDistance: 1 means identical, 0 maximally different) that is 'consistent' with FuzzyTermsEnum, and for two non-empty strings it returns 1 - distance / min(length). When a string is empty it instead returns a raw edit distance: 0 for getDistance(\"\", \"\") and max(n, m) for one empty side, so getDistance(\"\", \"abc\") = 3.0, three times the score of identical strings. Through DirectSpellChecker set up with new LuceneLevenshteinDistance(), minPrefix 0 and minQueryLength 1, an indexed empty term is suggested for the query \"a\" with score 1.0, while the default internal scoring filters it out.",
   "impact_class": "silent wrong results",
   "introduced_commit": "b096910a8219f1575cb8e257673915f1a821ffef (LUCENE-3662 'extend LevenshteinAutomata to support transpositions as primitive a edit', SVN trunk r1224817; SVN era, no GitHub PR; issue migrated as apache/lucene#4736). It replaced the empty-input branch 'if (n == m) return 1; else return 0;' that the class had when it was added by f5ee5914b021205199bf50010c0bc80a418b432c (LUCENE-3527, r1195081, 2011-10-30) with 'return 0; else return Math.max(n, m);'. The same commit added a raw edit-distance test helper (TestLevenshteinAutomata.getTDistance) with the identical branch, where those values are correct; that the branch was carried over from it is an inference, not stated anywhere. [read]. A regression on trunk, but no release ever had the correct values.",
   "introduced_date": "2011-12-26 (b096910a821; the class itself was added 2011-10-30 by f5ee5914b02 with the correct 1/0 branch)",
   "first_affected_version": "4.0.0-alpha [exec] (4.0.0 GA [exec]); the first release that contains the class, so no release had the correct values: the 3.4.0, 3.5.0, 3.6.0 and 3.6.2 trees contain neither LuceneLevenshteinDistance nor DirectSpellChecker [read]",
   "affected_versions": "every release that contains the class, 4.0.0-alpha to 10.5.2 (the last release before 10.6.0), and main ea57360912ed; no fixed release. [exec] a version-portable main() repro prints getDistance(\"\", \"\") = 0.0, (\"\", \"abc\") = 3.0 and (\"abc\", \"\") = 3.0 on 4.0.0-ALPHA, 4.0.0-BETA, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main; the finder's JUnit (including the DirectSpellChecker effect) fails 3 of 3 on 8.11.4 and 9.0.0 (a copy that differs only in the test-framework import), 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the independent reproduction's own JUnit fails 4 of 4 on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check re-ran the finder's JUnit on main (-ea and -da), 10.5.2 and 9.12.3 (all fail). [read] the remaining releases by blame (the lines are unchanged since b096910a821 apart from formatting); tag 4.0.0 DirectSpellChecker already scores with distance.getDistance when the distance is not INTERNAL_LEVENSHTEIN, but the DirectSpellChecker effect was executed on 8.11.4 and later only. Upstream main still has the branch (GitHub contents API, 2026-10-26). Not executed: x86, the JDK of each release's era (all runs used JDK 25.0.3 aarch64; getDistance depends only on IntsRef).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/3901",
    "https://issues.apache.org/jira/browse/LUCENE-2827",
    "https://github.com/apache/lucene/issues/2624",
    "https://issues.apache.org/jira/browse/LUCENE-1550",
    "https://github.com/apache/lucene/issues/4601",
    "https://issues.apache.org/jira/browse/LUCENE-3527"
   ],
   "doc": "",
   "repro": "repro/LFV-350/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-049",
   "priority": "low",
   "priority_rank": 513,
   "novelty": "new",
   "withheld": false,
   "area": "util / automaton",
   "title": "Operations.isTotal returns true for a deterministic automaton that can reach a dead state, so an AutomatonQuery can match every term",
   "summary": "You call Operations.isTotal, or build an AutomatonQuery, on a deterministic automaton that rejects some strings and has a reachable dead state, such as a complete DFA with an explicit sink state built by hand. You expect false, as Lucene 9.12.0 returns. Instead, since 10.0.0, isTotal checks only live states, so a transition into the dead state counts as coverage and it returns true; CompiledAutomaton then compiles the query to AUTOMATON_TYPE.ALL, and in the repro an AutomatonQuery matched 3 documents instead of 2.",
   "impact_class": "silent wrong results",
   "introduced_commit": "#13707 (ea3a9b89278)",
   "introduced_date": "2024-09-05",
   "first_affected_version": "10.0.0 (regression; 9.12.0 correct)",
   "affected_versions": "10.0.0-10.5.2, branch_10_6 and main [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-049.html",
   "repro": "repro/LFV-049/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-845",
   "priority": "low",
   "priority_rank": 514,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / classic and flexible standard grammars (Range lexical state, RANGE_GOOP token)",
   "title": "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",
   "summary": "You parse 'date:[20200101<TAB>TO<TAB>20201231]' or the multi-line 'date:[<LF>20200101 TO 20201231<LF>]' with the classic or the flexible standard query parser; both grammars declare TAB, LF, CR and U+3000 as whitespace and skip it inside ranges too, so you expect the same query as with spaces. Instead the range-bound token RANGE_GOOP, which excludes only U+0020 and the closing brackets, swallows any of these characters that touches a bound: the first query throws ParseException ('Was expecting: \"TO\"'), and the second parses without error into a TermRangeQuery whose bounds are '<LF>20200101' and '20201231<LF>', so it also matches 20191231 (4 hits instead of 3). In the same way 'date:{20200101 TO 20201231<TAB>}' admits its own exclusive endpoint, and a leading U+3000 makes the range match nothing.",
   "impact_class": "silent wrong results",
   "introduced_commit": "8ab0396cfccdafe51e6b741ea8e35a6491e1aa09 (svn r149785, author Brian Goetz, 'Support for new range query syntax. The delimiter is \" TO \", but is optional for backward compatibility with previous syntax.'; no issue or PR; CHANGES.txt 1.3 RC1 item 5): it replaced the one-token range, whose inside the analyzer split, with the RangeIn/RangeEx lexical states, extended the whitespace SKIP rule to them ('<DEFAULT, RangeIn, RangeEx> SKIP', _WHITESPACE then ' ' | TAB) and defined RANGEIN_GOOP (~[' ', ']'])+ and RANGEEX_GOOP (~[' ', '}'])+, which exclude only U+0020, so a TAB next to a bound has been part of the bound since then [exec]. Widened without touching the goop rule by 9ada9671259 (2004, LUCENE-93 / #1171, Bugzilla 18847: LF and CR added to _WHITESPACE) [exec], 13d5245314e (2009, LUCENE-1528 / #2602: U+3000 added) [read] and 343992fcbb4 (2009, LUCENE-1567 / #2641: the flexible parser created with a copy of the same token rules) [read]; c8c9ee2cb20 (LUCENE-996, 2010) and cffd01664bc (2011, flexible grammar) merged the two goop rules into RANGE_GOOP (~[' ', ']', '}'])+ with the same exclusions [read]",
   "introduced_date": "2002-06-25 (author date of 8ab0396cfcc, TAB); widened 2004-03-03 (LF, CR), 2009-01-28 (U+3000) and 2009-08-03 (flexible parser)",
   "first_affected_version": "1.3-rc1 [exec] (TAB; LF and CR from 1.4-rc1 [read], first on Maven Central 1.4.1 [exec]; U+3000 and the flexible parser from 2.9.0 [exec]); 1.2 [exec] is not affected because the TO range syntax did not exist yet",
   "affected_versions": "Every release from 1.3-rc1 to 10.5.2 (latest 9.x: 9.12.3; latest 10.x before 10.6.0: 10.5.2), the branch_10_6 head 4ae946e5a9b9 (10.6.0, released 2026-10-29) and main a9779ef3c193; not fixed upstream (the RANGE_GOOP line is unchanged on upstream main 20ced71c1e6e, branch_10x and branch_10_6, 2026-10-28 [read]). [exec] history probe (one class, public parse API through reflection): 1.3-rc1, 1.3, 1.4.1 and 1.4.3 (plain JDK runs on SHA-1-checked Maven Central jars) and all 156 releases from 1.9.1 to 10.5.2 through repro.sh are affected, 1.2 is not; the finder's JUnit fails 4/4 on main (-ea and -da), the branch_10_6 head, 10.5.2 and 9.12.3 (it does not compile on 9.0.0, older test-framework package); the independent reproduction's JUnit fails 6/7 on main (-ea and -da), the branch_10_6 head, 10.5.2 and 9.12.3. Characters affected: TAB in 1.3-rc1 and 1.3; TAB, LF and CR in 1.4-rc1 to 2.4.1 (classic only); all four in 2.9.0 to main, classic and flexible. [read] 1.4-rc1 to 1.4 final and 1.9 (not on Maven Central; same token rules in their trees). All runs JDK 25 on aarch64; the defect is in the generated lexer tables, so no platform dependence is expected (not executed on x86)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-845.html",
   "repro": "repro/LFV-845/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-082",
   "priority": "low",
   "priority_rank": 515,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / flexible",
   "title": "Flexible StandardQueryParser narrows out-of-range int literals with intValue(), so i:[2147483648 TO *] matches every document with the field",
   "summary": "You parse a point query whose literal lies outside the field's int range, such as i:[2147483648 TO *], i>=2147483648 or i:2147483648, with the flexible StandardQueryParser and an Integer PointsConfig. You expect no match, because no int value reaches that bound. Instead PointRangeQueryNodeProcessor and PointQueryNodeProcessor narrow the parsed number with Number.intValue(), which wraps it, so the range queries match all 5 documents of the repro and i:2147483648 matches the Integer.MIN_VALUE document.",
   "impact_class": "silent wrong results",
   "introduced_commit": "unknown (not yet bisected)",
   "introduced_date": "unknown (not yet bisected)",
   "first_affected_version": "unknown (not yet bisected)",
   "affected_versions": "main [exec]; the same lines are in the 10.5.2 source [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-082.html",
   "repro": "repro/LFV-082/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-645",
   "priority": "low",
   "priority_rank": 516,
   "novelty": "new",
   "withheld": false,
   "area": "core / document (DateTools date-to-string term encoding: timeToString/dateToString and stringToTime/stringToDate)",
   "title": "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)",
   "summary": "You convert a date before AD 1 or after 9999 with DateTools.timeToString (or dateToString) and expect what the class javadoc promises: strings whose lexicographic order is date order, which stringToTime turns back into the same time. Instead the SimpleDateFormat pattern 'yyyy...' prints the year of era with no era and at least four digits: 2 BC-01-01 becomes \"00020101\", which sorts after AD 1's \"00010101\" and parses back as AD 2-01-01 (at YEAR resolution 1 BC and AD 1 both give \"0001\"), and 10000-01-01 becomes \"100000101\", which sorts before \"20260101\" and makes stringToTime throw ParseException, because the parser is chosen by string length. Range queries, prefix queries and sorts on such terms therefore return wrong results with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "c7fbb991c3e55fb6c3c3f3d2f0757176a7eccb06 (trunk, svn r150483, 'Add a new class that supports converting dates to readable strings, with limited resolution.', committed by ASF committer dnaber; svn era, no PR and no JIRA id): the class's first commit already formats with the SimpleDateFormat patterns 'yyyy' .. 'yyyyMMddHHmmssSSS' (year of era, no era letter, no range check), parses by string length (4/6/8/10/12/14/17) and carries the ordering sentence [read]. Not a regression: later refactors kept the patterns (f72c1e579fe 2006 static formats; fcf6e305b48 LUCENE-1472 2011 ThreadLocal formats; 31479ab48ce LUCENE-1736 2011 'yyyyMMddHHmmssSSS'.substring(0, formatLen) and the format array indexed by string length; b6a4748f21b 2012 Locale.ROOT; 2971f311a2b LUCENE-9911 2021 ParseException cause; 2d6ad2fee6d reformat), and git log -S finds no commit that ever added an era, a signed year or a range check",
   "introduced_date": "2004-09-05 (c7fbb991c3e, trunk)",
   "first_affected_version": "1.9 [read] (2006-02-27, the first release with DateTools; first release candidate 1.9-rc1 2006-02-21; 1.9 is not on Maven Central); 1.9.1 [exec] (2006-03-02) is the first executed release and fails the history probe 5 of 5; 1.4.3 and earlier have no DateTools [exec]",
   "affected_versions": "Every release that has DateTools, 1.9 through 10.6.0 (10.6.0 by reading), and main a9779ef3c193; never fixed. [exec] the version-history runs's version-neutral main() probe (checks: 2 BC < AD 1 at DAY, 2 BC round trip, 1 BC < AD 1 at YEAR, 2026 < 10000 at DAY, year-10000 round trip; its control AD 1, 1582-10-15, 1970, 2026, 9999-12-31 passes) fails 5 of 5 on 17 releases (1.9.1, 2.0.0, 2.1.0, 2.9.4, 3.0.3, 3.2.0, 3.3.0, 3.6.2, 4.0.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2), on main and on the introducing commit's DateTools.java; the finder's JUnit fails 3 of 3 on main (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 5 of 6 on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's reachability JUnit fails 3 of 4 on main (-ea and -da), 10.5.2 and 9.12.3; upstream main a95c754ee003 (2026-10-26) has the same DateTools.java (last change dbaf97f5dcc, 2025-07-18, generics cleanup) and no open PR touches it, so 10.6.0 (released 2026-10-29) and the unreleased 11.0 line are affected (not executed). Not executed: x86 and JDKs other than 25.0.3 (the behaviour is documented java.text.SimpleDateFormat semantics: 'y' is the year of era and the letter count is a minimum width). JDK 25.0.3, aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-645.html",
   "repro": "repro/LFV-645/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-283",
   "priority": "low",
   "priority_rank": 517,
   "novelty": "known",
   "withheld": false,
   "area": "queryparser / classic and flexible date ranges (QueryParserBase.getRangeQuery, TermRangeQueryNodeProcessor; setTimeZone and ConfigurationKeys.TIMEZONE)",
   "title": "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",
   "summary": "You give the query parser a time zone with setTimeZone (plus setLocale and setDateResolution) and parse d:[6/1/2005 TO 6/4/2005], expecting what the QueryParser javadoc promises, a range 'between 2005-06-01 and 2005-06-04', read in that zone: June 1 00:00 to June 4 23:59:59.999 there. Instead both dates are parsed by a DateFormat that still uses the JVM default zone, and only the rounding of the inclusive end to 23:59:59.999 uses the configured zone, so the window starts at midnight in the JVM zone and ends at the end of the configured-zone day that contains the JVM-zone midnight of June 4: with the JVM on UTC and the parser on New York the June 4 New York documents are silently lost (and May 31 from 20:00 matches), with the JVM on UTC and the parser on Tokyo the first nine hours of June 1 are lost. Exclusive ranges such as {6/1/2005 TO 6/4/2005} ignore the configured zone entirely, and the classic and the flexible parser behave the same.",
   "impact_class": "silent wrong results",
   "introduced_commit": "5fea62f7c82cd4f79c893f06939c9f8cdbb269f5 ('LUCENE-4199: allow setting of tz used for date range parsing', rmuir, 2012-07-09, svn branch lucene4199 r1359149; no pull request (svn era); the issue LUCENE-4199 = apache/lucene#5271 is the forbidden-API build check, and its description and comments never mention time zones in the query parser), merged to trunk as e3813f80300 (r1359202, uschindler) and backported to branch_4x as f7941ee03a3 (r1359229, uschindler) the same day. It added setTimeZone/getTimeZone to both parsers and ConfigurationKeys.TIMEZONE, and in the date code changed only Calendar.getInstance(locale) to Calendar.getInstance(timeZone, locale) in the inclusive-end rounding; the DateFormat line that parses both dates (older code: 9af1a725691c in the classic parser, contrib-era commits in the flexible one) was not touched. Before it there was no setter and both steps used the JVM default zone, so the bug is as old as the setter. [read]",
   "introduced_date": "2012-07-09 (5fea62f7c82; trunk merge e3813f80300 and branch_4x backport f7941ee03a3 the same day)",
   "first_affected_version": "4.0.0-BETA [exec] (tag 2012-08-10; first GA release 4.0.0, tag 2012-10-11 [exec]); 4.0.0-ALPHA, the last release before, and 3.6.2 on the 3.x line have no setTimeZone (the probe does not compile; their date-range code uses the JVM default zone throughout, so the window is consistent) [exec]",
   "affected_versions": "every lucene-queryparser release from 4.0.0-BETA through 10.5.2 (131 releases on Maven Central; 10.5.2 was the last before 10.6.0), 10.6.0 (by reading) and main ea57360912ed. [exec] the history probe (JVM zone UTC, parser zone Asia/Tokyo, MINUTE resolution, classic and flexible parsers, inclusive and exclusive forms: 6 of 8 bounds wrong) fails on 24 releases (4.0.0-BETA, 4.0.0, 4.1.0, 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.8.2, 8.9.0, 8.10.0, 8.10.1, 8.11.0 .. 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2) and on main with -ea and -da, while its equal-zone control passes; the finder's and the independent reproduction's JUnits fail on 9.12.3, 10.5.2 and main (-ea and -da); the intended-behaviour check's probes fail on 9.12.3, 10.5.2 and main. [read] all 122 release tags 4.0.0-beta .. 10.5.2 in the full-history clone contain, in both files, the DateFormat without setTimeZone and the zone-aware Calendar; upstream main, branch_10x and branch_10_6 are unchanged (read 2026-10-26). Not fixed upstream. All runs on JDK 25.0.3, aarch64 Linux, not each release's own JDK.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/4425",
    "https://issues.apache.org/jira/browse/LUCENE-3352",
    "https://issues.apache.org/jira/browse/LUCENE-4199",
    "https://github.com/apache/lucene/issues/5271",
    "https://github.com/apache/lucene/issues/4426",
    "https://issues.apache.org/jira/browse/LUCENE-3353"
   ],
   "doc": "",
   "repro": "repro/LFV-283/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1206",
   "priority": "low",
   "priority_rank": 518,
   "novelty": "new",
   "withheld": false,
   "area": "core / document (DateTools string-to-date decoding: stringToDate and stringToTime)",
   "title": "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)",
   "summary": "You call DateTools.stringToDate (or stringToTime) on a string that is not in DateTools' yyyyMMdd... format, for example \"2024123X\" or the ISO date \"2019-12-31\", and expect the ParseException that both methods document ('if dateString is not in the expected format') and already give for a wrong length or an unreadable start such as \"aaaa\". Instead, because the string has one of the seven supported lengths, it goes to a lenient SimpleDateFormat through DateFormat.parse(String), which ignores trailing text and rolls impossible fields over, so a different date comes back with no error: \"2024123X\" gives 2024-12-03T00:00:00Z, \"2019-12-31\" gives 2018-10-31T17:00:00Z and \"20041301\" (month 13) gives 2005-01-01T00:00:00Z.",
   "impact_class": "minor",
   "introduced_commit": "c7fbb991c3e55fb6c3c3f3d2f0757176a7eccb06 (trunk, svn r150483, 'Add a new class that supports converting dates to readable strings, with limited resolution...', Daniel Naber; svn era, no PR and no JIRA or Bugzilla id; CHANGES.txt 1.9 'New features' item 4): the first DateTools already chose the pattern by dateString.length(), threw its own ParseException for any other length and returned new SimpleDateFormat(pattern).parse(dateString), a lenient (JDK default) prefix parse, under today's '@throws ParseException if dateString is not in the expected format' [read]. Its companion test commit bdcaaa7e623 asserted ParseException only for '97', '200401011235009999' and 'aaaa'. Not a regression: every later rewrite kept a lenient SimpleDateFormat and parse(String) (646d9646cbb LUCENE-491 GMT zone, 2006; f72c1e579fe static formats, 2006; 3c3b283e3c0 LUCENE-1653, 2009; fcf6e305b48 LUCENE-1472 ThreadLocal formats, 2011; 31479ab48ce LUCENE-1736 TL_FORMATS indexed by length and built from Resolution.format, 2011, today's :117 and :194-200; b6a4748f21b Locale.ROOT, 2012; 2971f311a2b LUCENE-9911 initCause, 2021), and git log -S'setLenient' and -S'ParsePosition' over the full history of DateTools.java find no commit [read].",
   "introduced_date": "2004-09-05 (author and commit date of c7fbb991c3e, 2004-09-05T21:27:29Z)",
   "first_affected_version": "1.9 [read] (1.9-rc1 2006-02-21, 1.9 final 2006-02-27; the first release with DateTools, so no release has the API without the defect; DateTools.java at the 1.9-rc1 and 1.9 tags is identical to 1.9.1's, and 1.9 is not on Maven Central); 1.9.1 [exec] (2006-03-02) is the first executed release and fails; 1.4.3 and earlier have no DateTools [exec]",
   "affected_versions": "Every release from 1.9 (2006) through 10.6.0 (4ae946e5a9b, released 2026-10-29) and main 5adff78bb168 (12.0.0-SNAPSHOT); never fixed. [exec] month-13 form (stringToTime(\"20041301\") returns 2005-01-01T00:00:00Z): all 157 final lucene-core releases on Maven Central from 1.9.1 to 10.6.0 (a main() form of the same call for releases without today's test framework; only the 4.0.0-ALPHA and -BETA pre-releases were not run), the introducing commit's own DateTools.java, 10.6.0 also with -da, and main with -ea and -da. Trailing-letter form (stringToDate(\"2024123X\") returns 2024-12-03T00:00:00Z): main with -ea and -da (tie-breaker; re-run), 10.6.0 (-ea and -da), 10.5.2 and 9.12.3, and 1.9.1 (tie-breaker main() probe on the SHA-1-checked jar). [read] every release tag from 1.9-rc1 to 10.6.0 parses with SimpleDateFormat parse(dateString) and has no setLenient or ParsePosition; DateTools.java has the same blob dda55bf2fb13 on 5adff78bb168, on releases/lucene/10.6.0 and on upstream main 1c2072f0284 (2026-11-02), and its newest upstream commit is dbaf97f5dcc (#14965, author and committer date 2025-07-18, an ecj cleanup that does not touch parsing). Not affected: 1.4.3 and earlier (no DateTools). Not new in 10.6 (10.5.2 and every earlier executed release fail). All runs used JDK 25.0.3 on Linux aarch64; older JDKs were not executed (documented java.text behaviour).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1206.html",
   "repro": "repro/LFV-1206/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1123",
   "priority": "low",
   "priority_rank": 519,
   "novelty": "new",
   "withheld": false,
   "area": "core / document (DateTools resolution limiting: round(long, Resolution) and round(Date, Resolution))",
   "title": "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",
   "summary": "You call DateTools.round(Long.MIN_VALUE, Resolution.DAY), for example to align the open lower bound of a date range with day-rounded indexed values, and expect a time no later than the input, as the javadoc promises ('the date with all values more precise than resolution set to 0 or 1'). Instead you get 9223372036794351616, a time in AD 292278994 just below Long.MAX_VALUE, with no error: the start of that day lies below Long.MIN_VALUE, and the lenient GregorianCalendar that round() uses wraps around in its long arithmetic. YEAR, MONTH, HOUR, MINUTE and SECOND wrap the same way for inputs before the first unit boundary above Long.MIN_VALUE, and round(Date, Resolution) delegates, so it wraps too.",
   "impact_class": "minor",
   "introduced_commit": "c7fbb991c3e (trunk, svn r150483, Daniel Naber, 'Add a new class that supports converting dates to readable strings, with limited resolution...'; SVN era, no PR and no JIRA id): DateTools was born with round(long, Resolution) setting the finer fields on a lenient java.util.Calendar and reading the time back, with today's @return wording and no range check [read]. Not a regression: LUCENE-491 (646d9646cbb, GMT calendar, before 1.9), LUCENE-1653 (3c3b283e3c0, cached Calendar and getTimeInMillis), LUCENE-1472 (fcf6e305b48 / b640e28ad38, ThreadLocal calendar, Resolution enum, switch), LUCENE-1846 (bb391fd3edc / 3c3e77e08c8, locale) and LUCENE-1736 (31479ab48ce / b49d9c897df, today's fall-through switch over TL_CAL) all kept the mechanism [read]; every executed release from 1.9.1 on fails [exec].",
   "introduced_date": "2004-09-05 (author and committer date of c7fbb991c3e)",
   "first_affected_version": "1.9 [read] (release tag 2006-02-27, the first release with DateTools; 1.9 is not on Maven Central and DateTools.java is identical at the 1.9 and 1.9.1 tags); 1.9.1 [exec] is the earliest executed release and fails; 1.4.3 and earlier have no DateTools [exec]",
   "affected_versions": "Every release from 1.9 (2006) through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT); never fixed. [exec] round(Long.MIN_VALUE, DAY) = 9223372036794351616 on 1.9.1, 2.4.1, 2.9.0, 3.0.3, 3.1.0, 3.3.0, 4.0.0, 4.10.4 and 8.11.4 (a main() variant of the same call and check, -da, because releases before 9.x lack today's LuceneTestCase), and with the one-test JUnit unchanged on 9.12.3 and 10.0.0 (-da), 10.6.0 (-ea and -da) and main 5adff78bb168 (-ea and -da, also in the re-run); the independent reproduction's YEAR test fails on main (-ea and -da), 10.6.0, 10.5.2 and 9.12.3. Not new in 10.6 (10.5.2 and every earlier executed release fail). Not fixed upstream: DateTools.java has the same blob dda55bf2fb13 on 5adff78bb168, on 10.6.0 and on upstream main 1c2072f02843 (2026-11-02); its last commit is dbaf97f5dcc (#14965, author date 2025-07-18, a lint cleanup that does not touch round) [read]. All runs used JDK 25.0.3 on Linux aarch64, so old releases ran against today's GregorianCalendar; how the JDKs of 2006-2011 behaved was not executed.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1123.html",
   "repro": "repro/LFV-1123/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-196",
   "priority": "low",
   "priority_rank": 520,
   "novelty": "new",
   "withheld": false,
   "area": "search / phrase matching (ExactPhraseMatcher, SloppyPhraseMatcher and PhrasePositions position arithmetic; PhraseQuery.Builder and MultiPhraseQuery.Builder accept the positions)",
   "title": "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",
   "summary": "You build a PhraseQuery with term a at position 0 and term b at position Integer.MAX_VALUE (the builder accepts it, because it only checks that positions are >= 0 and in order) and count it on a one-document index whose text is 'x a b'. You expect 0 hits, because no indexed position can be that far from a. Instead the exact matcher adds a's document position 1 and b's offset Integer.MAX_VALUE in int, the sum wraps to a negative number, both of its advance steps then leave its state unchanged, and IndexSearcher#count never returns, even with a 1 s IndexSearcher#setTimeout; with slop 1 the same kind of overflow makes the sloppy matcher return the document 'b x x a' as a hit.",
   "impact_class": "hang",
   "introduced_commit": "Hang: 5e9b2465991 on branch_5x (trunk twin fd8c4b31201), 'LUCENE-6260: Simplify ExactPhraseScorer.' (migrated as apache/lucene#7322, author jpountz; Subversion era, no pull request), which replaced the chunked exact-phrase intersection with the lead/advancePosition loop and introduced all three overflowing int expressions: phrasePos = lead.pos - lead.offset, expectedPos = phrasePos + posting.offset, and the lead re-target posting.pos - posting.offset + lead.offset [read]. The issue text and comments discuss performance only. Sloppy false hit: older and not from one commit. The int span in the sloppy scorer ('int matchLength = end - start', rewritten as 'matchLength = end - pp.position' by LUCENE-3215, c54608b60dc, 2011) and PhrasePositions 'position = nextPosition() - offset' date from the initial import (bd3948c539e, 2001); query offsets that can make them overflow became possible with fd4cd859c57 (2004-09-15), which added explicit positions to PhraseQuery and PhrasePrefixQuery (CHANGES.txt 1.4.2 item 4) [read]. Later refactors moved the exact loop without changing the arithmetic: LUCENE-8249 (7.4.0) created ExactPhraseMatcher#nextMatch, and #15861 (2026-04-21) changed only how frequencies are loaded [read].",
   "introduced_date": "2015-02-20 (hang: author and commit date of 5e9b2465991 and fd8c4b31201); sloppy side: 2004-09-15 (explicit query positions, fd4cd859c57) on span arithmetic from the 2001 initial import",
   "first_affected_version": "5.1.0 for the hang (the first release tag containing 5e9b2465991, tag commit dated 2015-04-13; 5.0.0, tagged 2015-02-19, does not contain it and terminates [exec]); the sloppy false hit is far older: 1.9.1 (2006) [exec], the oldest release that could be executed, and by reading 1.4.2 (2004), the first release with PhraseQuery#add(Term, int); in 1.9.1 to 2.4.1 the false hit is visible only at scorer level (a HitCollector sees it with score NaN, the top-docs path returned 0), and from 2.9.0 the top-docs path counts it too [exec]",
   "affected_versions": "Hang: every release from 5.1.0 to 10.6.0 (10.6.0 by reading) and main ea57360912ed. [exec] reproduced on 5.1.0, 5.5.5, 6.0.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.3.0, 9.12.3, 10.0.0, 10.5.2, main (-ea and -da) and commit 5e9b2465991; [read] 97 of the 106 releases from 5.1.0 to 10.5.2 on Maven Central are tagged in the history clone and every one of those tags contains the three int expressions (the other 9, 8.8.2 to 8.11.4, have no tag; 8.11.4 was executed). Not affected by the hang: 5.0.0 and earlier [exec]. IndexSearcher#setTimeout (added in 9.3.0) did not stop the hang in any executed release that has it [exec]; the releases in between were not run with a timeout. Sloppy false hit (slop 1; PhraseQuery with an offset of Integer.MAX_VALUE, MultiPhraseQuery with Integer.MIN_VALUE): reproduced on every executed release from 1.9.1 to 10.5.2 and on main [exec], scorer level only in 1.9.1 to 2.4.1. Not executed: 1.4.2 to 1.9 (not on Maven Central under org.apache.lucene). Not fixed: upstream main was still ea57360912ed on 2026-10-26, the overflowing expressions are present on main, branch_10x, branch_10_6 and branch_9_12, and no commit touches ExactPhraseMatcher, SloppyPhraseMatcher or PhrasePositions after it [read]. The history runs used JDK 25 and seed DEADBEEF; the version-adapted main() repros use NIOFSDirectory on 5.x and later and RAMDirectory on 4.x and older.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-196.html",
   "repro": "repro/LFV-196/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-397",
   "priority": "low",
   "priority_rank": 521,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / original Highlighter, QueryScorer and WeightedSpanTermExtractor (phrase-to-span conversion)",
   "title": "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",
   "summary": "You analyse 'the quick brown fox jumps' with a stop-word analyzer, search for the phrase \"quick the fox\" with slop Integer.MAX_VALUE (for example from the user text \"quick the fox\"~3000000000, which the classic QueryParser turns into \"quick ? fox\"~2147483647; the query matches), and highlight the hit with Highlighter and QueryScorer, expecting 'the <B>quick</B> brown <B>fox</B> jumps', which slop Integer.MAX_VALUE - 1 or the same phrase without the hole gives. Instead getBestFragment returns null, with no error: WeightedSpanTermExtractor rewrites the phrase as new SpanNearQuery(clauses, slop + positionGaps, inorder) with a plain int sum, the removed stop word counts as one position gap, the sum wraps to -2147483648, and a span query with that slop accepts no match, so no term is marked. MultiPhraseQuery has the same sum, and the UnifiedHighlighter with weight matches turned off reaches it through PhraseHelper and returns the passage with no highlight.",
   "impact_class": "silent wrong results",
   "introduced_commit": "35c7eb36dfb (svn r652164, LUCENE-794 'Commit of LUCENE-794 patch - adding phrase/span query support to highlighter', committed by GitHub markharwood, patch series by GitHub markrmiller; JIRA LUCENE-794 is now apache/lucene#1869; 2008-04-29) created WeightedSpanTermExtractor with the MultiPhraseQuery sum 'slop + positionGaps' already in today's form (main :232); LUCENE-2003 (#3078, 6cd7218a428 on the 2.9 branch and 9609a2cb4db on trunk, 2009-10-23, committed by GitHub markrmiller) added the PhraseQuery sum as 'slop += largestInc'; LUCENE-5503 (#6566, c5b49baa592 on trunk and 4c40ad78c94 on branch_5x, 2015-09-13, patch by GitHub tballison, committed by GitHub dsmiley) rewrote it as today's 'getSlop() + positionGaps' (main :161-162) and kept the overflow, only moving its threshold [read] [exec]. Present since the code was written; not a regression; both changes predate GitHub, so there is no pull request",
   "introduced_date": "2008-04-29 (35c7eb36dfb, LUCENE-794: MultiPhraseQuery sum); 2009-10-23 (LUCENE-2003: PhraseQuery sum); 2015-09-13 (LUCENE-5503: today's PhraseQuery formula, overflow kept)",
   "first_affected_version": "2.4.0 [exec] (release 2008-10-08): MultiPhraseQuery only, and only through the opt-in SpanScorer; 2.9.0 [exec]: MultiPhraseQuery through the default QueryScorer (LUCENE-1685 made the span-aware scorer the default); 2.9.1 and 3.0.0 [exec]: PhraseQuery too, the common case. 2.3.2 has no such code [exec]",
   "affected_versions": "every release from 2.4.0 through 10.6.0 (10.6.0 by reading) and main ea57360912ed; no version has a fix [exec] [read]. The UnifiedHighlighter weight-matches-off path (PhraseHelper subclasses WeightedSpanTermExtractor since 6.3.0, read) was executed on main and 10.5.2 only. 10.6.0 (released 2026-10-29) was read at 4ae946e5a9b, not executed. Every run used JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-397.html",
   "repro": "repro/LFV-397/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-401",
   "priority": "low",
   "priority_rank": 522,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / vectorhighlight BaseFragListBuilder (FastVectorHighlighter, SimpleFragListBuilder, WeightedFragListBuilder)",
   "title": "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)",
   "summary": "You index the field 'aaaaaaaaaaaaaaaaaaaa foo bbb foo ccc foo ddd' with term vectors (positions and offsets), search foo, and call FastVectorHighlighter.getBestFragments with fragCharSize = Integer.MAX_VALUE to get the whole field, expecting 'aaaaaaaaaaaaaaaaaaaa <b>foo</b> bbb <b>foo</b> ccc <b>foo</b> ddd', which fragCharSize 1000 or Integer.MAX_VALUE - 100 gives. Instead you get 'aaaaaaaaaaaaaaaaaaaa <b>foo</b> bbb foo ccc foo ddd', with no error: BaseFragListBuilder.createFieldFragList computes the fragment end as spanStart + fragCharSize in int, where spanStart is the first match's start minus the 6-char margin (15 here), so the sum wraps negative and the fragment closes at the end of the first match. The fragment is then re-centred to [0, Integer.MAX_VALUE), which covers the whole field, and every later match is discarded.",
   "impact_class": "silent wrong results",
   "introduced_commit": "9cbe5f4ff47815429f19776005674dac67464a80 (LUCENE-1522 'adding new Fast Vector Highlighter contrib', svn trunk r792542; pre-GitHub, a JIRA patch, no PR) wrote the unguarded sum 'int en = st + fragCharSize' in SimpleFragListBuilder [read]. The current symptom (whole field, only the first match highlighted) comes from LUCENE-1822 ('BaseFragListBuilder hard-coded 6 char margin is too naive', apache/lucene#2897), branch_4x commit e92d57762f1 (svn r1395848; trunk 15b7ffd6bf8f, r1395847), which added the re-centring that clamps the start to 0 and sets startOffset to Integer.MAX_VALUE after the wrapped first fragment [exec]. LUCENE-4899 (apache/lucene#5964; trunk 66580ef0749, branch_4x d291e242c28) rewrote the sum into today's lines 72 and 101 without changing the output [exec]. Not a regression: the sum has been unguarded since the class was written",
   "introduced_date": "2009-07-09 (9cbe5f4ff478, unguarded sum written); 2012-10-09 (LUCENE-1822, current symptom); 2013-04-05 (LUCENE-4899, current form of the two lines)",
   "first_affected_version": "2.9.0 [exec] (2009-09-23, the first release with FastVectorHighlighter; it throws StringIndexOutOfBoundsException on this input; run with the 2.9.0 tag's FastVectorHighlighter sources over the official lucene-core-2.9.0 jar, because Maven Central has no FastVectorHighlighter 2.9.0 artifact); the current symptom first in 4.1.0 [exec] (2013-01-21, the first release with LUCENE-1822); no earlier release has the API",
   "affected_versions": "every release that has FastVectorHighlighter, 2.9.0 through 10.6.0 (10.6.0 by reading), and main ea57360912ed, with three era-specific symptoms [exec, -ea, the same differential main() oracle in each era: 2.9.0 throws StringIndexOutOfBoundsException 'Range [15, -2147483634)'; 2.9.1, 3.0.0, 3.6.2 and 4.0.0 return one small fragment per match instead of one whole-field fragment, all matches highlighted; 4.1.0, 4.2.1, 4.3.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (also -da) return the whole field with only the first match highlighted; the controls Integer.MAX_VALUE - 100 and the last exact size Integer.MAX_VALUE - 15 match in every run] [exec: the finder's JUnit fails on main (-ea, -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails on main, 10.5.2 and 9.12.3 (-ea and -da)] [read: every 2.9.x and 3.x release tag has the unguarded 'int en = st + fragCharSize', and all 117 release tags from 4.3.0 to 10.5.2 contain today's two lines; lines 72 and 101 are unchanged on upstream main cf398bfb142c (2026-10-26), branch_10x and branch_10_6, and no open PR touches BaseFragListBuilder]. Releases between the executed ones were checked by source only. All runs used JDK 25.0.3",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-2464",
    "https://github.com/apache/lucene/issues/3538",
    "https://github.com/apache/lucene/issues/2897",
    "https://issues.apache.org/jira/browse/LUCENE-1822",
    "https://github.com/apache/lucene/issues/5964",
    "https://issues.apache.org/jira/browse/LUCENE-4899"
   ],
   "doc": "",
   "repro": "repro/LFV-401/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1091",
   "priority": "low",
   "priority_rank": 523,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / classic Highlighter (OffsetLimitTokenFilter, maxDocCharsToAnalyze)",
   "title": "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)",
   "summary": "You set Highlighter#setMaxDocCharsToAnalyze(60) on a 58-character text whose analysis stacks a synonym on every word and expect the TermQuery match 'cats' to be highlighted. Instead getBestFragment returns null: OffsetLimitTokenFilter counts the stacked tokens' lengths twice, stops after 15 tokens, and the Highlighter iterates that cut stream.",
   "impact_class": "minor",
   "introduced_commit": "unknown (not bisected); [read] since LUCENE-2939 (3.x)",
   "introduced_date": "unknown (not bisected)",
   "first_affected_version": "unknown (not bisected); 3.x by reading [read]; oldest executed 9.12.3 [exec]",
   "affected_versions": "9.12.3, 10.5.2, 10.6.0, main 645d4fe14a20 [exec]; main e1faeba08bde with -ea and -da [exec].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/7435",
    "https://issues.apache.org/jira/browse/LUCENE-6375",
    "https://github.com/apache/lucene/issues/7482",
    "https://issues.apache.org/jira/browse/LUCENE-6423"
   ],
   "doc": "",
   "repro": "repro/LFV-1091/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-859",
   "priority": "low",
   "priority_rank": 524,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / classic Highlighter fragmenting (SimpleSpanFragmenter.isNewFragment position counter; Highlighter.getBestTextFragments)",
   "title": "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",
   "summary": "You highlight 'Lucene is a search library written in Java' with the classic Highlighter, a QueryScorer for PhraseQuery 'search library', the default StandardAnalyzer and SimpleSpanFragmenter(scorer, 20), whose javadoc says it 'breaks text up into same-size fragments but does not split up Spans', and expect the 14-character phrase to stay in one fragment. Instead the fragments are 'Lucene is a <B>search</B>' | ' <B>library</B> written in Java' and getBestFragment returns 'Lucene is a <B>search</B>'; the same cut happens at the default fragment size 100 whenever the size threshold falls at the phrase's second word, and after a leading stop word or a word split by WordDelimiterGraphFilter the lag grows to two positions, so even three-word phrases are cut. The fragmenter counts positions only from the tokens the Highlighter shows it, and the Highlighter never shows it the first token or tokens that overlap the previous one, so it recognises the phrase one or more words late.",
   "impact_class": "silent wrong results",
   "introduced_commit": "c2f7d554a3e8886fc2781a7402fae746e4ee5ad2 (svn r713569, LUCENE-1389 / #2463 'SimpleSpanFragmenter can create very short fragments', committed by markrmiller, applying the reporter's positions.patch) for the headline plain-text trigger: it changed start() from 'position = 0' to 'position = -1' (today SimpleSpanFragmenter.java:100), stating 'so the first token position ends up 0 as it should', although the Highlighter never showed the fragmenter the first token [exec]. The root mechanism is older and not a regression: the counter that adds only the increments of the tokens it is shown came with the class, 35c7eb36dfb07ff919147d7570158433e48cd092 (svn r652164, LUCENE-794 / #1869, committed by markharwood, first released in 2.4.0), on top of the Highlighter loop that calls isNewFragment() only for the first token of each new distinct token group after the first group, 14f0da2aa20114f44026dbe845c222aa6b192683 (2004-07-26, 'support for analyzers that produce overlapping tokens') [read]",
   "introduced_date": "2008-11-13 (c2f7d554a3e, plain-text trigger); root mechanism 2008-04-29 (35c7eb36dfb, the class) and 2004-07-26 (14f0da2aa20, the Highlighter loop)",
   "first_affected_version": "2.9.0 [exec] for the headline plain-text trigger with default analysis (2.4.0 and 2.4.1 keep the plain-text phrase whole [exec]); 2.4.0 [exec], the first release with SimpleSpanFragmenter, already splits a phrase after a leading stop word, but only with stop-word position increments enabled (StopFilter.setEnablePositionIncrementsDefault(true), not the 2.4 default); 2.3.2 and earlier have no SimpleSpanFragmenter",
   "affected_versions": "Every release from 2.9.0 to 10.5.2, the branch_10_6 head 4ae946e5a9b9 (10.6.0, released 2026-10-29) and main a9779ef3c193 (unreleased 11.0) [exec]. 2.4.0 and 2.4.1 split only the leading-stop-word case, with stop-word position increments enabled [exec]. Releases between the executed ones are affected by inference (git tag --contains c2f7d554a3e lists every release tag from 2.9.0 on) [read]. Not fixed upstream: SimpleSpanFragmenter.java has the same blob (f41032e90dbf) on main c5ab3e57b9b, branch_10_6, branch_10x and the tested tree, and no open PR touches it [read]. Executed on Linux aarch64 with JDK 25 only.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/2463",
    "https://issues.apache.org/jira/browse/LUCENE-1389",
    "https://github.com/apache/lucene/issues/3305",
    "https://issues.apache.org/jira/browse/LUCENE-2229",
    "https://github.com/apache/lucene/issues/6083",
    "https://issues.apache.org/jira/browse/LUCENE-5019"
   ],
   "doc": "",
   "repro": "repro/LFV-859/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-861",
   "priority": "low",
   "priority_rank": 525,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / classic Highlighter fragmenting (SimpleSpanFragmenter.start, state carried across texts)",
   "title": "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",
   "summary": "You reuse one classic Highlighter with a QueryScorer and a SimpleSpanFragmenter for several texts (Highlighter keeps one fragmenter and calls its start(), documented as 'Initializes the Fragmenter', for every text) and expect each text to be cut into the same fragments as with a fresh Highlighter. Instead start() resets the position and fragment count but not waitForPos, the position the fragmenter is still waiting for, so when a phrase match ended the previous text no boundary is allowed in the next text until it reaches that old position: with the phrase 'search library' at the end of the first text and fragment size 20, the next text starts with one 70-character fragment 'Highlighting picks short fragments of text around each match so that a', then one-word fragments ', reader', ', of', ', the', where a fresh Highlighter gives 'Highlighting picks', ' short fragments of', ' text around each', and getBestFragment also differs. Hits and scores are unaffected; only the snippet layout changes, and it depends on what the same Highlighter highlighted before.",
   "impact_class": "minor",
   "introduced_commit": "35c7eb36dfb07ff919147d7570158433e48cd092 (svn r652164, 'Commit of LUCENE-794 patch - adding phrase/span query support to highlighter'; LUCENE-794 = apache/lucene#1869, patch by markrmiller, committed by markharwood; no CHANGES entry) [read]. Not a regression. Cross-text reuse became the normal usage in 2.9.0 (f73a4f43242 LUCENE-1695, Scorer.init per text; 10b41d2dce2 LUCENE-1685 / #2759, reusable QueryScorer); before that the leak shows on the documented repeat call on the same text after SpanScorer.reset()",
   "introduced_date": "2008-04-29 (35c7eb36dfb, author date = commit date 2008-04-29T22:07:18Z)",
   "first_affected_version": "2.4.0 [exec] (tagged 2008-10-08; 2.3.2, the last earlier release, has no SimpleSpanFragmenter: the history repro does not compile there)",
   "affected_versions": "Every release from 2.4.0 to 10.5.2, the branch_10_6 head 4ae946e5a9b9 (10.6.0, released 2026-10-29) and main a9779ef3c193 [exec]. Not fixed: no upstream commit to SimpleSpanFragmenter.java since 54fba99cb13 (author and commit date 2022-09-24, formatting) on main (head c5ab3e57b9b) or branch_10_6 [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-861.html",
   "repro": "repro/LFV-861/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-498",
   "priority": "low",
   "priority_rank": 526,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter default summary (FieldHighlighter.getSummaryPassagesNoHighlight over the SplittingBreakIterator that splits multi-valued fields on MULTIVAL_SEP_CHAR)",
   "title": "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",
   "summary": "You store two values in one field ('First value.' and 'Second value.'), run a query that matches the document but not that field, and ask the UnifiedHighlighter for 2 passages; you expect the documented default summary, the first 2 sentences from the field (for example 'First value.... Second value.', the way the highlight path joins values). Instead you get 'First value.\\u0000': the highlighter joins the values with an internal U+0000 separator, its SplittingBreakIterator reports a boundary on both sides of that character, and FieldHighlighter.getSummaryPassagesNoHighlight turns the 1-character gap into a passage, so the NUL is returned and takes the second value's slot (3 passages give 'First value.\\u0000Second value.'). With an empty first value even 1 passage returns just '\\u0000'.",
   "impact_class": "minor",
   "introduced_commit": "722e82712435ecf46c9868137d885484152f749b on master and its branch_6x twin 4b6794368df (LUCENE-7438 'New UnifiedHighlighter' by dsmiley, 2016-10-04; JIRA issue now GitHub #8490; the contribution PR apache/lucene-solr#79 by Timothy055 was closed without a GitHub merge, the code was committed directly) [read]. The commit added all three pieces the bug needs: the summary loop that makes a passage of every consecutive pair of boundaries, SplittingBreakIterator#next() reporting both sides of the separator, and UnifiedHighlighter wrapping every field iterator in a SplittingBreakIterator on MULTIVAL_SEP_CHAR = (char) 0. Later edits to the loop (LUCENE-7559 c51e89014ac, LUCENE-8145 9422609a5d4, #16056 dbf0d1426f1) are cosmetic. Not a regression",
   "introduced_date": "2016-10-04",
   "first_affected_version": "6.3.0 [exec] (first release with the UnifiedHighlighter, from branch_6x commit 4b6794368df; release commit a66a44513ee8, 2016-11-02); 6.2.1 has no org.apache.lucene.search.uhighlight package (the repro does not compile there) [exec]",
   "affected_versions": "every release with the UnifiedHighlighter, 6.3.0 through 10.6.0 (10.6.0 by reading), and main ea57360912ed [exec]; not affected: releases up to 6.2.1, which have no UnifiedHighlighter [exec]; not fixed upstream [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-498.html",
   "repro": "repro/LFV-498/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-494",
   "priority": "low",
   "priority_rank": 527,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter break iterators (LengthGoalBreakIterator#preceding under the SplittingBreakIterator that UnifiedHighlighter puts around every field's iterator, multi-valued fields)",
   "title": "UnifiedHighlighter with LengthGoalBreakIterator on a multi-valued field: a passage in a later value starts at the U+0000 value separator",
   "summary": "You highlight a field with two stored values, 'First value here.' and 'Second value here.', using UnifiedHighlighter.builder(...).withBreakIterator(() -> LengthGoalBreakIterator.createMinLength(sentence iterator, 10, 0.5f)), and expect the same snippet as with the plain sentence iterator, because each value is already one sentence longer than the goal: '<b>Second</b> value here.' for the query 'second'. Instead the passage starts one character early, on the internal U+0000 value separator ('\\u0000<b>Second</b> value here.'), and for 'first second' the two values come out joined by U+0000 instead of '... ' ('<b>First</b> value here.\\u0000<b>Second</b> value here.'). The cause is LengthGoalBreakIterator.preceding answering DONE (-1) for an offset inside the value, which the SplittingBreakIterator that UnifiedHighlighter always wraps around the iterator turns into the separator's index.",
   "impact_class": "minor",
   "introduced_commit": "4c9cc2cefd7f3593c4b4e1e5a087e3d206298989 on main and its branch_8x back-port 5874b9c7933233712da14c5a5b9bb4f916eb77f8 (both 2020-01-01, 'LUCENE-9093: UnifiedHighlighter LengthGoalBreakIterator frag align'; issue LUCENE-9093 'Unified highlighter with word separator never gives context to the left', now #10135; contributed as apache/lucene-solr#1123 by Traktormaster and committed by dsmiley with 'Closes #1123'): it replaced the pass-through LengthGoalBreakIterator.preceding with the fragment-alignment target, including both DONE returns (LengthGoalBreakIterator.java:201 and :208 on main), and changed FieldHighlighter to max(preceding(..), lastPassageEnd) [read] [exec]. A regression. The other half, SplittingBreakIterator.preceding returning sliceStartIdx + the base result (SplittingBreakIterator.java:221), dates from LUCENE-7438 (722e8271243, 6.3.0) and is correct for a base iterator that follows the BreakIterator contract",
   "introduced_date": "2020-01-01",
   "first_affected_version": "8.5.0 [exec] (8.4.1, the last release before LUCENE-9093, passes [exec]; on the main line 9.0.0 is the first release with the commit [exec]); LengthGoalBreakIterator first shipped in 6.4.0 (LUCENE-7620)",
   "affected_versions": "8.5.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.6.0 (10.6.0 by reading) and main ea57360912ed. [exec] fail: 8.5.0, 8.9.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) with the follow-up's version-portable probe (alignment 0, a 3-character term at a later value's start); the finder's repro fails on 9.1.0, 9.12.3, 10.5.2 and main; the independent reproduction's test fails on 8.5.0, 8.11.4, 9.12.3, 10.5.2 and main. [exec] pass: 6.4.0, 7.7.3 and 8.4.1. [read] git tag --contains places the commit in 8.5.0-8.8.1 and 9.0.0-10.5.2; 8.8.2, 8.10.x and 8.11.0-8.11.3 are branch_8x releases whose tags are not in the local history (8.9.0 and 8.11.4 were executed), so they are inferred. Not affected: 6.4.0-8.4.1 (pass-through preceding in all 34 release tags); the class does not exist before 6.4.0. Not fixed upstream: LengthGoalBreakIterator.java and SplittingBreakIterator.java are unchanged on upstream main a9779ef3c193 (2026-10-26), branch_10x and branch_10_6, and no open PR touches them [read]. Executed only on aarch64 Linux with JDK 25 (plain Java logic)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/10135",
    "https://issues.apache.org/jira/browse/LUCENE-9093",
    "https://github.com/apache/lucene-solr/pull/1123",
    "https://github.com/apache/lucene/issues/8490",
    "https://issues.apache.org/jira/browse/LUCENE-7438",
    "https://github.com/apache/lucene/issues/13832"
   ],
   "doc": "",
   "repro": "repro/LFV-494/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-887",
   "priority": "low",
   "priority_rank": 528,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / classic Highlighter formatters (GradientFormatter, SpanGradientFormatter)",
   "title": "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",
   "summary": "You build new GradientFormatter(maxScore, \"#FFFFFF\", \"#000000\", null, null), the javadoc's own example (white for a score of zero, black for maxScore and above), and highlight a term whose score is maxScore, expecting it to be drawn black. Instead it is drawn white (<font color=\"#FFFFFF\">) and weaker terms get darker colours, because getColorVal always runs from the numerically smaller channel value to the larger one, whatever order the min and max colours were given in. The same happens on every colour channel where min > max, in GradientFormatter and in SpanGradientFormatter, which inherits the method.",
   "impact_class": "minor",
   "introduced_commit": "c5b61e1671703e5c8f943931591321ab959237ed 'New GradientFormatter, TermVector helper class and IDF-based fragment scoring' (author recorded in git as Mark Harwood; a direct SVN commit, trunk r151021, to the highlighter sandbox, with no issue or PR) [read]. Not a regression: the defect is in the class's first version. SpanGradientFormatter, which inherits getColorVal, was added in 613414de820 (2005-01-07).",
   "introduced_date": "2004-12-31 (c5b61e16717, author and commit date 2004-12-31T11:22:27Z)",
   "first_affected_version": "1.9 [read] (the first release with the highlighter: tags 1.9-rc1 2006-02-21 and 1.9 2006-02-27; no 1.9 highlighter artifact exists on Maven Central, so the oldest executed release is 1.9.1 [exec]; 1.4.3, the last release before the commit, has no highlighter at all, so no earlier release is unaffected: the API did not exist)",
   "affected_versions": "every release from 1.9 through 10.5.2, plus the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193. [exec] a portable main() (protected getForeground/BackgroundColorString reached from a subclass, signatures unchanged since 2005) fails 6 of 7 checks, with the ascending control passing, on 1.9.1, 2.0.0, 2.9.4, 3.0.3, 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the finder's public-API JUnit fails 2 of 2 on 9.1.0, 9.12.3, 10.0.0, 10.5.2, branch_10_6 and main (-ea and -da; on 9.0.0 it does not compile because of the pre-9.1 test-framework package names, a harness limitation, not a pass); the independent reproduction's JUnit fails 4 of 5 on main (-ea and -da), 10.5.2 and 9.12.3. [read] the other releases (the getColorVal formula is identical in every release tree).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/11762",
    "https://github.com/apache/lucene/issues/15781",
    "https://github.com/apache/lucene/issues/5852",
    "https://issues.apache.org/jira/browse/LUCENE-4787",
    "https://github.com/apache/lucene/issues/1418",
    "https://issues.apache.org/jira/browse/LUCENE-340"
   ],
   "doc": "",
   "repro": "repro/LFV-887/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-858",
   "priority": "low",
   "priority_rank": 529,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / classic Highlighter fragmenting (SimpleSpanFragmenter.isNewFragment; Highlighter.getBestTextFragments)",
   "title": "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",
   "summary": "You highlight a text with the classic Highlighter, a QueryScorer and SimpleSpanFragmenter, whose javadoc says it 'breaks text up into same-size fragments but does not split up Spans', for a query with two overlapping phrases ('new york' OR 'york city hall'), two phrases that share a start ('new york' OR 'new york city hall'), or a phrase whose words get synonyms stacked on them by SynonymGraphFilter, and you expect every phrase match shorter than the fragment size to stay inside one fragment. Instead the fragmenter cuts inside the longer phrase ('The museum is near New York City' | ' Hall and the park', 'We flew to New York City' | ' Hall last week', 'I left my big laptop' | ' bag on the train'), so getBestFragment can return only part of the phrase, and in the same-start case listing the longer phrase first in the BooleanQuery makes the phrase come out whole. Hits, scores and which words are highlighted are correct; only the fragment boundaries are wrong.",
   "impact_class": "minor",
   "introduced_commit": "35c7eb36dfb07ff919147d7570158433e48cd092 (svn r652164, 'Commit of LUCENE-794 patch - adding phrase/span query support to highlighter', committed by markharwood; the SimpleSpanFragmenter patch series is by markrmiller; JIRA LUCENE-794 = #1869) [read]. Not a regression: present since the class was added; checked at release granularity by execution (2.3.2 has no such class, 2.4.0 fails, and the 2.4.0 source with only the span-bookkeeping fix backported passes on the 2.4.0 jars). The stacked-token leg also relies on Highlighter calling the fragmenter only for the first token of each token group, which predates the fragmenter (14f0da2aa20, 2004-07-26, first release 1.9) [read]",
   "introduced_date": "2008-04-29 (35c7eb36dfb, svn r652164); the 'break' form of the first-match rule 2008-11-13 (c2f7d554a3e, LUCENE-1389)",
   "first_affected_version": "2.4.0 [exec] (released 2008-10-08; 2.3.2, the last release before the introducing commit, has no SimpleSpanFragmenter: the port fails to compile on the missing class)",
   "affected_versions": "Every release from 2.4.0 to 10.5.2, the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193 [exec]. Not fixed: SimpleSpanFragmenter.java is byte-identical (blob f41032e9) in 9.12.3, 10.0.0, 10.5.2, branch_10_6, branch_10x and main, and its last behavioural change is LUCENE-2229 (ec64ba00299, 2015-12-29) [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-858.html",
   "repro": "repro/LFV-858/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-599",
   "priority": "low",
   "priority_rank": 530,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter (multi-value joining with the in-band MULTIVAL_SEP_CHAR U+0000: SplittingBreakIterator, ANALYSIS re-analysis)",
   "title": "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",
   "summary": "You store and index one text value that contains a U+0000 character, for example 'ab\\u0000cd' in a KeywordAnalyzer field, find it with a TermQuery for that exact value and highlight the hit with the default UnifiedHighlighter; you expect the same snippet as for the twin value with U+0001, which has identical postings and is highlighted as '<b>ab\\u0001cd</b>'. Instead the highlighter, which joins a field's values with U+0000 internally and then searches for U+0000 to find where values end, takes the character for a boundary between two values: the snippet ends there, and the ANALYSIS offset source re-analyzes 'ab' and 'cd' separately, finds no match and returns the plain summary 'ab'.",
   "impact_class": "silent wrong results",
   "introduced_commit": "722e82712435ecf46c9868137d885484152f749b (master) and its branch_6x cherry-pick 4b6794368df373df1f68ccf27f7556914efeb95e (shipped in 6.3.0): LUCENE-7438 'New UnifiedHighlighter' (issue apache/lucene#8490; code from apache/lucene-solr#79 by GitHub Timothy055, committed by GitHub dsmiley), which added MULTIVAL_SEP_CHAR = (char) 0, the unchecked join in LimitedStoredFieldVisitor, the SplittingBreakIterator on that char and MultiValueTokenStream's indexOf split [read]",
   "introduced_date": "2016-10-04",
   "first_affected_version": "6.3.0 [exec], the first release with the UnifiedHighlighter; no earlier version is unaffected in the strict sense because the API did not exist (6.2.1 has no uhighlight package; its predecessor PostingsHighlighter joins values with ' ' and treats U+0000 like U+0001 [exec])",
   "affected_versions": "every release from 6.3.0 through 10.6.0 (10.6.0 by reading) and main a9779ef3c193. [exec] 4/4 cases reproduce on 6.3.0, 6.4.0, 6.6.6, 7.0.0, 7.2.1, 7.3.0, 7.4.0, 7.5.0, 7.7.3, 8.0.0, 8.4.1, 8.5.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea; -da also on 6.3.0, 9.12.3, 10.5.2 and main). [exec] the finder's JUnit fails 3/3 on main (-ea, -da), 10.5.2 and 9.12.3; the independent reproduction's fails 3/4 on main (-ea, -da), 10.5.2 and 9.12.3; the intended-behaviour check's KeywordAnalyzer JUnit fails 1/2 on main (-ea, -da; its U+0001 control passes). The symptom shape varies (before 9.0.0 a phrase is highlighted per term; 7.5.0-8.4.1 also clip a POSTINGS match that spans the U+0000); the split itself does not. [read] git tag --contains covers the releases between the sampled points; upstream branch_10x and branch_10_6 carry the same code; not fixed on upstream main a95c754ee003 (2026-10-26). Releases were run on JDK 25.",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-7719",
    "https://github.com/apache/lucene/issues/8770",
    "https://github.com/apache/lucene/issues/8490",
    "https://issues.apache.org/jira/browse/LUCENE-7438",
    "https://github.com/apache/lucene/issues/8577",
    "https://issues.apache.org/jira/browse/LUCENE-7526"
   ],
   "doc": "",
   "repro": "repro/LFV-599/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-783",
   "priority": "low",
   "priority_rank": 531,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter (multi-valued content: postings and term-vector offset sources vs Analyzer#getOffsetGap; LimitedStoredFieldVisitor value join)",
   "title": "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",
   "summary": "You index a field with two values, 'alpha one' and 'beta two', with an analyzer whose offset gap is 3 (for example CustomAnalyzer.builder().withOffsetGap(3)) and offsets in the postings or term vectors, then highlight the hits of body:beta and body:two with the UnifiedHighlighter; you expect '<b>beta</b> two' and 'beta <b>two</b>', as with the default gap of 1. Instead you get 'be<b>ta t</b>wo' and the unhighlighted 'alpha one', because indexing put the second value 3 characters after the first while the highlighter rebuilds the text with a single separator character between values, so every offset in the second value points 2 characters too far. The re-analysis offset source rejects the same analyzer with an IllegalArgumentException; the postings and term-vector sources accept it and return wrong snippets silently.",
   "impact_class": "silent wrong results",
   "introduced_commit": "722e82712435ecf46c9868137d885484152f749b (master) and its branch_6x cherry-pick 4b6794368df373df1f68ccf27f7556914efeb95e (shipped in 6.3.0): LUCENE-7438 'New UnifiedHighlighter' (issue apache/lucene#8490; code from apache/lucene-solr#79 by GitHub Timothy055, committed by GitHub dsmiley), which already contains the one-character join in LimitedStoredFieldVisitor.stringField (UnifiedHighlighter.java:948 at 4b6794368df, :1463 on main), the loadFieldValues javadoc 'must be identical to what was indexed (at least for postings or term-vectors offset sources)' and the gap-1 check on the re-analysis path only [read] [exec]. The one-character join as a stand-in for the offset gap is older: the PostingsHighlighter (LUCENE-4290, 4.1.0, f2d1557c5d1) appended ' ' with the comment '// for the offset gap, TODO: make this configurable', and LUCENE-5087 (4.4.0) made only the character configurable [read]",
   "introduced_date": "2016-10-04",
   "first_affected_version": "6.3.0 [exec], the first release with the UnifiedHighlighter; 6.2.1 has no uhighlight package (API absent, a compile error, not a result about the bug). Its predecessor PostingsHighlighter has the same defect [exec]",
   "affected_versions": "every release from 6.3.0 through 10.5.2 (the last release before 10.6.0) and main a9779ef3c193. [exec] defect present in all 87 releases from 6.3.0 to 10.5.2 and on main (-ea; -da also on 6.3.0, 9.12.3, 10.5.2 and main); the gap-1 and gap-3 lines are byte-identical to main in every release; the gap-0 output is wrong everywhere but its text varies by range ('<b>\\u0000bet</b>' 6.3.0-7.4.0, '<b>\\u0000</b>' 7.5.0-8.4.1, '<b>\\u0000bet</b>a two' 8.5.0 to main) because passage boundaries changed. [exec] the finder's JUnit fails 3 of 5 on main (-ea, -da), 10.5.2, 10.0.0, 9.12.3 and 9.1.0, and adapted on 9.0.0 and 6.3.0; the independent reproduction's JUnit fails 4 of 6 on main (-ea, -da), 10.5.2 and 9.12.3. Released 10.6.0 (4ae946e5a9b): the finder's JUnit fails 3 of 5 with -da (seed DEADBEEF), the same three tests and messages as on main [exec]. Not fixed: upstream main f7bcc0abd816 (2026-10-27) has no highlighter commit after a9779ef3c193, the last commit under uhighlight/ is 54283150a816 (2026-06-14, build tooling), and no open PR changes the value join or adds a gap check [read].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/8322",
    "https://issues.apache.org/jira/browse/LUCENE-7267",
    "https://github.com/apache/lucene/issues/8490",
    "https://issues.apache.org/jira/browse/LUCENE-7438",
    "https://github.com/apache/lucene/issues/8577",
    "https://issues.apache.org/jira/browse/LUCENE-7526"
   ],
   "doc": "",
   "repro": "repro/LFV-783/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-913",
   "priority": "low",
   "priority_rank": 532,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter re-analysis without a searcher (highlightWithoutSearcher: MemoryIndexOffsetStrategy reader == null branch + WEIGHT_MATCHES)",
   "title": "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",
   "summary": "You build a UnifiedHighlighter without a searcher (builderWithoutSearcher, default flags) and call highlightWithoutSearcher(\"body\", query, \"a b c\", 1) with +title:x +body:a or +body:a #year:[2000 TO 2030], expecting '<b>a</b> b c', which highlight() gives for the same text on an indexed one-document copy, which the same call gives with withWeightMatches(false), and which 8.x gave by default. Instead it returns 'a b c' with no mark: under WEIGHT_MATCHES the whole query's Weight#matches runs on a MemoryIndex that holds only the highlighted field, where the other-field clause cannot match, so Matches is null ('doc doesn't match') and the highlighter falls back to the unmarked summary. The searcher path answers other-field clauses from the real index (OverlaySingleDocTermsLeafReader); the no-searcher branch has no such view, so a clause it cannot evaluate is treated as false.",
   "impact_class": "silent wrong results",
   "introduced_commit": "2719cf6630eb2bd7cb37d0e8462dc912d8fafd83 (LUCENE-9431 'UnifiedHighlighter WEIGHT_MATCHES is now true by default', apache/lucene#362, GitHub issue #10471; main only, never on branch_8x) exposes the bug under default flags [exec]. The code that drops the marks is older: b19ae942f154924b9108c4e0409865128f2a07d4 (LUCENE-8286, GitHub issue #9333, author dsmiley; branch_7x backport bf7d1078e4ef6c99abaf5c76eccf56ed0f09f553), which added HighlightFlag.WEIGHT_MATCHES, FieldOffsetStrategy.createOffsetsEnumsWeightMatcher and the reader == null branch of MemoryIndexOffsetStrategy.getOffsetsEnum together [read]; before 9.0.0 it was reachable only when the caller turned WEIGHT_MATCHES on",
   "introduced_date": "2021-10-22 (LUCENE-9431 commit, author and commit date); mechanism 2018-08-29 (LUCENE-8286 commit, author date)",
   "first_affected_version": "9.0.0 [exec] with default flags (LUCENE-9431); 7.5.0 [exec] for callers who turned WEIGHT_MATCHES on (LUCENE-8286); 6.3.0 to 7.4.0 have highlightWithoutSearcher but no WEIGHT_MATCHES flag, so they cannot reach the code [read]",
   "affected_versions": "Default flags: every 9.x and 10.x release from 9.0.0 to 10.5.2 (all 33 run with the portable history probe: fail), the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193 [exec]. 7.5.0 to 8.11.4 keep the marks with default flags (22 of the 33 releases in that range run: pass; the 11 bug-fix releases not run are assumed the same) and lose them when WEIGHT_MATCHES is turned on (every run). 7.4.0 and earlier are not affected (no WEIGHT_MATCHES flag). Not fixed upstream: upstream main c5ab3e57b9ba is 5 commits ahead of a9779ef3c193 and none touches lucene/highlighter or lucene/memory [read].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/362",
    "https://github.com/apache/lucene/issues/9333",
    "https://issues.apache.org/jira/browse/LUCENE-8286",
    "https://github.com/apache/lucene/issues/10471",
    "https://issues.apache.org/jira/browse/LUCENE-9431",
    "https://github.com/apache/lucene/issues/10751"
   ],
   "doc": "",
   "repro": "repro/LFV-913/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-775",
   "priority": "low",
   "priority_rank": 533,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter stored-value loading (LimitedStoredFieldVisitor maxLength cut)",
   "title": "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'",
   "summary": "You store the value 'Hello U+1F600 world' (the emoji takes UTF-16 indexes 6 and 7), search for hello and highlight the hit with UnifiedHighlighter.builder(searcher, analyzer).withMaxLength(7), and expect a snippet made of whole characters, '<b>Hello</b> ', just as maxLength 6 gives '<b>Hello</b> ' and maxLength 8 gives the whole emoji. Instead LimitedStoredFieldVisitor keeps exactly 7 UTF-16 units, so the content and the snippet end with the first half of the emoji, '<b>Hello</b> \\uD83D', which String.getBytes(UTF_8) turns into '<b>Hello</b> ?' and a strict UTF-8 encoder rejects. The same happens at the default maxLength 10,000 when a value's 10,000th unit is the first half of a supplementary character, and for a later value of a multi-valued field at its per-value budget.",
   "impact_class": "minor",
   "introduced_commit": "722e82712435ecf46c9868137d885484152f749b (LUCENE-7438 'New UnifiedHighlighter', migrated as apache/lucene#8490, fix version 6.3; pull request apache/lucene-solr#79 by Timothy055, closed without a GitHub merge; committed by dsmiley on master, first released in 7.0.0) and its same-day branch_6x cherry-pick 4b6794368df373df1f68ccf27f7556914efeb95e, which first ships in 6.3.0: it added LimitedStoredFieldVisitor with both cut lines [read]. Not a regression: the class had the defect in its first version. The same unchecked cut is older than the class: its predecessor PostingsHighlighter (LUCENE-4290, 6ac21f776c7 on branch_4x / f2d1557c5d1 on trunk, rmuir, 2012-12-11, first released in 4.1.0; removed in 7.0.0 by LUCENE-7815) cut with append(value, 0, maxLength - builder.length()) [exec]; that class is gone, so it is lineage, not part of this row.",
   "introduced_date": "2016-10-04 (LUCENE-7438); the predecessor PostingsHighlighter cut dates from 2012-12-11 (LUCENE-4290)",
   "first_affected_version": "6.3.0 [exec]: the first release with the UnifiedHighlighter (branch_6x cherry-pick 4b6794368df); 6.2.1 has no UnifiedHighlighter [exec]. Lineage only: PostingsHighlighter had the same cut from 4.1.0 until its removal in 7.0.0 [exec].",
   "affected_versions": "every release from 6.3.0 to 10.5.2 (all 87 releases: 6.3.0-6.6.6, 7.0.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2), 10.6.0 (by reading) and main a9779ef3c193 (unreleased 11.0); never fixed upstream. [exec] the follow-up's version-portable probe UhMaxLengthSurrogateHistoryProbe (constructor plus setMaxLength, NIOFSDirectory; the candidate's 5 scenarios plus 2 controls with the cut next to the emoji) is affected 5 of 5 on 6.3.0 (-ea and -da), 6.6.6, 7.0.0, 7.2.1, 7.3.0, 7.4.0, 7.5.0, 7.6.0, 7.7.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da), with both controls well-formed and highlighted on every version; the candidate JUnit (builder API, so 9.1.0 and later) fails 5 of 5 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the independent reproduction's JUnit fails 6 of 6 on main (-ea and -da), 10.5.2 and 9.12.3. [read] both cut lines and no surrogate handling at all 78 tagged releases from 6.3.0 to 10.5.2 in the history clone (8.8.2-8.11.3 are not tagged there; they lie between 8.8.1 [read] and 8.11.4 [exec]); upstream main a95c754ee003 (2026-10-26, the latest local fetch), branch_10x, branch_10_6 and branch_10_5 keep both lines (UnifiedHighlighter.java:1447 and :1464). The secondary lost-highlight symptom (a short re-analyzed value with StandardAnalyzer) appears only from 7.7.0 (7.6.0 keeps the highlight), which is LFV-158's boundary; the unpaired surrogate itself is present from 6.3.0 on.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-775.html",
   "repro": "repro/LFV-775/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-756",
   "priority": "low",
   "priority_rank": 534,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter (highlightWithoutSearcher entry point, maxLength option)",
   "title": "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",
   "summary": "You build a UnifiedHighlighter without a searcher (builderWithoutSearcher, optionally withMaxLength(20)) and call highlightWithoutSearcher on a text longer than maxLength, expecting the text to be cut to its first maxLength chars before highlighting, as getMaxLength ('Content will be truncated to this size before highlighting') and withMaxLength document and as the searcher entry points do. Instead the whole text is analyzed and highlighted: with maxLength 20, the 48-char text 'Alpha beta gamma. Delta epsilon. Lucene is here.' gives '<b>Lucene</b> is here.' (its only match is at offset 33) where the searcher path returns 'Alpha beta gamma. ', and with the default maxLength of 10,000 a match at char 10,541 of a 10,560-char text is highlighted. The only truncation lives in the stored-field loader (LimitedStoredFieldVisitor), which this entry point never calls, although the re-analysis strategy it uses relies on it ('content is already truncated to maxLength').",
   "impact_class": "minor",
   "introduced_commit": "722e82712435ecf46c9868137d885484152f749b (LUCENE-7438 'New UnifiedHighlighter', GitHub issue #8490; proposed as apache/lucene-solr#79, which was closed without a GitHub merge, and committed directly; branch_6x backport 4b6794368df) [read]: the method passes content untruncated since it was created, so this is not a regression. The same commit added the getMaxLength javadoc and the 'content is already truncated to maxLength' comment; LUCENE-10197 (#412, b1b1a890d08 / a9f812c1cf9, 9.1.0) later added the withMaxLength javadoc on the Builder that builderWithoutSearcher returns. Later edits to the method (2e948fea300 LUCENE-7575 SortedSet to Set, 6faa4f98e04 LUCENE-9570 formatting) did not touch truncation",
   "introduced_date": "2016-10-04",
   "first_affected_version": "6.3.0 [exec]; on the main line 7.0.0",
   "affected_versions": "Every release from 6.3.0 to 10.5.2, 10.6.0 (by reading), and main a9779ef3c193; never fixed (the method body is unchanged at upstream main f7bcc0abd816, branch_10x and branch_10_6; no open PR touches it; read 2026-10-27). [exec] a cross-version probe (original non-Builder API, recording PassageFormatter, searcher-path and large-maxLength controls) fails on 6.3.0 (-ea and -da), 6.4.0, 6.6.6, 7.0.0, 7.7.3, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the finder's Builder-API JUnit fails on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the independent reproduction's JUnit fails on 10.5.2 (-ea and -da), 9.12.3 and main, and its old-API main() on 8.11.4 and 6.3.0. Releases in between are affected by code identity [read]; 10.6.0 (released 2026-10-29) and the unreleased 10.7 branch were read, not executed.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-756.html",
   "repro": "repro/LFV-756/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-496",
   "priority": "low",
   "priority_rank": 535,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter break iterators (CustomSeparatorBreakIterator, alone or as the base of LengthGoalBreakIterator)",
   "title": "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",
   "summary": "You give the UnifiedHighlighter a CustomSeparatorBreakIterator('.'), alone or inside LengthGoalBreakIterator, and expect passages to start and end at the breaks its own next() reports, just after each '.'. Instead following() and preceding() are off by one next to the separator: on 'Aa bb. Cc dd. Ee ff' (breaks 0, 6, 13, 19) following(5) returns 13 instead of 6 and preceding(13) returns 13 instead of 6, so a min-length-6 summary is 'Aa bb. Cc dd.' instead of 'Aa bb.' and the phrase 'dd ee' is shown as '<b>dd. Ee</b> ff' instead of ' Cc <b>dd. Ee</b> ff'. Nothing throws and the match is still highlighted; only the snippet boundary moves by one segment.",
   "impact_class": "minor",
   "introduced_commit": "6d5f86105e8358ab4b8a1a1c9644a036c06a9816 (trunk, 'LUCENE-6485: Add CustomSeparatorBreakIterator', svn r1682114), first shipped through the branch_5x backport 83358bfd1f8e5c25bb3ec640e16dc48b221bd15f (svn r1682115); LUCENE-6485 (apache/lucene#7544, a JIRA patch, no PR) [read]. The UnifiedHighlighter-visible effects came later, when callers began to use the wrong answers: the min-length overshoot with LengthGoalBreakIterator (LUCENE-7620, 6.4.0), and the phrase-passage start loss with LUCENE-9093's center-based preceding() call (8.5.0, with WEIGHT_MATCHES opt-in) and LUCENE-9431's WEIGHT_MATCHES default (9.0.0) [exec]",
   "introduced_date": "2015-05-27 (both commits)",
   "first_affected_version": "5.3.0 [exec]; last unaffected 5.2.1, where the class does not exist [exec]",
   "affected_versions": "every release from 5.3.0 to 10.5.2, and main ea57360912ed. [exec] the iterator probe fails with the same 6 of 7 contract checks on 5.3.0, 6.6.6, 7.0.0, 8.11.4, 9.12.3, 10.5.2 and main (-ea and -da); the finder's JUnit fails 4 of 4 on 9.12.3, 10.5.2 and main (-ea, -da); the independent reproduction's JUnit fails 8 of 11 on main, 10.5.2 and 9.12.3 and the independent reproduction's main() probe fails on 8.11.4 and 7.7.3; the UnifiedHighlighter differential shows the min-length summary overshoot on 6.4.0, 7.5.0, 8.4.1, 8.5.0, 8.11.4, 9.0.0 and 9.12.3, the phrase start loss from 8.5.0 (WEIGHT_MATCHES forced) and with default flags from 9.0.0. [read] with comments, whitespace and the package line removed, the class is byte-identical in all 94 tagged releases 5.3.0..10.5.2 of the history clone (8.9.0-8.11.4 are untagged there; 8.11.4 was executed). Not fixed upstream: the file was last changed on 2020-12-18 (formatting only) and no open PR touches it [read]. PostingsHighlighter-level effects (5.3-6.6) were not executed. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/8671",
    "https://github.com/apache/lucene/issues/10135",
    "https://github.com/apache/lucene/issues/8780",
    "https://github.com/apache/lucene/issues/7544",
    "https://issues.apache.org/jira/browse/LUCENE-7620",
    "https://issues.apache.org/jira/browse/LUCENE-9093"
   ],
   "doc": "",
   "repro": "repro/LFV-496/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-622",
   "priority": "low",
   "priority_rank": 536,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / opennlp OpenNLPSentenceBreakIterator (java.text.BreakIterator implementation, next(int))",
   "title": "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",
   "summary": "You set a text on an OpenNLPSentenceBreakIterator and call next(n) to jump n sentence boundaries, expecting the n-th boundary, as java.text.BreakIterator#next(int) promises ('Returns the nth boundary from the current boundary') and as n calls of next() give. When that boundary is the end of the text, next(n) returns DONE (-1) instead: with the model-free NLPSentenceDetectorOp on 'Whole text is one sentence.', next() from first() returns 27 but next(1) returns -1, and on the module's three-sentence test text (boundaries 0, 31, 59, 102) next(3) from first() returns -1 instead of 102 while next(2) correctly returns 59. The iterator is still moved to the end, so only the returned value is wrong; code that steps with next(n) until DONE loses the final sentence group.",
   "impact_class": "minor",
   "introduced_commit": "b720e1ee3a524034fb8a8a6188b0b23bf17ff1cb (branch_7x, the commit in the first affected release 7.3.0) and 3e2f9e62d772218bf1fcae6d58542fad3ec43742 (master, first released in 8.0.0), both 'LUCENE-2899: Add OpenNLP Analysis capabilities as a module', committed by sarowe on 2017-12-15 (JIRA patch era, migrated as apache/lucene#3973, no GitHub PR) [read]. Not a regression: the defect was born with the class; the later commits on the file (7f8b7ffbcad LUCENE-9570 reformat, 44fa35b65ff #13170 preceding() fix, b0ebaaed565 #14216 errorprone) do not touch next() or next(int)",
   "introduced_date": "2017-12-15 (both commits)",
   "first_affected_version": "7.3.0 [exec]; 7.2.1 and earlier have no analysis-opennlp module (API absent [exec]); the master commit first shipped in 8.0.0",
   "affected_versions": "every release from 7.3.0 through 10.6.0 (7.3.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.6.0; 10.6.0 by reading) and main a9779ef3c193; never fixed. [exec] the follow-up's version-neutral main() probe NextNHistoryProbe gives identical failing output (model-free one sentence: next() = 27, next(1) = -1; the release's own test sentence model on three sentences: next(3) = -1 instead of 102; controls next(4) == DONE, next(2) == 59, next(-2) == 0 hold) on 7.3.0, 7.3.1, 7.4.0, 7.5.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da), under OpenNLP tools 1.8.3 to 2.5.12; the finder's JUnit fails 2 of 3 on main (-ea and -da), 10.5.2, 9.12.3 and 9.4.2; the independent reproduction's JUnit fails 4 of 5 on main (-ea and -da) and 10.5.2, and its 3 model-free tests fail on 9.12.3; the intended-behaviour check's JUnit fails 3 of 7 on main (-ea and -da) and 10.5.2. [read] every release tag 7.3.0..10.5.2 in the history clone has a next(int) body identical (whitespace-normalised) to main's; 8.8.2-8.11.3 are untagged in the clone and bracketed by 8.8.1 [read] and 8.11.4 [exec]; the heads branch_10_6 2763db11b0a (before 10.6.0 RC1; file unchanged at 4ae946e5a9b) and the unreleased branch_10x 1309534296e are identical [read]. Not affected: 7.2.1 and earlier (API absent). Executed only on aarch64 Linux with JDK 25.0.3 (pure Java logic)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-622.html",
   "repro": "repro/LFV-622/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-623",
   "priority": "low",
   "priority_rank": 537,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-opennlp / OpenNLPSentenceBreakIterator (public java.text.BreakIterator over OpenNLP sentence spans: setText, previous, following, moveToSentenceAt)",
   "title": "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",
   "summary": "You create an OpenNLPSentenceBreakIterator, give it a text that starts with whitespace, for example ' Sentence number 1 has 6 words. Sentence number 2, 5 words.', and walk it backward with last()/previous() (the reverse loop shown in the BreakIterator javadoc), expecting the forward boundaries [0, 33, 60] in reverse order and then DONE. Instead previous() returns 2, which is not a boundary, and the next previous() throws ArrayIndexOutOfBoundsException (Index -1); following(0) on a one-sentence text with leading whitespace recurses until StackOverflowError. The OpenNLP sentence detector trims whitespace from its spans and setText stores those starts unchanged, so the first stored sentence start lies after the begin index that first() and next() treat as the first boundary.",
   "impact_class": "crash",
   "introduced_commit": "b720e1ee3a524034fb8a8a6188b0b23bf17ff1cb on branch_7x (first release 7.3.0) and 3e2f9e62d772218bf1fcae6d58542fad3ec43742 on master (first release 8.0.0), both 'LUCENE-2899: Add OpenNLP Analysis capabilities as a module' (committed by sarowe; patch-era JIRA issue LUCENE-2899, migrated as apache/lucene#3973, no GitHub PR), with the same file blob f69fbc6b: the class was added with this defect. [read]",
   "introduced_date": "2017-12-15 (both commits); first release 7.3.0, tagged 2018-04-04",
   "first_affected_version": "7.3.0 (tagged 2018-04-04), the first release with the analysis/opennlp module [exec]. No release is unaffected: 7.2.1 and older do not have the class (API absent; executed as a setup error, no module artifact)",
   "affected_versions": "Every release from 7.3.0 through 10.6.0 (69 releases through 10.5.2, and 10.6.0 by reading) and main a9779ef3c193; never fixed. [exec] the follow-up's history probe (backward walk and following(0) on one and two sentences after two leading spaces, each release with its own test sentence model; the controls without leading whitespace pass) fails on 7.3.0 (-ea and -da), 7.4.0, 7.5.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da), with every bundled opennlp-tools version from 1.8.3 to 2.5.12 (the detector trims the leading whitespace in all of them); the finder's JUnit fails on 9.1.0, 9.4.2, 9.12.3, 10.0.0, 10.5.2 and main; the independent reproduction's JUnit fails on main (-ea and -da), 10.5.2 and 9.12.3 (on 9.12.3 its preceding() checks hit the separate #12210 crash first, which #13170 fixed in 10.0.0; the other parts reproduce). [read] at all 60 release tags from 7.3.0 to 10.5.2 in the local history clone, first, next, last, following, moveToSentenceAt, previous and setText match main once comments and whitespace are removed (only preceding() differs before 10.0.0, not on a failing path); 8.8.2-8.11.3 are inferred (tags not in the clone; bracketed by 8.8.1, read, and 8.11.4, executed); branch_10_5, branch_10_6, branch_10x and upstream main a95c754ee00 (2026-10-26) carry the same file blob af1ada42 (not executed); the 7 commits ea57360912ed..a9779ef3c193 do not touch lucene/analysis/opennlp. Not executed: x86 (pure Java logic). JDK 25.0.3, aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-623.html",
   "repro": "repro/LFV-623/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-180",
   "priority": "low",
   "priority_rank": 538,
   "novelty": "new",
   "withheld": false,
   "area": "search / CachingCollector first pass and score-caching replay (CachingCollector, CachingCollectorManager)",
   "title": "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",
   "summary": "You wrap a FacetsCollector, or any collector that does its per-segment work in LeafCollector#finish, in a CachingCollector or CachingCollectorManager so you can run the query once and replay the hits later, or you replay a score-caching cache into such a collector, and you expect the same facet counts as a plain IndexSearcher search. Instead the collector reports no hits: CachingCollector's per-leaf wrapper overrides finish() for its own bookkeeping and never passes the call on, and the score-caching replay never calls finish() at all, although the no-score replay does. In the repro a query that matches 20 documents gives 0 matching docs, with no error unless assertions are enabled.",
   "impact_class": "silent wrong results",
   "introduced_commit": "de07bdd88dd1 (branch_9x, released in 9.8.0) and 8811f31b9ca6 (main, released from 10.0.0), the same patch: #12380 'Add a post-collection hook to LeafCollector.' by jpountz, merged 2023-06-30 (closes #12375) [exec]; that commit added LeafCollector#finish and the forwarding FilterLeafCollector#finish, replaced CachingCollector's old postCollection() bookkeeping with a NoScoreCachingLeafCollector#finish override that does not call super.finish(), added collector.finish() to the no-score replay only (ScoreCachingCollector#collect, which overrides it, was not touched), and moved FacetsCollector's MatchingDocs recording into finish() [read]; the CachingCollectorManager entry point 3afffeef5a8d (#16247, by gaobinlong, merged 2026-07-08, first released in 10.6.0) inherits it [exec]",
   "introduced_date": "2023-06-30 (#12380, both commits); 2026-07-08 (#16247, CachingCollectorManager entry point, first released in 10.6.0)",
   "first_affected_version": "9.8.0 [exec] (first main-line release: 10.0.0 [exec]); 9.7.0 is the last release without the bug [exec]: LeafCollector#finish did not exist there and FacetsCollector recorded MatchingDocs without it, which works through CachingCollector; CachingCollectorManager: 10.6.0 (released 2026-10-29; listed under 10.6.0 in CHANGES.txt)",
   "affected_versions": "every release from 9.8.0 to 10.5.2 (all 23: 9.8.0, 9.9.0-9.9.2, 9.10.0, 9.11.0-9.11.1, 9.12.0-9.12.3, 10.0.0-10.5.2), 10.6.0 (10.6.0 by reading) and main ea57360912ed. [exec] the follow-up's history probe (public-API main() program, lucene-core + lucene-facet, 20 docs as 1 and as 2 segments, 12 bug checks plus controls) gets 12 of 12 checks wrong on each of them with -ea, and also with -da on 9.8.0, 9.12.3, 10.0.0, 10.5.2 and main, and 0 of 12 with the fix sketch shadowed on main; the finder's release-compatible JUnit fails its 2 bug tests on all 23 releases and main (-da too on 9.8.0, 9.12.3, 10.5.2 and main); the CachingCollectorManager JUnit fails 2 of 4 on main with -ea and -da; the independent reproduction's tests fail on 10.5.2, 9.12.3 and 9.8.0, the cross-model review's finish-count test on 10.5.2 and 9.8.0, the intended-behaviour check's re-run on 10.5.2. Not affected [exec]: all 37 releases from 8.0.0 to 9.7.0 (probe; JUnit on 9.1.0-9.7.0) and both parent commits. [read] branch_10x and branch_10_6 (10.6.0, released 2026-10-29) carry both defect sites (their CachingCollector.java differs from main's only by a 'final' modifier); releases before 8.0.0 predate the hook. FacetsCollector and a finish-counting collector were executed on every version; BlockGroupingCollector only on main and 10.5.2 and the TermGroupFacetCollectorManager collector only on main (security probe). Not executed: x86, CachingCollectorManager with intra-segment partitions; the history runs used JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-180.html",
   "repro": "repro/LFV-180/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-880",
   "priority": "low",
   "priority_rank": 539,
   "novelty": "new",
   "withheld": false,
   "area": "grouping / GroupReducer and SecondPassGroupingCollector (second-pass per-group collectors)",
   "title": "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",
   "summary": "You write a GroupReducer that gives each group its own FacetsCollector (or any collector that compiles a segment's results in LeafCollector#finish), run it through SecondPassGroupingCollector, and expect each group's collector to see the documents of its group, as GroupReducer's javadoc says and as a plain IndexSearcher search would give. Instead every group's FacetsCollector reports no documents, with no error: GroupReducer.setNextReader replaces each group's leaf collector on every segment without calling finish() on the previous one, GroupReducer has no finish hook, and SecondPassGroupingCollector does not override finish(), so IndexSearcher's per-leaf finish() reaches only the outer collector. In the repro 5 documents in 2 segments are routed to groups a (3) and b (2), yet both groups report 0 hits; with assertions enabled FacetsCollector throws AssertionError on the second segment instead.",
   "impact_class": "silent wrong results",
   "introduced_commit": "8811f31b9ca6 (main, first released in 10.0.0) and de07bdd88dd1 (branch_9x backport, released in 9.8.0), the same 17-file patch: #12380 'Add a post-collection hook to LeafCollector.' by jpountz, merged 2023-06-30 (closes #12375); it added LeafCollector#finish, made IndexSearcher call it, made MultiCollector and FilterLeafCollector forward it, moved FacetsCollector's MatchingDocs recording into finish() (doSetNextReader now asserts docsBuilder == null) and moved three grouping collectors to finish(), but did not change GroupReducer or SecondPassGroupingCollector [read]; the defect site itself (GroupReducer.setNextReader and the GroupCollector holder) is caf329717ef6 (LUCENE-7701 'Refactor grouping collectors', 2017-03-28, first released in 7.0.0), which was correct until #12380 defined finish [read]",
   "introduced_date": "2023-06-30 (#12380: merged 2023-06-30T13:19:35Z; author date 2023-06-30 15:19:35 +0200 on both commits); 2017-03-28 (caf329717ef6, origin of the GroupReducer lines, not a defect before finish existed)",
   "first_affected_version": "9.8.0 [exec] (first main-line release: 10.0.0 [exec]); 9.7.0 is the last release without the bug [exec]: LeafCollector#finish does not exist there (the root-cause test does not compile) and FacetsCollector recorded the previous leaf in doSetNextReader and the last one in getMatchingDocs, which works through GroupReducer (the stock FacetsCollector repro passes on 9.7.0 and 9.6.0)",
   "affected_versions": "every release from 9.8.0 to 10.5.2 (23 releases: 9.8.0, 9.9.0-9.9.2, 9.10.0, 9.11.0-9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2), the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193. [exec] the stock FacetsCollector JUnit fails on 9.8.0 (-ea and -da), 9.9.0, 9.10.0, 9.12.3, 10.5.2 (-ea and -da), branch_10_6 and main (-ea and -da); the root-cause test (a per-group collector that counts finish calls: finishes=0 for both groups versus 2 under a direct IndexSearcher search) fails on 9.8.0, 9.12.3, 10.0.0, 10.5.2, branch_10_6 and main (-ea and -da); the independent reproduction's own JUnit fails 3 of 4 on main (-ea and -da), 10.5.2 and 9.12.3 (-ea and -da) and 9.8.0 (-da); the intended-behaviour check re-ran the finder's JUnit on main (-ea and -da) and 10.5.2 (-da); all runs on JDK 25, aarch64. [read] the other releases by git tag --contains de07bdd88dd / 8811f31b9ca and blob identity (GroupReducer.java 313172ac and SecondPassGroupingCollector.java 2000493f in every release 9.5.0-10.5.2, branch_10_6 and main; FacetsCollector#finish in every release from 9.8.0). Not affected: 9.0.0-9.7.0 and 7.0.0-8.x (no finish hook; 9.7.0 and 9.6.0 [exec] pass the FacetsCollector repro). Not fixed upstream: GroupReducer.java was last changed on upstream main by 2cbf261032dc (2021-01-05, reformat) and SecondPassGroupingCollector.java by 54fba99cb131 (2022-09-24, tidy); upstream main c5ab3e57b9ba (author date 2026-10-28) has nothing later (checked 2026-10-28).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-880.html",
   "repro": "repro/LFV-880/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-883",
   "priority": "low",
   "priority_rank": 540,
   "novelty": "known",
   "withheld": false,
   "area": "grouping / GroupReducer and SecondPassGroupingCollector (second-pass per-group collectors)",
   "title": "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",
   "summary": "You write a GroupReducer whose per-group collector needs only the first documents of its group in a segment (for example a stock TopFieldCollector in index order with a hit threshold of 1, which then throws CollectionTerminatedException, as collectors may), run it through SecondPassGroupingCollector, and expect every group's collector still to see the documents of its own group, as GroupReducer's javadoc says and as MultiCollector does for its children. Instead GroupReducer.collect does not catch the exception, SecondPassGroupingCollector passes it on, and IndexSearcher ends the segment for the whole second pass, so all the other groups silently miss their remaining documents in that segment. In the repro one segment holds docs 0-2 in group a and docs 3-4 in group b: group a's collector stops on doc 1, group b reports no hit instead of doc 3, and the second pass counts 2 of 5 documents.",
   "impact_class": "silent wrong results",
   "introduced_commit": "caf329717ef6 (LUCENE-7701 'Refactor grouping collectors' by romseygeek, master only; 2017 JIRA patch workflow with no GitHub PR, GitHub mirror #8752, fix version 7.0): it added GroupReducer, whose collect() calls collector.leafCollector.collect(doc) and whose setNextReader() calls collector.collector.getLeafCollector(ctx), neither handling CollectionTerminatedException, and made SecondPassGroupingCollector a concrete class that forwards every grouped document to groupReducer.collect() [read]; the pre-7.0 second pass also forwarded without a catch, but its per-group collectors were its own fixed TopScoreDocCollector / TopFieldCollector instances, which never throw the exception in 6.6.6 or 7.0.0, and no documented hook let a caller supply one, so that precursor is not counted",
   "introduced_date": "2017-03-28 (caf329717ef6: author date 2017-03-28T19:52:53+01:00, commit date 2017-04-10T11:10:18+01:00; LUCENE-7701 closed 2017-04-10)",
   "first_affected_version": "7.0.0 [exec] (tagged 2017-09-08, the first release with GroupReducer; never backported to 6.x: 6.5.0 and 6.6.6 [exec] give a compile error because GroupReducer, TermGroupSelector and getCollector(BytesRef) do not exist). A custom collector that throws CollectionTerminatedException from collect() triggers it from 7.0.0 [exec]; the stock early-terminating per-group collector of each line also does: EarlyTerminatingSortingCollector on 7.0.0 and 7.7.3 [exec], TopFieldCollector itself from 7.2.0 (index-sort prefix, LUCENE-8059) and with Sort.INDEXORDER from 7.7.0 (LUCENE-8463) [read], executed on 8.0.0 and later",
   "affected_versions": "every release from 7.0.0 to 10.5.2 (all 65 releases from 7.0.0 to 10.5.2 that are tagged in the local Lucene clone contain caf329717ef6; the 8.8.2-8.11.x releases are not tagged there, and 8.11.4 was executed), the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193. [exec] the follow-up's history probe (a custom collector that stops after 2 documents per group, the version's stock early-terminating collector per group, and the getLeafCollector path; two controls and a MultiCollector contrast pass on every executed version) fails on 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea, and -da on main) and passes on main with the fix sketch shadowed; the finder's JUnit fails on main (-ea and -da), branch_10_6, 10.5.2, 9.12.3 and 9.1.0; the independent reproduction's JUnit fails 4 of 5 on main (-ea and -da), 10.5.2 and 9.12.3; all runs on JDK 25, aarch64. [read] the releases between the executed ones by source shape (GroupReducer.collect/setNextReader and SecondPassGroupingCollector.collect/doSetNextReader are unchanged apart from the Scorable signature and formatting) and git tag --contains. Not affected: releases before 7.0.0 (no GroupReducer). Not regressed and not fixed upstream: GroupReducer.java was last changed on upstream main by 2cbf261032dc (2021-01-05, reformat) and SecondPassGroupingCollector.java by 54fba99cb131 (2022-09-24, tidy); upstream main c5ab3e57b9ba (author date 2026-10-28) has nothing later, and open PR #16548, which would fix the collect path, is unmerged (checked 2026-10-28).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16548",
    "https://github.com/apache/lucene/issues/8752",
    "https://github.com/apache/lucene/issues/16911",
    "https://github.com/apache/lucene/issues/7387",
    "https://issues.apache.org/jira/browse/LUCENE-6326",
    "https://github.com/apache/lucene/issues/7830"
   ],
   "doc": "",
   "repro": "repro/LFV-883/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-468",
   "priority": "low",
   "priority_rank": 541,
   "novelty": "known",
   "withheld": false,
   "area": "codecs / vectors (flat scalar-quantized format: byte kNN and byte similarity search)",
   "title": "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",
   "summary": "You index a BYTE vector field with Lucene104ScalarQuantizedVectorsFormat, a registered stand-alone flat (brute-force) format that accepts BYTE fields without error and searches its FLOAT32 and FLOAT16 fields by scoring every vector, and expect a byte kNN query to return the k nearest documents. Instead the reader hands byte searches to the raw flat reader, whose search method does nothing, so an unfiltered KnnByteVectorQuery returns 0 hits and ByteVectorSimilarityQuery.Adaptive with threshold 0 matches 0 of 10 documents, with no error. The same kNN query with a term filter that matches every document returns the exact top 3, because the filtered path falls back to exact search when the reader returns too few hits.",
   "impact_class": "silent wrong results",
   "introduced_commit": "8856a5f4eb7ec5b53c657f6c9c499fea52b9ee55 (main) and its 10.x backport 39e7f0973ec1f217f219506bc78c36cf422cf7c4 (the commit contained in releases), PR #14078 'Binary vector format for flat and hnsw vectors' (benwtrent), which created the flat Lucene102BinaryQuantizedVectorsReader with search(byte[]) delegating to the raw reader's empty search while search(float[]) scores every vector; carried unchanged into Lucene104ScalarQuantizedVectorsReader by PR #15169 'Add a new codec to implement OSQ for 4 and 8 bit quantized vectors' (mccullocht; 594eeb7e637c94d1018cdb938a5596de9034c0bc on main, 07033dcd84ccbbcf13bc3a81a6430445d2e4d3fa on 10.x). The empty FlatVectorsReader.search itself is older and deliberate (#13469, 487d24ae69f, first released in 9.12.0); #14078 is the first change in which a stand-alone flat format searches float fields but not byte fields [read]",
   "introduced_date": "2025-03-04 (#14078); 2025-09-17 (#15169, the named class)",
   "first_affected_version": "10.2.0 [exec] (flat Lucene102BinaryQuantizedVectorsFormat); 10.4.0 [exec] for the named Lucene104ScalarQuantizedVectorsFormat",
   "affected_versions": "[exec] 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1 and 10.3.2 with the flat Lucene102BinaryQuantizedVectorsFormat; 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main ea57360912ed with Lucene104ScalarQuantizedVectorsFormat (-ea and -da on 10.2.0, 10.4.0, 10.5.2 and main); an index written by 10.3.2 with the flat Lucene102 format and read by 10.5.2 and by main (-ea and -da) through backward-codecs fails the same way [exec]. Not affected: 10.1.0 and every 9.x release (neither format exists, the repro does not compile [exec]); there the older flat Lucene99ScalarQuantizedVectorsFormat returns 0 unfiltered hits for FLOAT32 and BYTE fields alike, the deliberate #13469 behaviour, so the float-searched, byte-not-searched split does not arise [exec]. Executed on aarch64 with JDK 25 and the Panama vector provider only; the byte path never reaches a vector scorer, so provider and CPU independence is [read].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15257",
    "https://github.com/apache/lucene/issues/13469",
    "https://github.com/apache/lucene/issues/13910",
    "https://github.com/apache/lucene/issues/14078",
    "https://github.com/apache/lucene/issues/15169",
    "https://github.com/apache/lucene/issues/16473"
   ],
   "doc": "",
   "repro": "repro/LFV-468/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-230",
   "priority": "low",
   "priority_rank": 542,
   "novelty": "new",
   "withheld": false,
   "area": "grouping / block grouping (BlockGroupingCollector.getTopGroups group maxScore; GroupingSearch(Query) and BlockGroupingCollectorManager within-group paging)",
   "title": "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",
   "summary": "You index each group as a document block and search with GroupingSearch(Query groupEndDocs) and the default relevance sorts, asking for the second page of documents inside each group with setGroupDocsOffset(1). You expect each group's maxScore to be the best score in the group (GroupDocs documents it as 'Max score in this group'), as two-pass term grouping reports and as block grouping did up to 10.4.0. Since 10.5.0 it is instead the score of the first document on the requested page, or -Infinity when the page is past the end of the group, and TopGroups.maxScore inherits the wrong value; the documents returned are correct.",
   "impact_class": "silent wrong results",
   "introduced_commit": "56fa833e554034a2e781da432b56ed09d0bc7ba4 (main) and its branch_10x backport 7a551555d54f82daf00c1ad5c0985e0e56e73af7: GITHUB#15942 'Skip max score computation when sorting by relevance in BlockGroupingCollector' by gaobinlong, approved (2026-04-08) and merged (2026-04-27) by benwtrent, listed under 10.5.0 Optimizations (CHANGES.txt:1060) [read]. No commit-level bisect on main was built.",
   "introduced_date": "2026-04-27 (UTC; author date 2026-04-28 01:48 +0800), the same day on main and branch_10x",
   "first_affected_version": "10.5.0 [exec] (tag dated 2026-06-25; git tag --contains 7a551555d54 lists exactly 10.5.0, 10.5.1, 10.5.2 and 10.6.0); 10.4.0 is the last release without it [exec]",
   "affected_versions": "10.5.0, 10.5.1 and 10.5.2 (every 10.5.x release), 10.6.0 (by reading, see below) and main ea57360912ed [exec]: the finder's JUnit fails 2 of 3 on all four (main with -ea and -da); the independent reproduction's own JUnit fails 2 of 5 on main (-ea and -da), 10.5.0 and 10.5.2. Upstream main, branch_10x, branch_10_6 and branch_10_5 still have the faulty lines as of 2026-10-26 [read]. Not affected [exec]: 10.4.0, 10.3.2, 10.0.0, 9.12.3, 8.11.4 and 8.0.0 (finder's JUnit, mechanical API ports for 9.x and 8.x; the independent reproduction's suite on 10.4.0 and 9.12.3). Context, not this bug: 7.7.3 gives NaN for an empty page (an older defect from TopDocs.getMaxScore, gone since 8.0.0 with LUCENE-8405) while its offset-1 case is correct [exec]. Releases between the listed ones were not run; none contains the backport commit [read]. All runs on aarch64 with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-230.html",
   "repro": "repro/LFV-230/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1054",
   "priority": "low",
   "priority_rank": 543,
   "novelty": "known",
   "withheld": false,
   "area": "grouping / GroupingSearch two-pass grouping (term, function and GroupSelector grouping), TopGroups.totalGroupCount",
   "title": "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",
   "summary": "You group with new GroupingSearch(\"group\") and setAllGroups(true) so that TopGroups.totalGroupCount tells you how many groups match, and for a query that matches nothing you expect 0 (TopGroups documents null as 'this value is not computed'). Instead search() returns early with an empty TopGroups whose totalGroupCount is null, skipping the step that adds the group count it has already computed, so getAllMatchingGroups().size() is 0 while totalGroupCount is null; the same happens for a page at or past the last group (4 hits in 3 groups, offset 3: null instead of 3). The package documentation's own example, 'int totalGroupCount = result.totalGroupCount;', then throws NullPointerException.",
   "impact_class": "minor",
   "introduced_commit": "89b55566d8392657be86e1441a329373e9132257 (LUCENE-3778 = #4851 'Create a grouping convenience class', author Martijn van Groningen, SVN trunk r1303871): the first GroupingSearch already returned an empty TopGroups without the group count when the first pass found no group, before the setAllGroups wrap with matchingGroups.size() [read]",
   "introduced_date": "2012-03-22",
   "first_affected_version": "4.0.0-ALPHA (first final release 4.0.0); 3.6.2 and earlier have no GroupingSearch",
   "affected_versions": "[exec] main 645d4fe14a20 (-ea and -da; re-run at the registration check 2026-10-30: 1 of 1 fails each, seed DEADBEEF), 10.6.0 (4ae946e5a9b9, -ea and -da), 10.5.2, 9.12.3, 8.11.4, 7.7.3, 6.6.6 and 5.5.5 (pre-9 import port), 4.10.4, 4.0.0 and 4.0.0-ALPHA (4.x port) all fail with 'expected:<0> but was:<null>'; 3.6.2: API absent [exec]. [read] every release from 4.0.0-ALPHA to 10.6.0 has the same early return (10.5.2 in the '== null' form, 10.6.0 in the '#16247 isEmpty()' form, both executed). Not fixed upstream: main head 716d6f216f5 (2026-10-29) has no lucene/grouping commit after 645d4fe (the last GroupingSearch.java commit is #16247, author date 2026-07-08) and no open apache/lucene PR changes the early return [read]. The Lucene.NET port fixed its own copy in 4.8.0-beta00018 (lucenenet#1363). Not new in 10.6.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/1363",
    "https://issues.apache.org/jira/browse/LUCENE-4581",
    "https://issues.apache.org/jira/browse/LUCENE-4626",
    "https://github.com/apache/lucene/issues/16931",
    "https://github.com/apache/lucene/issues/16247",
    "https://github.com/apache/lucene/issues/4851"
   ],
   "doc": "",
   "repro": "repro/LFV-1054/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-407",
   "priority": "low",
   "priority_rank": 544,
   "novelty": "new",
   "withheld": false,
   "area": "grouping / range group selectors (LongRangeFactory and DoubleRangeFactory, used by LongRangeGroupSelector and DoubleRangeGroupSelector)",
   "title": "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",
   "summary": "You group documents with new LongRangeFactory(10, 10, 25), meaning buckets 10 wide starting at 10 and everything at or above 25 in one bucket, and expect what the javadoc says: [10, 20), a shorter final bucket [20, 25), and [25, MAX). Instead the value 22 is labelled LongRange(20, 30) while 27 is labelled LongRange(25, MAX), so the two reported ranges overlap; each group holds the right documents, but a range query built from the label [20, 30), the way Lucene's own selector tests rebuild a group, also returns the document with value 27 from the other group. DoubleRangeFactory behaves the same, because both getRange methods set the bucket's upper bound to its lower bound + width and never cap it at max.",
   "impact_class": "minor",
   "introduced_commit": "7c350d22c7070acf362fb4f477e6797f2711c910 (LUCENE-7889 'Allow grouping on Double/LongValuesSource', PR apache/lucene-solr#1484 by romseygeek, migrated issue apache/lucene#8940; branch_8x backport 5e62c42c5f304eee7b5695f97f02a2aea7d00366) [read]. Born with the feature, not a regression: the javadoc that promises a shorter final range came in the same commit, on top of code that never implemented it",
   "introduced_date": "2020-05-11",
   "first_affected_version": "8.6.0 [exec] (the first release with the range factories; 8.5.2 has no such API [exec])",
   "affected_versions": "every release that has the classes: 8.6.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.6.0 and main ea57360912ed [exec] [read]. Not fixed upstream: main cf398bfb142c (2026-10-26), branch_10x, branch_10_6, branch_10_5 and branch_9x carry only the two commits above [read]. All runs on one aarch64 Linux host with JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-407.html",
   "repro": "repro/LFV-407/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-412",
   "priority": "low",
   "priority_rank": 545,
   "novelty": "new",
   "withheld": false,
   "area": "grouping / range group selectors (DoubleRangeFactory, used by DoubleRangeGroupSelector)",
   "title": "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))",
   "summary": "You group documents by a double field with new DoubleRangeFactory(0, 0.1, 10), buckets 0.1 wide, and expect each group's DoubleRange label to contain the values grouped under it, because DoubleRange is documented as [min, max). Instead the value 0.6 is grouped under DoubleRange(0.5, 0.6), which excludes 0.6, and 1.7 under DoubleRange(1.7000000000000002, 1.8000000000000003); 27 of the 100 values 0.0, 0.1, ..., 9.9 lie outside their own label, adjacent labels leave gaps (no label contains 0.6) or overlap, and a range query built from a label misses or picks up documents (values 0.55, 0.6, 0.65 form a group DoubleRange(0.5, 0.6) of 2 documents whose label matches 1). The cause is that getRange picks the bucket with Math.floor((value - min) / width) but computes its bounds separately as min + bucket * width and then that + width, and the three roundings disagree near boundaries; group membership itself stays consistent.",
   "impact_class": "minor",
   "introduced_commit": "7c350d22c7070acf362fb4f477e6797f2711c910 (LUCENE-7889 'Allow grouping on Double/LongValuesSource', PR apache/lucene-solr#1484 by romseygeek, migrated issue apache/lucene#8940; branch_8x backport 5e62c42c5f304eee7b5695f97f02a2aea7d00366, the commit in 8.6.0) [read]. Born with the feature, not a regression",
   "introduced_date": "2020-05-11",
   "first_affected_version": "8.6.0 [exec] (the first release with DoubleRangeFactory; 8.5.2 has no such API [exec])",
   "affected_versions": "every release that has the class: 8.6.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.6.0 and main ea57360912ed [exec] [read]. Not fixed upstream: main, branch_10x and branch_10_6 last changed the file in LUCENE-9570 [read]. All runs on one aarch64 Linux host with JDK 25.0.3; Java floating point is strict IEEE-754 binary64 since Java 17, so other platforms are not expected to differ, but none was run",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-412.html",
   "repro": "repro/LFV-412/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-411",
   "priority": "low",
   "priority_rank": 546,
   "novelty": "new",
   "withheld": false,
   "area": "grouping / range group selectors (DoubleRangeFactory, used by DoubleRangeGroupSelector)",
   "title": "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",
   "summary": "You group documents by a double field with new DoubleRangeFactory(-10, 5, 10), meaning buckets 5 wide from -10 to 10 and every value below -10 in one bucket, and expect the bucket returned for -20 to be a [min, max) range that contains -20, the way LongRangeFactory returns [Long.MIN_VALUE, -10). Instead DoubleRangeFactory returns DoubleRange(4.9E-324, -10.0): it uses Double.MIN_VALUE as the lower end, and Double.MIN_VALUE is the smallest positive double, not the most negative one, so the range is inverted and holds none of its members (with min > 0 it leaves out 0.0 and every negative member). Each group still holds the right documents, but its reported bounds are wrong, and a range query built from them, the way Lucene's own selector tests rebuild a group, finds none or only some of the group's documents.",
   "impact_class": "minor",
   "introduced_commit": "7c350d22c7070acf362fb4f477e6797f2711c910 (LUCENE-7889 'Allow grouping on Double/LongValuesSource', PR apache/lucene-solr#1484 by romseygeek, migrated issue apache/lucene#8940; branch_8x backport 5e62c42c5f304eee7b5695f97f02a2aea7d00366) [read]. The line and the assertion already exist in the 2017 Double-only LUCENE-7889 JIRA patch; the LongRangeFactory twin, first added in the 2020 commit, uses Long.MIN_VALUE. Born with the feature, not a regression",
   "introduced_date": "2020-05-11 (committed to main and to branch_8x; the code first appears in the 2017 LUCENE-7889 JIRA patch)",
   "first_affected_version": "8.6.0 [exec] (the first release with DoubleRangeFactory, through the branch_8x backport; 8.5.2 has no such API [exec]); first on the main line: 9.0.0",
   "affected_versions": "every release that has the class: 8.6.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.6.0 and main ea57360912ed [exec]. 8.8.2-8.11.4 rest on execution against Maven Central release jars only (those tags are not in the local history clones). 10.6.0 (released 2026-10-29) has it: the bug doc's repro fails on the 10.6.0 release jars (assertions off) [exec], and the file is the same blob on branch_10_6 [read]. Not fixed upstream: DoubleRangeFactory.java is unchanged since the 2021 reformat on main, branch_10x, branch_10_5 and branch_9x, and none of the 411 open apache/lucene PRs touches it or its test [read]. All runs on one aarch64 Linux host with JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-411.html",
   "repro": "repro/LFV-411/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-881",
   "priority": "low",
   "priority_rank": 547,
   "novelty": "new",
   "withheld": false,
   "area": "grouping / GroupingSearch doc-block path (BlockGroupingCollectorManager score mode)",
   "title": "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)",
   "summary": "You group documents indexed as blocks with new GroupingSearch(groupEndDocs), sort the groups and the documents inside each group by fields, and leave setIncludeMaxScore at its default true (or set it), expecting TopGroups.maxScore and each GroupDocs.maxScore to hold the best score, as the setIncludeMaxScore javadoc ('Whether to include the score of the most relevant document per group') says and as two-pass grouping with the same settings returns (0.22094907 in the repro). Instead both are NaN, because GroupingSearch.groupByDocBlock asks BlockGroupingCollectorManager to compute scores only when one of the two sorts needs them and never reads includeMaxScore. Adding includeMaxScore to that needsScores argument, the rule the two-pass path already follows, fixes it.",
   "impact_class": "minor",
   "introduced_commit": "55bfadbce115a825a75686fe0bfe71406bc3ee44 (master, LUCENE-8412 'Remove trackDocScores from TopFieldCollector factory methods', patch by jpountz with +1 from romseygeek and mikemccand, migrated as apache/lucene#9459; JIRA patch, no GitHub PR): it removed GroupingSearch.includeScores / setIncludeScores (default true) and replaced the block path's includeScores argument with groupSort.needsScores() || sortWithinGroup.needsScores(), while passing includeMaxScore only to the two-pass TopGroupsCollector. includeMaxScore was never read on the block path in any version, so before 8.0.0 block max scores existed only because includeScores defaulted to true [exec]",
   "introduced_date": "2018-07-23 (author date 09:05:02 +0200, commit date 09:06:49 +0200, master); first released in 8.0.0",
   "first_affected_version": "8.0.0 [exec] with default settings; 7.7.3 is the last unaffected release with default settings (and 7.4.0 the last release before the commit date) [exec]; but on 7.7.3 too setIncludeScores(false) + setIncludeMaxScore(true) gives NaN [exec], because includeMaxScore was never wired into the block path; GroupingSearch itself exists since 4.0.0-alpha (LUCENE-3778, 89b55566d83)",
   "affected_versions": "every release from 8.0.0 to 10.5.2, the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193 (11.0.0-SNAPSHOT). [exec] the finder's JUnit (testBlockGrouping fails with 'TopGroups.maxScore expected:<0.22094907> but was:<NaN>', the two-pass control passes) fails 1 of 2 on 8.0.0 (-ea and -da), 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da), branch_10_6 4ae946e5a9b and main (-ea and -da), and on a source build of 55bfadbce11; it passes on 7.0.0, 7.4.0, 7.5.0, 7.7.3 (-ea and -da) and on the parent 34686c00dde; the independent reproduction's own JUnit fails 2 of 5 (3 controls pass) on main (-ea and -da), 10.5.2 (-ea and -da), 9.12.3 (-ea and -da) and 8.0.0, and passes 5 of 5 on 7.7.3; the intended-behaviour check and the adjudication re-ran on main (-ea and -da). [read] the releases between the executed ones, from code identity (the expression is unchanged since 55bfadbce11). Not fixed upstream: upstream main c5ab3e57b9b (2026-10-28) is unchanged at the fix site; the newest upstream commit on GroupingSearch.java is 3afffeef5a8 (author date 2026-07-08), contained in a9779ef. All runs JDK 25.0.3 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-881.html",
   "repro": "repro/LFV-881/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-511",
   "priority": "low",
   "priority_rank": 548,
   "novelty": "known",
   "withheld": false,
   "area": "grouping / max-score reporting (TopGroupsCollector, BlockGroupingCollector)",
   "title": "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",
   "summary": "You run a grouped search whose hits all score 0, for example a BooleanQuery with only FILTER clauses, and sort the documents inside each group by a field; you expect TopGroups.maxScore and each GroupDocs.maxScore to be 0, the highest score of any hit. Instead they are 1.4E-45 (Float.MIN_VALUE), because the running maximum starts at Float.MIN_VALUE, the smallest positive float, instead of below every score; and since 10.5.0 a second-pass TopGroupsCollector built with getMaxScores=false reports the same 1.4E-45 instead of the documented NaN for 'scores were not computed'. The hits, the group order and the counts are correct; only the reported max score is off.",
   "impact_class": "minor",
   "introduced_commit": "three steps, each confirmed by execution on both sides plus a one-line shadow of the release-tag source (release bracket, not a commit-level bisect): (1) c14d35136d9c0fe505abb65c0f1200dbe7e71a34 (branch_4x, svn r1344854; trunk twin 9b103fa61e8b, svn r1344844, which git blame on main gives for BlockGroupingCollector.java:274), LUCENE-4077 'expose max score and per-group (parent) scores in TopGroups' (GitHub issue #5149, by mikemccand, no PR): added TopGroups.maxScore and its javadoc and filled it from a Math.max that starts at Float.MIN_VALUE in the second-pass and block getTopGroups (overall all-zero case; the second-pass line moved into TopGroupsCollector with LUCENE-7701, caf329717ef, 7.0.0); (2) 331ccf391067b7775db371bec1ec8e8c9004e904, LUCENE-8405 'Remove TopDocs.maxScore' (#9452, by jpountz): added MaxScoreCollector with the same start (per-group case with a field sort inside groups); (3) 23d400cabd8e63d26d594ec94e866ef5e22d2a12 (release-branch cherry-pick 043858e4f74), PR #15873 fixing #15872 (by gaobinlong): switched getTopGroups from Math.max to nonNANmax over the kept start, so all-NaN groups yield the start value instead of NaN (no-score case) [exec]",
   "introduced_date": "2012-05-31 (LUCENE-4077); 2018-07-18 (LUCENE-8405); 2026-04-29 (#15873 merged; commit dated 2026-04-30 +0800)",
   "first_affected_version": "4.0.0-alpha [exec] (overall TopGroups.maxScore for all-zero scores; 3.6.2 has no TopGroups.maxScore [exec]); per-group GroupDocs.maxScore with a field sort inside groups from 8.0.0 [exec]; the no-score NaN case from 10.5.0 [exec]",
   "affected_versions": "Every release from 4.0.0-alpha through 10.5.2 and main ea57360912ed reports TopGroups.maxScore = 1.4E-45 for all-zero scores on the second-pass (field sorts) and block-grouping (field group sort) paths; GroupDocs.maxScore = 1.4E-45 with a field sort inside groups from 8.0.0; TopGroups.maxScore = 1.4E-45 instead of NaN with no scores computed in 10.5.0, 10.5.1 (source check only), 10.5.2 and main [exec]. Partly hidden paths: since 10.5.0 (#15942) block grouping with a relevance group sort reports 0; on main the fully default GroupingSearch (relevance group and within-group sort) reports 0, which it does not on any executed release from 4.0.0-alpha to 10.5.2 (likely a side effect of #16247, listed under 10.6.0, released 2026-10-29; not bisected). 10.6.0 was not run. Not fixed upstream: the three start values are unchanged on upstream main a9779ef3c193 (2026-10-26) and no grouping commit landed after ea57360912ed [read]. All runs on one aarch64 Linux host with JDK 25.0.3",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/10039",
    "https://issues.apache.org/jira/browse/LUCENE-8996",
    "https://github.com/apache/lucene-solr/pull/906",
    "https://github.com/apache/lucene/issues/15872",
    "https://github.com/apache/lucene/issues/15873",
    "https://github.com/apache/lucene/issues/4713"
   ],
   "doc": "",
   "repro": "repro/LFV-511/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-064",
   "priority": "low",
   "priority_rank": 549,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / vectors",
   "title": "Quantized MIP/EUCLIDEAN scores become NaN when OSQ correction terms overflow",
   "summary": "With the OSQ format and MAXIMUM_INNER_PRODUCT or EUCLIDEAN, you index vectors with components around 1e17-1e19. You expect finite scores, as the float path gives. Instead the correction terms overflow to inf - inf, the quantized score is NaN, and NaN drops whole 64-document batches (one outlier made 301 of 301 scores NaN).",
   "impact_class": "silent wrong results",
   "introduced_commit": "#15169 (594eeb7e637) [read]",
   "introduced_date": "2025-09-17",
   "first_affected_version": "unknown (not yet bisected; 10.5.2 executed)",
   "affected_versions": "10.5.2 and main [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-064.html",
   "repro": "repro/LFV-064/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1120",
   "priority": "low",
   "priority_rank": 550,
   "novelty": "new",
   "withheld": false,
   "area": "core / search: late-interaction rescoring (LateInteractionField, LateInteractionFloatValuesSource, LateInteractionRescorer)",
   "title": "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)",
   "summary": "You index a document with a LateInteractionField whose token matrix is {{1,0},{0,0}} (the second token is all zeros) and rescore it with LateInteractionRescorer.create(\"li\", {{1,0}}), which uses COSINE by default. You expect a valid score, here 1.0 because the document's first token equals the query token, or an IllegalArgumentException for the zero token, as KnnFloatVectorField gives under COSINE. Instead the field accepts the zero row, the cosine of the zero row is 0/0 = NaN, Float.max in SUM_MAX_SIM keeps that NaN over the exact match, and the document comes back with score NaN (with -ea, VectorUtil.cosine throws AssertionError).",
   "impact_class": "minor",
   "introduced_commit": "d9618080b34 (apache/lucene#14729 'Support for Re-Ranking Queries using Late Interaction Model Multi-Vectors' by vigyasharma, main; branch_10x cherry-pick 7de24ce973d, released in 10.3.0) [read]; not a regression: the classes shipped without zero-vector or finiteness checks, while the single-vector precedent (finiteness checks in the field and query classes, #12281, 2023) was already in place",
   "introduced_date": "2025-07-08 (author and commit date of d9618080b34, #14729 merged; branch_10x cherry-pick 7de24ce973d the same day)",
   "first_affected_version": "10.3.0 [exec] (first release with the late-interaction classes; 10.2.2 and 9.12.3 give compile_error because the API is absent [exec])",
   "affected_versions": "every release from 10.3.0 through 10.6.0 (10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and 10.6.0, released 2026-10-29 at 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT). Executed: main with -ea and -da (the finder, the independent reproduction also with the scalar vector provider, the cross-model review's tests re-run, the intended-behaviour check, the adjudication and a separate re-run), 10.6.0 with -ea and -da, 10.5.2 with -da, 10.4.0 with -da and 10.3.0 with -ea and -da [exec]; 10.3.1, 10.3.2, 10.5.0 and 10.5.1 by reading (the three late-interaction source files are byte-identical to d9618080b34 at those tags) [read]. Not affected: 10.2.2 and earlier and all 9.x (API absent; 10.2.2 and 9.12.3 compile_error [exec]). Not new in 10.6 (10.5.2 and 10.3.0 fail). Not fixed upstream: on upstream main 1c2072f0284 (author date 2026-11-02) the three late-interaction files were last changed by d9618080b34, and the only open PR touching LateInteractionFloatValuesSource (#16748) keeps VectorUtil.cosine and Float.max [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1120.html",
   "repro": "repro/LFV-1120/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-140",
   "priority": "low",
   "priority_rank": 551,
   "novelty": "new",
   "withheld": false,
   "area": "document / range fields (DoubleRange, FloatRange, their doc-values fields; facet range-on-range)",
   "title": "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])",
   "summary": "You index a DoubleRange or FloatRange with min 0.0 and max -0.0 (Java's negative zero, numerically equal to 0.0); the constructor accepts it, as it accepts [0.0, 0.0], so you expect queries to treat it as the point zero, or else an IllegalArgumentException like the one thrown for every other min > max pair. Instead Lucene stores the bounds in its sort order, where -0.0 is below 0.0, so the stored range is inverted: the document matches newWithinQuery [0,0] and newIntersectsQuery [-1,1] but not newIntersectsQuery [0,0] or newIntersectsQuery of its own bounds. The same happens with the doc-values slow intersects query and range-on-range facet counts, and a query with bounds [0.0, -0.0] misses a document [0.0, 0.0] that newContainsQuery with the same bounds matches.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f5964ec6e45a (LUCENE-7381 'add point based DoubleRangeField and RangeFieldQuery', migrated issue #8434, author nknize, a JIRA-era patch with no GitHub PR; branch_6x backport 7dfcfcc71851) wrote both the primitive check 'if (min[d] > max[d])' and the sortable encoding (NumericUtils.doubleToSortableLong) in the same method; FloatRange got the same code from 249780cf6082 (LUCENE-7388, #8441; branch_6x 59807c530c9c); both lines are unchanged on main (git blame; later edits are formatting only, LUCENE-9570) [read]; the doc-values fields reach it from LUCENE-8362 (8.2.0) and range-on-range facets from #11901 (GITHUB#11869, 9.5.0); later RangeFieldQuery rewrites (LUCENE-7449 in 6.5.0, LUCENE-7847 in 6.6.0, LUCENE-7828 528899d845cc in 7.0.0) changed which contradiction appears, not whether one appears [exec]",
   "introduced_date": "2016-07-15 (DoubleRangeField, author date; committed 2016-07-20); FloatRangeField 2016-07-21 (committed 2016-08-17)",
   "first_affected_version": "6.2.0 [exec] (sandbox DoubleRangeField/FloatRangeField); first affected core release 6.5.0 [exec] (LUCENE-7740 moved the fields to core as DoubleRange/FloatRange); the exact symptoms the repros assert (own pair WITHIN and CONTAINS but not INTERSECTS; WITHIN [0,0] but not INTERSECTS [0,0]) from 7.0.0 [exec]; doc-values fields from 8.2.0 [exec]; range-on-range facets from 9.5.0 [exec]",
   "affected_versions": "all 89 releases from 6.2.0 through 10.5.2 and main ea57360912ed, each executed failing with a version-portable main() probe (two index shapes, reading-independent consistency oracles, passing controls) [exec], and 10.6.0 (by reading); the finder's JUnit fails 6 of 6 on 9.5.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) and its core part 5 of 5 on 9.4.2 [exec]; the independent reproduction's JUnit fails 5 of 9 on 9.12.3, 10.5.2 and main (-ea and -da) and the independent reproduction's core-only main() fails on 7.7.3 and 8.11.4 [exec]; doc-values probe fails on 8.2.0, 8.11.4, 9.12.3, 10.5.2 and main [exec]; the symptom differs by era: 6.2.0-6.4.2 WITHIN [0,0] and INTERSECTS [0,0] but not CONTAINS [0,0], 6.5.x and 6.6.x WITHIN [0,0] and INTERSECTS [-1,1] but not INTERSECTS [0,0] (6.6.x also depends on the segment's other documents), 7.0.0 onwards the symptoms in the summary [exec]; unaffected: 6.1.0 and earlier (the API does not exist; 6.0.0, 6.0.1 and 6.1.0 executed, compile error); branch_10x, branch_10_6 and branch_9_12 carry the same line [read], so 10.6.0 (released 2026-10-29) is affected and later releases will be unless fixed first [not executed]; not fixed upstream [read]; caveat: the 6.x-8.x jars were run on JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-140.html",
   "repro": "repro/LFV-140/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-310",
   "priority": "low",
   "priority_rank": 552,
   "novelty": "new",
   "withheld": false,
   "area": "facet / range facet counts (DoubleRange bounds and values converted to sortable longs in DoubleRangeFacetCounts, against DoubleRange.accept and getQuery)",
   "title": "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",
   "summary": "You count range facets over a double field with DoubleRangeFacetCounts and a range that starts at an inclusive 0.0, such as new DoubleRange(\"[0, 1]\", 0.0, true, 1.0, true), and some documents hold -0.0 (Java's negative zero, which ordinary arithmetic such as Math.ceil(-0.25) or -1 * 0.0 produces). You expect the count to include every document the range accepts, because DoubleRange.accept and the range's own drill-down query getQuery() compare with primitive >= and <=, treat -0.0 as equal to 0.0, and match those documents. Instead the counter converts bounds and values with NumericUtils.doubleToSortableLong, where -0.0 sorts below +0.0, so those documents are silently left out of the count (likewise +0.0 at an inclusive -0.0 upper bound), and the range [+0.0, -0.0], which the DoubleRange constructor accepts, makes DoubleRangeFacetCounts throw IllegalArgumentException 'matches nothing'.",
   "impact_class": "silent wrong results",
   "introduced_commit": "8e1879225a35 (LUCENE-5371 'faster range faceting using segment trees', migrated as apache/lucene#6435, committed by mikemccand on the lucene5339 feature branch, svn r1552086; landed on trunk as 9d0b60388da (r1555338) and on branch_4x as 7477fde1cb0 (r1555342), together with LUCENE-5339; SVN era, no pull request). It replaced the per-hit loop 'if (ranges[j].accept(v)) counts[j]++' with LongRangeCounter over NumericUtils.doubleToSortableLong of the bounds and of each value, and added the primitive 'minIn > maxIn' constructor check and the LongRange 'matches nothing' check that rejects the converted [+0.0, -0.0]. [exec].",
   "introduced_date": "2013-12-18 (8e1879225a3 on the lucene5339 branch); trunk and branch_4x 2014-01-04; first release 4.7.0, tagged 2014-02-25",
   "first_affected_version": "4.7.0 [exec] (version-adapted probe: -0.0 in [0,1] facet count 1 vs accept()/getFilter 2; +0.0 in [-1,-0.0] 1 vs 2; [+0.0,-0.0] throws 'matches nothing'); 4.6.1, the last release before, is consistent [exec] (its RangeAccumulator counted with DoubleRange.accept); range faceting first appeared in 4.4.0 (LUCENE-4965) [read]",
   "affected_versions": "every release from 4.7.0 through 10.6.0 and main (ea57360912ed, 645d4fe14a20); not fixed upstream. [exec] the follow-up's version-adapted main() probes (control plus the three cases) fail on 4.7.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main and pass on 4.6.1 (the control is consistent on every version); the finder's JUnit fails 3 of 3 on 9.12.3 (one-line compat copy), 10.5.2 and main (-ea and -da); the independent reproduction's JUnit, which adds the multi-valued field and MultiDoubleValuesSource paths, fails 4 of 5 on 9.12.3, 10.5.2 and main (-ea and -da), and the independent reproduction's own probes fail on 4.7.0 and pass on 4.6.1; the minimal JUnit fails on main 645d4fe14a20 (gradle, assertions on and off) and on the 10.6.0 and 10.5.2 release jars (-ea and -da). Counting paths and the release that added each [read]: single-valued field 4.7.0, DoubleValuesSource 6.4.0 (LUCENE-7610), multi-valued field 8.10.0 (LUCENE-9946), MultiDoubleValuesSource 9.1.0 (LUCENE-10245). [read] 4.4.0-4.6.0 use the same accept() loop as 4.6.1; releases between the executed ones were not run one by one, and the conversion code is the same at every checked tag; upstream main 716d6f216f52, branch_11x 603af8703753 and branch_10_6 7e5aec4370e0 carry the same accept(), constructor check and conversion (branch_10x was emptied upstream on 2026-10-29), so the next releases are affected unless fixed first. All runs on JDK 25.0.3, aarch64 Linux, not each release's own JDK.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-310.html",
   "repro": "repro/LFV-310/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-313",
   "priority": "low",
   "priority_rank": 553,
   "novelty": "new",
   "withheld": false,
   "area": "facet / range, rangeonrange and facetset (exclusive-bound adjustment of double and float ranges: range.DoubleRange, rangeonrange.DoubleRange, facetset.DimRange.fromDoubles/fromFloats)",
   "title": "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",
   "summary": "You build a facet range with an exclusive bound that is an infinity, for example new DoubleRange(\"> +Inf\", Double.POSITIVE_INFINITY, false, Double.POSITIVE_INFINITY, true), meaning 'value > +Infinity', or the mirror [-Inf, -Inf) 'value < -Infinity'. No double is greater than +Infinity, so you expect a range that matches nothing, rejected with IllegalArgumentException 'matches nothing' as the class does for other empty ranges and as LongRange and DimRange.fromLongs do for an exclusive Long.MAX_VALUE bound. Instead the constructor makes the bound inclusive with Math.nextUp (or Math.nextAfter / Math.nextDown for the max), which leaves an infinity unchanged, so the range becomes [+Inf, +Inf]: DoubleRangeFacetCounts counts and the drill-down query matches every +Infinity document, and the copies in rangeonrange.DoubleRange and DimRange.fromDoubles/fromFloats count the same documents.",
   "impact_class": "silent wrong results",
   "introduced_commit": "3d60bd10d48d9111b2825d4246f5234059ecdbb1 (trunk svn r1477562; branch_4x d1fcf26e425b462322607d1d6947eb5e448e029e, r1477560), 'LUCENE-4965: add dynamic numeric range faceting' by mikemccand (CHANGES.txt credits Mike McCandless and Shai Erera), JIRA LUCENE-4965 migrated as apache/lucene#6029; SVN era, no pull request. It created facet.range.DoubleRange and FloatRange with the 'if (!minInclusive) min = Math.nextUp(min)' / 'max = Math.nextAfter(max, Double.NEGATIVE_INFINITY)' adjustment, so the defect is as old as the API (not a regression). LUCENE-5371 (#6435; 8e1879225a35, merged as 9d0b60388da8 / 7477fde1cb06, 2014-01-04, first release 4.7.0) made LongRange reject the analogous exclusive Long.MAX_VALUE / Long.MIN_VALUE bound with failNoMatch() but gave DoubleRange only a 'min > max' check, which cannot see min == max == the infinity. Later copies of the idiom: DimRange.fromDoubles/fromFloats from #841 (LUCENE-10274, main f6bb9d218c0e, backport #981 0e1502c12ba9, mdmarshmallow with shaie and gsmiller, 2022-06-25, first release 9.3.0) and rangeonrange.DoubleRange from #11901 (GITHUB#11869, main cbfed77fd33c, branch_9x d9fc418914ae, mdmarshmallow, 2022-12-30, first release 9.5.0), a verbatim copy of the constructor. [read]",
   "introduced_date": "2013-04-30 (LUCENE-4965); copies 2022-06-25 (#841, DimRange) and 2022-12-30 (#11901, rangeonrange.DoubleRange)",
   "first_affected_version": "4.4.0 [exec] (range.DoubleRange and range.FloatRange; 4.3.1 has no facet.range package, compile error [exec]); DimRange.fromDoubles/fromFloats 9.3.0 [exec] (9.2.0 has no facetset package [exec]); rangeonrange.DoubleRange 9.5.0 [exec] (9.4.2 has no rangeonrange package [exec])",
   "affected_versions": "range.DoubleRange: every release from 4.4.0 through 10.6.0 and main ea57360912ed; not fixed upstream (upstream main e1c4184cb983 has the three files byte-identical, 2026-10-26). [exec] the history probes (public API, main() mode, all controls passing) fail on 4.4.0 (-ea and -da), 4.5.1, 4.6.1, 4.7.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main (-ea and -da); range.FloatRange (same defect, removed by LUCENE-5345 in 4.7.0) fails on 4.4.0, 4.5.1 and 4.6.1; DimRange.fromDoubles/fromFloats fail on 9.3.0 (-ea and -da), 9.12.3, 10.5.2 and main (-ea and -da); rangeonrange.DoubleRange fails on 9.5.0 (-ea and -da), 9.12.3, 10.5.2 and main (-ea and -da); the finder's JUnit fails 3 of 4 on main (-ea and -da), 10.5.2, 9.12.3 and, as a 9.x port, 9.3.0; the independent reproduction's JUnit fails 5 of 6 on main (-ea and -da), 10.5.2 and 9.12.3, and the independent reproduction's accept() main() fails on 8.11.4 and 4.10.4. [read] every release tag from 4.4.0 on in the history clone contains the introducing commit (8.9.0-8.11.4 are not tagged there; 8.11.4 was executed); git log -L shows no change to the adjustment between the executed versions. 10.6.0 (released 2026-10-29) fails the bug doc's one-method repro on its release jars (4ae946e5a9b9, -ea and -da) [exec]; main has the three files unchanged and branch_10x the same range.DoubleRange constructor code [read]. All runs on JDK 25.0.3, aarch64 Linux, not each release's own JDK.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-313.html",
   "repro": "repro/LFV-313/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1131",
   "priority": "low",
   "priority_rank": 554,
   "novelty": "new",
   "withheld": false,
   "area": "facet / facetset and rangeonrange (exclusive-bound stepping of double and float ranges: facetset.DimRange.fromDoubles/fromFloats with RangeFacetSetMatcher, rangeonrange.DoubleRange with DoubleRangeOnRangeFacetCounts)",
   "title": "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]",
   "summary": "You index one document with a DoubleFacetSet holding -0.0 and count it with two RangeFacetSetMatchers, DimRange.fromDoubles(-1, true, 0, false) and DimRange.fromDoubles(0, true, 1, true), which split [-1, 1] at zero; you expect the two counts to add up to 1, because -0.0 belongs to [-1, 0) if the zeros are ordered as Double.compare orders them (the sortable order the matcher compares in) and to [0, 1] if they compare equal. Instead both counts are 0, with no error, while a covering [-1, 1] range counts the document: fromDoubles turns the exclusive max 0 into Math.nextDown(+0.0) = -Double.MIN_VALUE, which in sortable order lies below -0.0, so -0.0 falls between the two ranges. fromFloats, the mirror case (+0.0 against [-1, -0.0] and (-0.0, 1], where Math.nextUp(-0.0) skips +0.0) and range-on-range DoubleRange behave the same way.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f6bb9d218c0e (LUCENE-10274 / #841, 'Add FacetSets faceting capabilities', by mdmarshmallow; branch_9x backport #981, merge commit 0e1502c12ba, byte-identical for DimRange.java) [read]. Range-on-range reach: cbfed77fd33 (GitHub#11869 / #11901; branch_9x d9fc418914a), which copied the same stepping (with the comment 'Why no Math.nextDown?') from facet.range.DoubleRange.",
   "introduced_date": "2022-06-25 (f6bb9d218c0, author date 2022-06-25T07:27:11-07:00 on main; branch_9x backport merged the same day); range-on-range 2022-12-30 (cbfed77fd33)",
   "first_affected_version": "9.3.0 [exec]; range-on-range reach first in 9.5.0 [exec]; not a regression",
   "affected_versions": "Every release with facet sets: 9.3.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b), and main 5adff78bb168 (12.0.0-SNAPSHOT). Executed: the one-test repro fails '[-1, 0) + [0, 1] expected:<1> but was:<0>' on main -ea and -da, 10.6.0 -ea and -da, 9.3.0 -ea and -da, 9.12.3 -da and 10.0.0 -da (on 9.x to 10.3.x the test uses new MatchAllDocsQuery() in place of MatchAllDocsQuery.INSTANCE, nothing else); the independent reproduction's own test fails on main -ea and -da, 10.6.0 -da, 10.5.2 -ea and -da, 9.12.3 -ea and -da and 9.3.0 -da; 9.2.0 does not compile (no facetset package) [exec]. Range-on-range reach test (indexed [-0.0, -0.0], query ranges [-1, 0) and [0, 1] under INTERSECTS): fails on 9.5.0, 9.12.3 and 10.6.0 (-da) and on main (-ea and -da); 9.4.2 has no rangeonrange package [exec]. Releases between the executed ones by reading: the stepping lines and the matcher comparisons are unchanged in every releases/lucene tag from 9.3.0 to 10.6.0 [read]. Upstream main 1c2072f02843 (2026-11-02): both files unchanged since 2024-09-10 and 2022-12-30 (author dates) [read]. Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1131.html",
   "repro": "repro/LFV-1131/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-416",
   "priority": "low",
   "priority_rank": 555,
   "novelty": "known",
   "withheld": false,
   "area": "queries / function queries (FunctionRangeQuery range scorers: DoubleDocValues.getRangeScorer and the float default FunctionValues.getRangeScorer)",
   "title": "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",
   "summary": "You index documents whose DoubleDocValuesField \"d\" holds -Infinity, 0 and +Infinity and search new FunctionRangeQuery(new DoubleFieldSource(\"d\"), null, 5.0, false, true), which prints as frange(double(d)):{* TO 5.0]; you expect every value up to 5, -Infinity included, because the same query over a LongFieldSource keeps the Long.MIN_VALUE document and Lucene treats a null range endpoint as open (TermRangeQuery: 'Open endpoints may not be exclusive', normalized to inclusive). Instead only the 0 document matches: DoubleDocValues.getRangeScorer (and the float default in FunctionValues.getRangeScorer) replaces the null bound with -Infinity and then applies the exclusive flag to it (docVal > -Infinity), so the -Infinity document is dropped, and [0 TO *} drops the +Infinity document the same way.",
   "impact_class": "silent wrong results",
   "introduced_commit": "b3f0ae9b7a0 (LUCENE-3240, GitHub #4313, svn r1140379, 2011-06-27: moved Solr's DocValues, later FunctionValues, with the float-default getRangeScorer into Lucene's new queries module) and a993ae90323 (LUCENE-3249, GitHub #4322, svn r1140906, 2011-06-28: moved DoubleFieldSource with its double override, FloatFieldSource, LongFieldSource and IntFieldSource; from here stock Lucene sources show the bug); no pull request (svn and JIRA era; umbrella LUCENE-2883, #3957). The comparison code was written in Solr by SOLR-939 (6bd49091023, 2009-03-23), and git blame -w -M -C of every comparison and null-to-infinity line on main points there; LUCENE-5247 (9db7442d648, 2013) only moved the double code into DoubleDocValues, and LUCENE-6720 (13f8ab93a97 trunk / 88d137632d3 branch_5x, 2015-08-06, #7778) added FunctionRangeQuery on top without changing the comparisons [read]",
   "introduced_date": "2011-06-27 (Lucene, LUCENE-3240); code origin in Solr 2009-03-23 (SOLR-939)",
   "first_affected_version": "4.0.0-ALPHA [read] / 4.0.0 GA [exec] (3.6.2 has no org.apache.lucene.queries.function package: compile error [exec]); through the FunctionRangeQuery class since 5.4.0 [exec], before that through the public FunctionValues.getRangeScorer [exec]",
   "affected_versions": "every release from 4.0.0-ALPHA through 10.5.2 and main ea57360912ed (11.0.0-SNAPSHOT); not fixed upstream. [exec] the follow-up history probes (public API, three controls passing in each run) fail the 4 bug checks on 4.0.0, 4.10.4, 5.0.0 and 5.3.2 (FunctionValues.getRangeScorer called directly), and on 5.4.0, 6.6.6, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main (FunctionRangeQuery inside ConstantScoreQuery), all with -ea, and pass 7 of 7 with the candidate fix shadowed in; the finder's JUnit fails on main (-ea and -da), 10.5.2 (-ea) and 9.12.3 (-da; with -ea it stops first on the unrelated negative-score assertion in TopScoreDocCollector, LFV-406); the independent reproduction's JUnit fails 5 of 8 on main (-ea and -da), 10.5.2 (-ea and -da) and 9.12.3 (-ea); the intended-behaviour check re-ran the finder repro on main (-ea and -da), 10.5.2 (-da) and 9.12.3 (-da); 3.6.2 not applicable (API absent). [read] the comparison and null-to-infinity lines are unchanged since 2009, so the releases between the executed ones are affected; 4.0.0-ALPHA and -BETA were not executed (harness takes x.y.z only); the newest commits touching DoubleDocValues.java (d0d2aa274fb5, 2024-06-06) and FunctionValues.java (bfe5c847d3c4, 2026-07-27) do not change it. All runs on JDK 25.0.3, aarch64 Linux, not each release's own JDK.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16847",
    "https://github.com/apache/lucene/issues/7778",
    "https://issues.apache.org/jira/browse/LUCENE-6720",
    "https://github.com/apache/lucene/issues/7785",
    "https://issues.apache.org/jira/browse/LUCENE-6727",
    "https://github.com/apache/lucene/issues/6311"
   ],
   "doc": "",
   "repro": "repro/LFV-416/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1108",
   "priority": "low",
   "priority_rank": 556,
   "novelty": "new",
   "withheld": false,
   "area": "queries / function queries (DocTermsIndexDocValues.getRangeScorer: string ValueSource range matching behind FunctionRangeQuery)",
   "title": "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",
   "summary": "You run FunctionRangeQuery(new BytesRefFieldSource(\"f\"), \"016777217\", null, true, true) as a filter on a segment whose SORTED field f has more than 2^24 distinct values, and expect only documents whose value is at least \"016777217\". The document holding \"016777216\" matches too, with no error: getRangeScorer turns the string bounds into exact int ordinals but then compares each document's ordinal as a float, and above 2^24 neighbouring ordinals round to the same float. Only values within one float step of a bound are wrongly added; no in-range document is lost.",
   "impact_class": "silent wrong results",
   "introduced_commit": "b1ec1cd9e0ce3498945adaac67d497c226072ba7 (master) and its branch_8x backport e783f3729d63dff23fc82cd151c4348561b7966d (the copy that shipped first, in 8.6.0), LUCENE-9258 'DocTermsIndexDocValues should not assume it's operating on a SortedDocValues field' (apache/lucene#10298, migrated JIRA issue; JIRA patch, no GitHub PR; author micpalmia, committed by dsmiley). To support SortedSetSelector views it replaced the matches() body 'int ord = values.ordValue(); return ord >= ll && ord <= uu;' with 'float docVal = ordVal(doc); return docVal >= ll && docVal <= uu;' [read]. Later commits 8ef6a0da568 (reformat) and d0d2aa274fb (#13440) touched the method without changing the compare, and f3a284ad830 (LUCENE-9796) changed only bytesVal and strVal in the same file [read].",
   "introduced_date": "2020-03-11 (author date 16:56:10 -0400; committed 16:57:47 -0400 on master and 16:58:42 -0400 on branch_8x)",
   "first_affected_version": "8.6.0 [exec]; the string range scorer compared int ordinals from at least 4.0.0 through 8.5.2 [read], so this is a regression",
   "affected_versions": "every release from 8.6.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main e1faeba08bde (12.0.0-SNAPSHOT). Executed, all failing 'expected:<1> but was:<2>': the repro JUnit on main (-ea and -da), 10.6.0, 10.0.0, 9.12.3, 9.0.0, 8.11.4 and 8.6.0 (ports differ only in API spelling), an independent reproducer's own JUnit on 10.5.2 as well; 8.5.2 passes [exec]. Bytecode: matches(int) of DocTermsIndexDocValues$1 uses i2f/fcmp and no if_icmp in all 50 release jars 8.6.0-10.6.0, the reverse in 8.5.2 [read]. Real single-segment indexes without any wrapper: 16,777,218 unique SORTED values give wrong counts on main -da and 10.6.0 -da (by the independent reproducer) and on main ea57360912ed -ea/-da; the lead probes (16,777,220 and 16,777,224 documents) fail on main, 10.6.0, 9.12.3 and 8.6.0 and are clean on 8.5.2 [exec]. Not new in 10.6 (10.5.2 fails). Not fixed upstream: the newest upstream commit on DocTermsIndexDocValues.java on main (HEAD 3078a1ce833, checked 2026-11-02), branch_11x and branch_10_6 is d0d2aa274fb (#13440, 2024-06-06), which left the compare unchanged; no open PR touches the file [read]. Executed on Linux aarch64 with JDK 25.0.3 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1108.html",
   "repro": "repro/LFV-1108/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-879",
   "priority": "low",
   "priority_rank": 557,
   "novelty": "new",
   "withheld": false,
   "area": "misc / DocValuesStats double statistics (DocValuesStatsCollector, DocValuesStatsCollectorManager)",
   "title": "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",
   "summary": "You collect statistics for a double doc-values field with DocValuesStats.DoubleDocValuesStats (or SortedDoubleDocValuesStats) and expect mean(), documented as 'the mean of all values of the field', to be +Infinity for the values {+Infinity, 1.0}: that is sum()/count(), and it is what java.util.DoubleSummaryStatistics, the oracle of the upstream test, returns. Instead mean() is NaN, because the running update mean += (val - mean) / count computes Infinity - Infinity as soon as the running mean is infinite and another value arrives; {+Infinity, +Infinity} also gives NaN, while sum() and max() report +Infinity. The answer depends on document order ({1.0, +Infinity} gives +Infinity) and, since 10.5.0, on the searcher: with an executor and one segment per slice, DocValuesStatsCollectorManager rebuilds the mean from the sums and returns +Infinity.",
   "impact_class": "silent wrong results",
   "introduced_commit": "ad7152ad4739 (master, 'LUCENE-7590: add DocValuesStatsCollector', by shaie; JIRA LUCENE-7590, migrated as apache/lucene#8641; pre-GitHub patch workflow, no PR): DoubleDocValuesStats was created with mean += (val - mean) / count; the release line got it through the branch_6x commit 7269c484a4a0 (a re-commit after 43f4f7a2795 was reverted by e09ef681e4d); SortedDoubleDocValuesStats got the same update per value in 944b8e07f557 (master) / 63a5cd00173f (branch_6x) [read]; 0210af757c54 (#15653 'Introduce DocValuesStatsCollectorManager', by gaobinlong, co-author javanna, merged 2026-05-19, released in 10.5.0) added merge(), which rebuilds the mean as (sum + otherSum) / n: the source of the serial-versus-executor disagreement only, not of the NaN [read]",
   "introduced_date": "2016-12-11 (authored; committed to master and branch_6x 2016-12-14, DoubleDocValuesStats); 2016-12-17 (SortedDoubleDocValuesStats); 2026-05-19 (#15653, the executor path that disagrees)",
   "first_affected_version": "6.4.0 [exec] (6.3.0 has no DocValuesStats [exec]); the serial-versus-executor disagreement since 10.5.0 [exec] (10.4.0 has no DocValuesStatsCollectorManager [exec])",
   "affected_versions": "every release from 6.4.0 to 10.5.2, the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193. [exec] the follow-up's history probe (public-API main(): {+Inf, 1.0} and {+Inf, +Inf} with DoubleDocValuesStats, docs {+Inf},{1.0} with SortedDoubleDocValuesStats, plus controls) returns NaN, NaN, NaN on 6.4.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.4.0, 10.5.0, 10.5.2 and main (-ea and -da) while the controls are right, and returns +Infinity three times with the fix shadowed on main; the history step's manager JUnit fails 2 of 2 on 10.5.0, 10.5.2 and main; the finder's JUnit fails 2 of 2 on main (-ea and -da), branch_10_6 4ae946e5a9b and 10.5.2, and its collector-only form (repro/src-pre105) 1 of 1 on 10.4.0, 9.12.3 and 9.1.0; the independent reproduction's serial JUnit fails 6 of 7 on main (-ea and -da), 10.5.2 and 9.12.3 and its manager JUnit 1 of 1 on main (-ea and -da) and 10.5.2; the intended-behaviour check re-ran the finder's repro on main (-ea and -da), 10.5.2 and 9.12.3; all runs on JDK 25, also for releases that predate it. [read] the running-mean lines are present and unchanged at every release tag read; releases between the executed ones were not run one by one, and the 8.9-8.11 tags are not in the local history clone (8.11.4 was executed from release jars). 10.6.0 (released 2026-10-29) is affected: the doc's repro fails on its release jars with -ea and -da [exec]. Not fixed upstream: DocValuesStats.java was last changed by #15653 on main, branch_10x, branch_10_6, branch_9x and branch_9_12 (follow-up prior-report record, read 2026-10-28; upstream main re-checked 2026-10-28).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-879.html",
   "repro": "repro/LFV-879/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-940",
   "priority": "low",
   "priority_rank": 558,
   "novelty": "new",
   "withheld": false,
   "area": "benchmark / search-quality package (trec.TrecJudge, the qrels reader used by QualityBenchmark and QueryDriver)",
   "title": "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",
   "summary": "You evaluate search quality with QueryDriver or QualityBenchmark and a TREC qrels file read by TrecJudge, expecting a document to count as relevant only when its grade is 1 or more, as trec_eval counts it. TrecJudge instead treats every grade token except the exact string \"0\" as relevant, so documents graded -2 (spam or useless, in TREC Web track qrels) or -1 count as relevant: a junk page graded -2 that ranks above the only relevant page gives 2 relevant documents, P@1 1.0 and AP 1.0, where trec_eval gives 1, 0 and 0.5. There is no error or warning.",
   "impact_class": "silent wrong results",
   "introduced_commit": "98fa2d898d1882f0bee2ccb7401e1135efd05520, LUCENE-836 'Add support for search quality benchmarking' (SVN r560372, Doron Cohen; review venue JIRA LUCENE-836, migrated as apache/lucene#1911; no PR), which created TrecJudge with String zero = \"0\"; ... boolean relevant = !zero.equals(st.nextToken()); (now TrecJudge.java:57 and :70) [read]. Not a regression: the later commits on the file (LUCENE-1257 and LUCENE-2681 generics, LUCENE-2845 and LUCENE-3965 module moves, LUCENE-3949 license header, LUCENE-5512 diamond, a 2017 spelling fix, LUCENE-9570 reformat) left the parse loop unchanged",
   "introduced_date": "2007-07-27 (author date = commit date, 2007-07-27T20:24:52Z)",
   "first_affected_version": "2.3.0 (2008-01-23) [exec]; 2.2.0 has no search-quality package [exec]",
   "affected_versions": "Every release from 2.3.0 to 10.6.0 (the 154 lucene-benchmark versions on Maven Central up to 10.5.2, and 10.6.0 [exec] on its release jars by the bug doc's test, -ea and -da), plus branch_10_6 and main a9779ef3c193 [read] [exec]. Shadowing only TrecJudge.java with the fix sketch makes the portable repro pass on 2.3.0, 8.11.4 and 10.5.2. Not fixed on upstream main 645d4fe14a20 (2026-10-28): TrecJudge.java last changed by 7f8b7ffbcad (LUCENE-9570 reformat, author date 2021-01-03). All runs on Linux aarch64 with JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-940.html",
   "repro": "repro/LFV-940/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-937",
   "priority": "low",
   "priority_rank": 559,
   "novelty": "new",
   "withheld": false,
   "area": "benchmark / quality (utils.SubmissionReport, the TREC run-file writer used by QualityBenchmark and QueryDriver)",
   "title": "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",
   "summary": "You evaluate search quality with lucene/benchmark's SubmissionReport, for example through QueryDriver, whose usage text calls the output the 'submission file for trec_eval', and expect the score column of each TREC run line (qid Q0 docno rank score tag) to be a plain number. SubmissionReport formats scores with NumberFormat.getInstance(Locale.ROOT) and never turns grouping off, so a hit scoring 1200.5 is written as '1,200.5000'. trec_eval reads that column with C atof(), which stops at the comma and returns 1.0, and then re-sorts the run by the parsed score, so a run [1200.5, 900.25] is evaluated as [900.25, 1.0], with the top hit moved down, and the reported metrics are silently wrong.",
   "impact_class": "silent wrong results",
   "introduced_commit": "98fa2d898d1882f0bee2ccb7401e1135efd05520, LUCENE-836 'Add support for search quality benchmarking.' (author Doron Cohen; Subversion/JIRA-patch era, no PR; migrated as apache/lucene#1911): the constructor built NumberFormat.getInstance() with 4 fraction digits and never turned grouping off [read]. Related: LUCENE-1116 (9e65cd554f2e, 2008-01-03, also in 2.3.0) made the line the 6-column TREC run format; LUCENE-2058 (149a0c9b2588, 2009-11-13, first in 3.0.0) made QueryDriver write it as the 'output submission file for trec_eval'; LUCENE-4199 (3d964bea6364, 2012-07-08, first tag 4.0.0-beta) switched to Locale.ROOT and kept grouping.",
   "introduced_date": "2007-07-27 (LUCENE-836, author date of 98fa2d898d18)",
   "first_affected_version": "2.3.0 [exec] (released 2008-01-24, the first release with the quality package; 2.2.0 has no quality API [exec])",
   "affected_versions": "Every release from 2.3.0 to 10.6.0 (10.6.0 [exec] on its release jars by the bug doc's test, -ea) and main a9779ef3c193 [exec] [read]. In 2.3.0-3.6.2 the formatter followed the JVM default locale, so under a decimal-comma locale such as de_DE every score also lost its fraction ('999,5000' read as 999.0) [exec]; LUCENE-4199 removed that part with Locale.ROOT but left the grouping comma. All runs on aarch64 Linux with JDK 25, release jars checked against Maven Central SHA-1s.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-937.html",
   "repro": "repro/LFV-937/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-935",
   "priority": "low",
   "priority_rank": 560,
   "novelty": "new",
   "withheld": false,
   "area": "benchmark / search-quality evaluation (QualityStats)",
   "title": "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)",
   "summary": "You evaluate search quality with QualityBenchmark, average the per-query results with QualityStats.average(stats) and ask the average for its precision at 10, expecting the mean of the per-query P@10 values (which, like trec_eval's P_10, already count missing ranks as non-relevant). If the queries returned different numbers of results and their mean is below 10, getPrecisionAt(10) ignores the correct mean that average() stored and extrapolates again from the precision at the mean result count: with setMaxResults(10), a query whose 10 hits are all relevant (P@10 = 1.0) and a query whose only 2 hits are relevant (P@10 = 0.2) give 0.4 instead of 0.6. There is no error, and the printed SUMMARY never shows the affected cutoffs.",
   "impact_class": "minor",
   "introduced_commit": "98fa2d898d1882f0bee2ccb7401e1135efd05520, LUCENE-836 'Add support for search quality benchmarking' (SVN r560372; review venue JIRA LUCENE-836, migrated as apache/lucene#1911; no PR), which added the per-query n > numPoints extrapolation in getPrecisionAt and average() together [read]. Not a regression: later commits (LUCENE-1116 MRR and empty-input guard, 2021 reformat, #14228 for-each rewrite, #16255 renames) did not change the meaning",
   "introduced_date": "2007-07-27 (author date = committer date)",
   "first_affected_version": "2.3.0 [exec]; 2.2.0 has no search-quality package [exec]",
   "affected_versions": "Every release from 2.3.0 to 10.6.0 (10.6.0 [exec] on its release jars by the bug doc's test, -ea and -da), plus main a9779ef3c193 and branch_10_6 [read] [exec]. Not fixed on upstream main 645d4fe14a20 (2026-10-28): QualityStats.java last changed by #16255 (author date 2026-06-14, renames only). All runs on Linux aarch64 with JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-935.html",
   "repro": "repro/LFV-935/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-825",
   "priority": "low",
   "priority_rank": 561,
   "novelty": "new",
   "withheld": false,
   "area": "facet / taxonomy facets (TopOrdAndFloatQueue order of float-valued child labels in getTopChildren: float association and value-source facets)",
   "title": "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",
   "summary": "You aggregate a float weight per taxonomy label (FloatAssociationFacetField, or a DoubleValuesSource such as the expression clicks / impressions) and call getTopChildren(k), documented to return 'the topN child labels'. If one label's value is NaN (a=5, b=NaN, c=10), getTopChildren(1) returns [a (5.0)] although c=10 outranks a, and getTopChildren(2) returns [b (NaN), c (10.0)], so the top-1 is not even in the top-2, whatever rank NaN should get. TopOrdAndFloatQueue.OrdAndFloat#lessThan compares with < and > and otherwise falls back to the ordinal, so NaN ties with every value, the order is not transitive and the heap keeps the wrong labels; #12966 (9.11.0) let NaN-valued labels into this queue and, in the same change, ordered dims with the NaN-safe Float.compare.",
   "impact_class": "silent wrong results",
   "introduced_commit": "9ba4af7b883c (GITHUB#12966 'Reduce duplication in taxonomy facets; always do counts', by @stefanvodita, squash-merged to main; 9.x backport 42884fab46de / GITHUB#13358): it replaced the child admission test 'value > 0' (false for NaN) with 'count > 0' in TaxonomyFacets.getTopChildrenForPath, so a NaN-valued child now enters TopOrdAndFloatQueue (on 9.x the copy TopOrdAndFloatNumberQueue), whose < / > comparator with ordinal tie-break dates from the LUCENE-5339 facet rewrite (5458dbf2484f, by @mikemccand, merged as 9d0b60388da / 7477fde1cb0, in every release since 4.7.0) and could not see NaN before. The CHANGES entry of #12966 ('Aggregation facets no longer assume that aggregation values are positive', closes #12585) shows the wider admission was deliberate for non-positive values; NaN is not mentioned in #12585, #12966 or #13358. [read]",
   "introduced_date": "2024-04-05 (author and committer date of 9ba4af7b883c; PR opened 2023-12-22); backport 2024-05-14; the comparator itself 2013-11-14 (author date of 5458dbf2484f), latent until 2024",
   "first_affected_version": "9.11.0 [exec] on the 9.x line, 10.0.0 [exec] on the 10.x line; 9.10.0 passes [exec], because its 'value > 0' admission test kept NaN labels out of the queue (it silently omitted them and every non-positive label, the older behaviour that #12585 / #12966 changed on purpose, not this bug); 4.6.1 has no such API [exec]",
   "affected_versions": "9.11.0, 9.11.1, 9.12.3, 10.0.0, 10.5.2 and main a9779ef3c193 [exec]; 9.12.0-9.12.2 and 10.1.0-10.5.1 [read]; upstream main 20ced71c1e6e and branch_10_6 4ae946e5a9b9 carry a byte-identical TopOrdAndFloatQueue.java (blob f5c43fd6dca5, as in a9779ef3c193) [read], so the released 10.6.0 has it; the bug doc's repro also fails on the 10.6.0 jars (4ae946e5a9b, -ea and -da) [exec]. Not affected [exec]: 4.7.0, 4.10.4, 5.5.5, 8.11.4, 9.0.0, 9.1.0, 9.9.2 and 9.10.0 (API-adapted copy of the oracle; NaN labels dropped by the old admission test). Fix site per line: main and 10.x TopOrdAndFloatQueue.OrdAndFloat#lessThan; 9.11-9.12 the copy in TopOrdAndFloatNumberQueue.OrdAndFloat#lessThan (the 9.x TopOrdAndFloatQueue is the legacy, unused class). All runs on JDK 25, Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-825.html",
   "repro": "repro/LFV-825/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-427",
   "priority": "low",
   "priority_rank": 562,
   "novelty": "known",
   "withheld": false,
   "area": "grouping / function grouping (core util.mutable: MutableValueFloat and MutableValueDouble equality)",
   "title": "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)",
   "summary": "You group search hits by a float or double function, for example new DoubleFieldSource(\"v\") or a 0/0 division, and some documents have the value NaN; you expect them to form one NaN group, because MutableValueDouble's own hashCode (doubleToLongBits) and compareTo (Double.compare) treat every NaN as one value. Instead equalsSameType compares with ==, under which NaN is not even equal to itself, so on releases up to 10.5.2 every NaN document becomes its own group, each such group comes back with 0 documents and the NaN documents drop out of the grouped hit count. On main and, by reading, 10.6.0 the same search fails with IllegalArgumentException 'group values differ across shards', because the result merge compares the NaN group value with itself.",
   "impact_class": "silent wrong results",
   "introduced_commit": "0269c89b07f07e4783cf8a4fdcc59dfaeab136e4 (SOLR-1682 'field collapsing / grouping', yonik, Solr trunk, svn era, no PR) created MutableValueDouble and MutableValueFloat with equalsSameType = 'value == other.value' next to compareSameType = Double/Float.compare '// handles NaN' and a canonical-bits hashCode; bcf1dcccbe4 (SOLR-2198, 2010-11-23) gave the line its current form 'value == b.value && exists == b.exists' and kept the ==; LUCENE-3232 (9bf4c3fd8fe) and LUCENE-3274 (36330b50b43) moved the classes into Lucene core before any release, changing only package lines [read]",
   "introduced_date": "2010-08-21 (0269c89b07f, Solr trunk); current form of the line 2010-11-23 (bcf1dcccbe4); in Lucene core from 2011-07-06 (36330b50b43)",
   "first_affected_version": "4.0.0-ALPHA (2012, the first release with org.apache.lucene.util.mutable) [read]; first final release 4.0.0 [exec]; 3.6.2 and every earlier release lack the classes [exec]",
   "affected_versions": "every release from 4.0.0-ALPHA to 10.5.2 (all 123 release tags carry the identical == line) [read]; executed: 4.0.0, 4.1.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.4.0, 10.5.0 and 10.5.2 (wrong groups and counts, no error) and main ea57360912ed (IllegalArgumentException) [exec]; branch_10_6 (10.6.0) [read]; symptom by version: 4.0.0 also reports totalGroupCount 0 for every input (unrelated LUCENE-4581); 4.1.0 to 6.6.6 split the NaN groups but count totalGroupCount right (a TreeSet that uses compareTo); 7.0.0 to 10.5.2 also inflate totalGroupCount (LUCENE-7701 switched to a HashSet); not fixed upstream: the files are unchanged on upstream main, branch_10x, branch_10_6 and branch_10_5 (last change the 2020 LUCENE-9570 reformat) [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/6852",
    "https://issues.apache.org/jira/browse/LUCENE-5790",
    "https://github.com/apache/lucene/issues/13292",
    "https://github.com/apache/lucene/issues/6001",
    "https://issues.apache.org/jira/browse/LUCENE-4937",
    "https://github.com/apache/lucene/issues/10409"
   ],
   "doc": "",
   "repro": "repro/LFV-427/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-820",
   "priority": "low",
   "priority_rank": 563,
   "novelty": "new",
   "withheld": false,
   "area": "facet / taxonomy facets (TaxonomyFacets#getAllDims ordering of float-valued dims: float association and value-source facets)",
   "title": "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)",
   "summary": "You aggregate float values per taxonomy dim (FloatAssociationFacetField weights or a DoubleValuesSource) and call getAllDims, documented to sort dims by value, and getTopDims, documented to return the same as the first entries of getAllDims. If one dim's value is NaN (dims a=1, b=NaN, c=2), getAllDims can return [a=1.0, b=NaN, c=2.0], with a ahead of c, while getTopDims(1, 10) returns [b=NaN]; with 32 or more dims, getAllDims can instead throw IllegalArgumentException 'Comparison method violates its general contract!' from List.sort. The getAllDims comparator compares doubleValue() with > in both directions and falls back to the dim name, so NaN ties with every value and the order is not transitive, while getTopDims has used the NaN-safe Float.compare (valueComparator) since #12966 (9.11.0).",
   "impact_class": "silent wrong results",
   "introduced_commit": "51265435699d (LUCENE-5339 development branch, svn r1543202, author Michael McCandless, 'LUCENE-5339: add base class for taxo facet impls; catch wrong index field name for a given dim'): it added TaxonomyFacets.getAllDims with the value-descending < / > comparator on doubleValue(); the per-class getAllDims comparators it replaced compared value.intValue(), a total order. It reached releases through the trunk merge 9d0b60388da and the branch_4x backport 7477fde1cb0 ('LUCENE-5371, LUCENE-5339: ... simplify facet APIs'); JIRA LUCENE-5339 (GitHub mirror #6403), no PR (svn era). Later edits kept the logic: 034595f5e9f (2013-12-02, final tie-break by dim name), cfe57ec320b (2013-12-31, BY_VALUE_THEN_DIM), 8db1e41fc07 (LUCENE-10585, #915, 2022, List.sort) and 644feeb02a9 (#13795, 2024, inlined as a lambda). The default association path reaches the comparator since 9ba4af7b883 (#12966, 2024-04-05; 9.x backport 42884fab46d / #13358, first released in 9.11.0), which stopped dropping labels whose value is not > 0 and moved getTopDims and the queues, but not getAllDims, to valueComparator. [read]",
   "introduced_date": "2013-11-18 (author date of 51265435699d); 2014-01-04 (merged to trunk and branch_4x); the default association path since 2024-04-05 (#12966)",
   "first_affected_version": "4.7.0 [exec] (released 2014-02-25, the first release with the Facets/getAllDims API; there on the value-source path with multiValued + requireDimCount dims, whose value is the dim ordinal's own aggregate); the default single-valued FloatAssociationFacetField path from 9.11.0 [exec] (9.10.0 drops NaN labels on that path [exec]); 4.6.1 has no such API [exec]",
   "affected_versions": "Every release from 4.7.0 to 10.6.0 and main a9779ef3c193; not fixed upstream. [exec] The follow-up's portable main() repro (a value-source path and an association path, with controls that replace NaN by 1.5 and pass everywhere) fails on 18 sampled releases (4.7.0, 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.1.0, 9.2.0, 9.10.0, 9.11.0, 9.12.3, 10.0.0, 10.5.2) and main: the value-source path misorders and throws on all of them, the association path from 9.11.0 on, and the getTopDims prefix check fails from 9.2.0, the first release with getTopDims. The finder's JUnit fails 3 of 3 on main (-ea and -da), 10.5.2, 10.0.0, 9.12.3 and 9.11.0; the independent reproduction's JUnit fails 4 of 5 on main (-ea and -da), 10.5.2, 9.12.3 and 9.11.0, and the independent reproduction's value-source JUnit fails on main and 9.10.0; the intended-behaviour check's JUnit fails 4 of 5 on main (-ea and -da), 10.5.2 and 9.11.0. Releases between the sampled ones were not run; git log -L shows the comparator logic unchanged across them. [read] upstream main 20ced71c1e6e and branch_10_6 4ae946e5a9b9 have the same comparator, so the released 10.6.0 has it; its release jars fail the tie-break tests with -ea and -da [exec]. All runs on JDK 25 (Linux aarch64); the exception needs a sort that checks the Comparator contract (TimSort, the default since Java 7), and symptoms on the Java 6 runtimes of the 4.x era were not executed.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-820.html",
   "repro": "repro/LFV-820/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-212",
   "priority": "low",
   "priority_rank": 564,
   "novelty": "new",
   "withheld": false,
   "area": "spatial3d / geom circles (GeoStandardCircle cut plane and SidedPlane sidedness, behind Geo3DPoint.newDistanceQuery and GeoCircleFactory.makeGeoCircle)",
   "title": "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",
   "summary": "You build a Geo3D distance query with a very small radius, for example Geo3DPoint.newDistanceQuery with 1.24 cm, and expect it to match only points near the centre, or to be rejected as too small. The circle's cut plane passes within about r^2/2 of the circle's centre (here about 2e-18), far below double rounding, and SidedPlane takes the plane's inside from the sign of evaluate(center), which at that size is rounding noise. When the noise has the wrong sign the circle is the whole planet minus a speck (below about 1 mm, minus a patch of up to a few hundred metres near the centre), and the query silently returns every indexed point outside it: in the repro, all 3 documents thousands of kilometres away.",
   "impact_class": "silent wrong results",
   "introduced_commit": "bde056c763231cd4f35acbc708cfc07dc181b1fc (LUCENE-6196 'Geo3d initial checkin', issue #7258, contributed by DaddyWri and committed by dsmiley on the svn branch lucene6196; reached trunk through merge f760a51f80d3 and branch_5x through 536ae683ff6a; svn era, no PR) [read]. The flaw survived two rewrites: LUCENE-6544 (trunk 03408382767, branch_5x 226f69dd68b6, 2015-06-18, issue #7602, first released in 5.3.0) built today's rim-point plane with SidedPlane.constructNormalizedPerpendicularSidedPlane, still sided by signum(evaluate(center)); LUCENE-6699 (trunk 03e5bcfa739c, branch_5x 31b17203f2c0, 2015-09-02, issue #7757, first released in 5.4.0) added the exact-zero guard that turns about half of the tiny circles into the 'probably too small' IllegalArgumentException",
   "introduced_date": "2015-04-13 (branch commit); 2015-05-06 (merged to trunk and branch_5x)",
   "first_affected_version": "5.2.0 [exec] (first release with geo3d; 5.1.0 has no geo3d package, so the probe does not compile there); the public query API Geo3DPoint.newDistanceQuery first appears in 6.1.0, which fails [exec]",
   "affected_versions": "5.2.0 to 10.6.0 and main ea57360912ed. [exec] fails on 5.2.0 (-ea and -da), 5.2.1, 5.3.0, 5.4.0, 5.5.5, 6.0.0, 6.1.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.4.1, 8.5.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) (41 follow-up history runs with three repros: the canonical JUnit, a 200-query end-to-end sweep and a shape-level sweep; every control run matched nothing); the finder's JUnit, the independent reproduction's repro and the intended-behaviour check's shape check also fail on 10.5.2 and 9.12.3. [read] releases between the tested points are inferred from the continuous history of the defective lines. Not fixed: upstream main is the tested commit and no commit since 2023 changed the logic of GeoStandardCircle, SidedPlane, GeoCircleFactory or GeoStandardPath (follow-up prior-report record). 10.6.0 (released 2026-10-29) [exec]: the bug doc's minimal JUnit (derived from the finder's) fails 1 of 1 on the 10.6.0 release jars with -ea and -da.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-212.html",
   "repro": "repro/LFV-212/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-187",
   "priority": "low",
   "priority_rank": 565,
   "novelty": "known",
   "withheld": false,
   "area": "search / phrase queries (SloppyPhraseMatcher repetition groups: gatherRptGroups, non-multi-term branch)",
   "title": "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",
   "summary": "You index text into a field whose analysis can put two words at one position (for example an index-time synonym) and search with a sloppy phrase such as \"a b a b\"~1, in which two different words each repeat; you expect every document within the slop, and certainly every document that holds the exact phrase, to match, whatever other documents share its segment. SloppyPhraseMatcher works out which phrase positions repeat each other only once per segment, on the first candidate document, and groups them by equal position in that document rather than by term, so when that document has a and b stacked at one position both words land in one group and the matcher then asks for more occurrences than exist. That document and later documents of the segment are missed with no error: in the two-document repro the plain document 'a b a b' matches with slop 0 but not with slop 1, while the same document indexed alone matches with slop 1.",
   "impact_class": "silent wrong results",
   "introduced_commit": "c54608b60dc6fb3e451dd1d3c430cf42c38f5fb5 (trunk r1173961, 2011-09-22, LUCENE-3215 'SloppyPhraseScorer sometimes computed Infinite freq', Doron Cohen; branch_3x a398352a0cbc09542c07a64ba5b35569f13ea77d, r1174002, same day): it introduced repetition groups built once per scorer from equal first-document positions, without a term check; git blame on main attributes 'int tpPos = tpPos(pp);' and '|| tpPos(pp2) != tpPos) { // not a repetition' in gatherRptGroups (SloppyPhraseMatcher.java:565, 570) to it. Widened by LUCENE-3821 (branch_3x cf54f6523f9a50cc92c46f89ae84667a764f6cc3, r1299077, 2012-03-09; trunk 187bfe2ebc4555e93b71d6fe463d14d1a3b45932, r1299112, 2012-03-10), which added rptGroups, gatherRptGroups and advanceRepeatGroups (advance group member j by j positions) and made a later exact-phrase document fail too [read]",
   "introduced_date": "2011-09-22 (root cause, LUCENE-3215); 2012-03-09/10 (exact-phrase symptom, LUCENE-3821)",
   "first_affected_version": "3.5.0 [exec] (a later document without stacked tokens, 'b a b a' at slop 2, is missed after a stacked first document); 3.6.0 [exec] for the candidate's exact-phrase repro; first 4.x: 4.0.0-alpha contains both trunk commits [read], 4.0.0 executed",
   "affected_versions": "Every release from 3.5.0 to 10.5.2 and main ea57360912ed: 127 release tags in the history clone (3.5.0, 3.6.0-3.6.2, 4.0.0-alpha .. 10.5.2; git tag --contains c54608b60dc / a398352a0cb) plus 8.8.2-8.11.4, which the clone does not tag [read]; the exact-phrase variant in all of them except 3.5.0. [exec] version-adapted history repro (same documents, query and assertion): 3.5.0, 3.6.0 (-ea, -da), 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea, -da) fail; the unchanged candidate JUnit fails on 9.1.0, 9.12.3 (-ea, -da), 10.5.2 (-ea, -da) and main (-ea, -da); the independent reproduction's independent test fails on 8.11.4, 9.12.3, 10.5.2 and main (-ea, -da); the intended-behaviour check's public-analyzer checks fail on 10.5.2 and main (-ea, -da). Not affected by the cross-document effect in these checks: 2.1.0 to 3.4.0 (but the stacked document itself has been missed since 2.2.0, a LUCENE-3068-family symptom; see notes). Not fixed: upstream main and branch_10x still contain the position test (read-only check 2026-10-26).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/4141",
    "https://issues.apache.org/jira/browse/LUCENE-3068",
    "https://issues.apache.org/jira/browse/LUCENE-3821",
    "https://github.com/apache/lucene/issues/4894",
    "https://github.com/apache/lucene/issues/16851",
    "https://github.com/apache/lucene/issues/4288"
   ],
   "doc": "",
   "repro": "repro/LFV-187/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-193",
   "priority": "low",
   "priority_rank": 566,
   "novelty": "known",
   "withheld": false,
   "area": "search / phrase queries (SloppyPhraseMatcher repetition groups: gatherRptGroups same-offset exclusion, collide, advanceRepeatGroups, sortRptGroups tie order)",
   "title": "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",
   "summary": "You build a sloppy phrase query by hand with two entries at the same position, for example PhraseQuery a@0 a@1 a@1 (the second 'a' added twice at position 1), and expect slop 1 to match everything slop 0 matches and the query to give the same answer every time it runs. SloppyPhraseMatcher's rule that two entries from one query position are not repetitions of each other is checked only pairwise, so a third entry (a@0) pulls both into one repetition group and the matcher then forces them onto different document positions: the document 'a a' matches with slop 0 but not with slop 1 to 4. For MultiPhraseQuery the same collision is resolved in HashSet iteration order, because groups are sorted by offset only, so the one immutable query (a|b)@0 b@2 a@2 ~2 on one unchanged reader matches the document a@0, a@1 with b@1 stacked, a@2 in about half of 200 evaluations and misses it in the rest, with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "c54608b60dc6fb3e451dd1d3c430cf42c38f5fb5 (trunk r1173961, 2011-09-22, LUCENE-3215 'SloppyPhraseScorer sometimes computes Infinite freq', apache/lucene#4288; branch_3x backport a398352a0cbc09542c07a64ba5b35569f13ea77d, r1174002, same day) for the PhraseQuery manifestation: the rewrite replaced the pairwise conflict check that LUCENE-3068 (3.2.0) had made skip equal-offset pairs with repeat chains that test the equal offset only against the chain's first PP. The MultiPhraseQuery nondeterminism came with LUCENE-3821 (apache/lucene#4894, still open; branch_3x cf54f6523f9a50cc92c46f89ae84667a764f6cc3, r1299077, 2012-03-09; trunk 187bfe2ebc4555e93b71d6fe463d14d1a3b45932, r1299112, 2012-03-10), which brought HashSet<PhrasePositions> back for multi-term repeat groups with an offset-only sort. git blame on main attributes the grouping-loop lines (SloppyPhraseMatcher.java:565, 570-572) to c54608b60dc and lesser(), collide(), advanceRepeatGroups(), sortRptGroups() and most of gatherRptGroups() to 187bfe2ebc4. No pull request (SVN-era JIRA patches). [read]",
   "introduced_date": "2011-09-22 (PhraseQuery manifestation, LUCENE-3215); 2012-03-09 branch_3x / 2012-03-10 trunk (MultiPhraseQuery nondeterminism, LUCENE-3821)",
   "first_affected_version": "3.5.0 [exec] for the PhraseQuery manifestation (3.4.0 passes); 3.6.0 [exec] for the MultiPhraseQuery nondeterminism (3.5.0 is deterministic)",
   "affected_versions": "Every release from 3.5.0 (PhraseQuery manifestation) and 3.6.0 (MultiPhraseQuery nondeterminism) to 10.6.0 (10.6.0 by reading), and main ea57360912ed [read]. [exec] fails: 3.5.0 (PhraseQuery only, -ea and -da), 3.6.0 (both; MultiPhraseQuery also -da), 3.6.2, 4.0.0, 4.10.4, 5.0.0, 5.5.5 (version-adapted main() ports with the same documents and queries), 6.0.0, 6.6.6, 7.7.3, 8.11.4 and 9.0.0 (the independent reproduction's 8.x-package JUnit port, 3 of 4 fail, control passes), 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) with the candidate JUnit (2 of 2 fail). [exec] not affected: the PhraseQuery case passes on 3.2.0, 3.3.0 and 3.4.0 (3.4.0 with -ea and -da); the MultiPhraseQuery case is deterministic on 3.1.0, 3.2.0, 3.4.0 and 3.5.0 (200 of 200 matches in both add orders). 3.1.0 also misses the PhraseQuery document, for the older reason LUCENE-3068 fixed in 3.2.0 (no same-offset exclusion at all; the control b@0 a@1 a@1 on 'b a' fails there too and passes from 3.2.0 on). Single-commit file swaps confirm both introductions: the LUCENE-3215 files on 3.4.0 fail and the files before it on 3.5.0 pass; the LUCENE-3821 files on 3.5.0 are nondeterministic and the files before it on 3.6.0 are deterministic. branch_10_6 and branch_10x not executed (SloppyPhraseMatcher.java and PhrasePositions.java byte-identical to 10.5.2 as fetched 2026-10-24). Not fixed upstream: the repeat-group code is unchanged since 2012 on main, branch_10x and branch_10_6 (read-only check 2026-10-26).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/4894",
    "https://issues.apache.org/jira/browse/LUCENE-3821",
    "https://github.com/apache/lucene/issues/4141",
    "https://issues.apache.org/jira/browse/LUCENE-3068",
    "https://github.com/apache/lucene/issues/4485",
    "https://issues.apache.org/jira/browse/LUCENE-3412"
   ],
   "doc": "",
   "repro": "repro/LFV-193/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-465",
   "priority": "low",
   "priority_rank": 567,
   "novelty": "new",
   "withheld": false,
   "area": "search / IndexSearcher#count (two-clause term-disjunction shortcut, GITHUB#13036) under IndexSearcher#setTimeout",
   "title": "IndexSearcher#count on a two-term disjunction over-counts, even above maxDoc, when the searcher timeout fires while the intersection is counted",
   "summary": "You set a timeout with IndexSearcher#setTimeout and call IndexSearcher#count on a query like `a OR b`, where term b matches far fewer documents than term a, on an index without deletions. When the timeout fires you expect a partial count, at most the number of matching documents, which is what every other count and collect path returns under the same timeout (and what this path returned up to 9.9.2). Instead count() returns count(a) + count(b) minus a cut-short count of `a AND b`, which is too high (1041 for a 1000-document index with 955 matches when the deadline has already passed) and gets smaller, not larger, when the timeout fires later; timedOut() is true.",
   "impact_class": "silent wrong results",
   "introduced_commit": "c845bf02fefc3fa5c70a811fa086fb890f7a7add (branch_9x backport, committed by jpountz, first released in 9.10.0) and b537e1da2760df5b52f4e5610df89e58c51c1a5f (main, first released in 10.0.0): GITHUB#13036 'Optimize counts on two clause term disjunctions' by jfreden, merged by jpountz (origin issue #12644). It added the count(a) + count(b) - count(a AND b) shortcut to IndexSearcher#count with a guard that checks deletions and query shape but not the timeout, on top of the IndexSearcher#setTimeout feature of LUCENE-10151 / #927 (af05550ebfe on main, aa082b46f66 on branch_9x, 2022-06-29, first released in 9.3.0) [exec] [read]",
   "introduced_date": "2024-02-01 (both commits; #13036 merged 2024-02-01)",
   "first_affected_version": "9.10.0 [exec] on the 9.x line (via c845bf02fefc); 10.0.0 on the 10.x line [exec]; 9.9.2 (released 2024-01-29) and every release back to 9.3.0 are not affected [exec]; before 9.3.0 IndexSearcher#setTimeout does not exist [read]",
   "affected_versions": "9.10.0, 9.11.0, 9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2, 10.6.0 (release jars [exec], below) and main ea57360912ed [exec]. Not affected: 9.3.0-9.9.2 [exec]; before 9.3.0 there is no IndexSearcher#setTimeout [read]. 10.6.0 (released 2026-10-29) fails the doc's repro on its release jars with -ea and -da [exec]. Not checked: unreleased 10.7.0, x86 (all runs aarch64, JDK 25). Not fixed upstream: upstream main 49483e82b35 (2026-10-26) keeps the guard without a timeout check, and no open PR changes it [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-465.html",
   "repro": "repro/LFV-465/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-117",
   "priority": "low",
   "priority_rank": 568,
   "novelty": "known",
   "withheld": false,
   "area": "search / kNN query rewrite (AbstractKnnVectorQuery optimistic re-entry pass) under the IndexSearcher timeout",
   "title": "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",
   "summary": "You set a timeout with IndexSearcher#setTimeout and run a kNN query on an index with several segments; Lucene searches every segment once and, if that first pass completed, searches the segments that supplied the best hits a second time to improve the answer. You expect a timeout to give you the partial results found so far ('Return partial results only when timeout is met', AbstractKnnVectorQuery.java:296), so hits that the complete first pass already found are kept. Instead, when the timeout fires during the second pass, each re-entered segment's cut-short second-pass result (usually empty) replaces its first-pass hits, so the query keeps fewer or farther hits than a slightly earlier timeout would have given, down to 0 hits (IndexSearcher#count goes 6 -> 0 when one more timeout check is allowed).",
   "impact_class": "silent wrong results",
   "introduced_commit": "d279af1961f4 on main (branch_10x backport 61424c489e65), PR #14226 'OptimisticKnnVectorQuery' (msokolov): it added the second (re-entry) pass, run under indexSearcher.getTimeout(), and runSearchTasks' unconditional perLeafResults.put that replaces a re-entered leaf's first-pass TopDocs [read]; the partial fix 92e0eb8f71e2 (PR #14640, fixes #14639, msokolov; branch_10x 6643f7ea6384) added only the gate 'first-pass relation == EQUAL_TO' (AbstractKnnVectorQuery.java:125) and shipped in the same releases, so no release had the second pass without that gate [read]; prerequisite: df154cdc228 (#13202, 9.11.0) made the kNN rewrite honour IndexSearcher#setTimeout [read]",
   "introduced_date": "2025-05-05 (#14226 merged on main); 2025-07-17 (branch_10x backport, committer date); the #14640 gate 2025-05-12 on main and 2025-07-17 on branch_10x",
   "first_affected_version": "10.3.0 [exec] (10.2.2 and every earlier release executed are not affected [exec]: they have no second pass)",
   "affected_versions": "10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main ea57360912ed [exec]. Not affected [exec]: 9.10.0, 9.11.0, 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.2.1 and 10.2.2 (no second pass; 9.x never received #14226; before 9.11.0 the kNN rewrite does not consult setTimeout at all). Not executed: 10.6.0 (not on Maven Central as of 2026-10-26); branch_10x and branch_10_6 carry the same gate and the same unconditional put [read]. Not fixed upstream at main ea57360912ed [read]; open PR #16866 keeps the replacement [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/14639",
    "https://github.com/apache/lucene/issues/14640",
    "https://github.com/apache/lucene/issues/16866",
    "https://github.com/apache/lucene/issues/14226",
    "https://github.com/apache/lucene/issues/14962",
    "https://github.com/apache/lucene/issues/13202"
   ],
   "doc": "",
   "repro": "repro/LFV-117/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-091",
   "priority": "low",
   "priority_rank": 569,
   "novelty": "new",
   "withheld": false,
   "area": "index / doc values (single-valued SortedSetDocValues view, DocValuesRangeIterator)",
   "title": "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",
   "summary": "You take the SortedSetDocValues of a segment whose documents have at most one value each (DocValues.getSortedSet and LeafReader#getSortedSetDocValues then return a single-valued wrapper), call intoBitSet(upTo, ...), and read nextOrd() for the document the iterator now sits on; or you pass that view to DocValuesRangeIterator.forOrdinalRange on a skip-indexed field and load the matches in bulk. You expect nextOrd() to describe the current document, as after the nextDoc() loop that the intoBitSet javadoc says it behaves exactly like, and the range iterator to mark only documents whose value is in range. Instead the wrapper's intoBitSet moves the inner iterator without refreshing its cached ordinal, so with two documents a and b nextOrd() on doc 1 returns a's ordinal, and forOrdinalRange for [b, b] also marks doc 8192, whose value is a.",
   "impact_class": "silent wrong results",
   "introduced_commit": "cebfb0f415b4 (#14618 'Impl intoBitset and docIdRunEnd for wrappers', main; branch_10x backport f2319c52ea90), which added the delegating intoBitSet override [exec]. Regression: before it the inherited DocIdSetIterator#intoBitSet loop called the wrapper's own nextDoc(), which refreshes the ordinal. The visible forOrdinalRange extra hit also needs the SortedSetDocValues factory (#15989) and the batched sorted-set range path (#16172), both first released in 10.5.0; they rely on the intoBitSet contract that #14618 broke and are not themselves the defect [read]",
   "introduced_date": "2025-05-09 (#14618 merged); range-iterator consequence reachable from 2026-06-05 (#16172 merged)",
   "first_affected_version": "10.3.0 (root cause) [exec]; 10.5.0 for the forOrdinalRange extra hit [exec]",
   "affected_versions": "root cause: 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2, branch_10_6 d04ee7317726 (10.6 line; 10.6.0 released 2026-10-29) and main ea57360912ed [exec]; forOrdinalRange extra hit: 10.5.0, 10.5.1, 10.5.2, branch_10_6 and main [exec]; 10.4.0 has no such factory (the full test does not compile) [exec]; not affected: 10.2.0-10.2.2 (no override, the default loop calls the wrapper's nextDoc) [exec]; not applicable: 10.1.0 and earlier, including 9.12.3 (SortedSetDocValues#intoBitSet absent, compile error) [exec]; the file is unchanged since #14618 on upstream main, branch_10x and branch_10_6 [read]; main 645d4fe14a2 [exec]; SingletonSortedSetDocValues.java has the same blob on main 645d4fe14a2, branch_10x 657014b3c57 and branch_10_6 4ae946e5a9b (10.6.0 RC1) [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-091.html",
   "repro": "repro/LFV-091/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-415",
   "priority": "low",
   "priority_rank": 570,
   "novelty": "known",
   "withheld": false,
   "area": "codecs / doc values (Lucene90 sparse multi-valued sorted-numeric rangeIntoBitSet)",
   "title": "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)",
   "summary": "On a default-codec index with docs {0: [1,3], 1: no value, 2: [5,7]} in a multi-valued numeric doc-values field, you call advanceExact(1) on the field's SortedNumericDocValues (it returns false) and then rangeIntoBitSet(1, 3, 1, 3, bits, 0) on the same iterator. You expect no bit, because neither doc 1 nor doc 2 has a value in [1, 3], and that is what the method's documented per-document default returns from the same state. Instead the codec's override evaluates doc 1 with doc 0's values and marks it (in a DENSE block it uses the next valued document's values), and when no earlier document has values ({0: no value, 1: [1,3], 2: [5,7]}, advanceExact(0) then rangeIntoBitSet(0, 3, 1, 3, ...)) it throws ArrayIndexOutOfBoundsException: Index -1.",
   "impact_class": "silent wrong results",
   "introduced_commit": "1c99a1eccf9c2fb09a25da081d6857b5faf85232 (GITHUB#16166 'Add batch evaluation for sorted numeric ranges', by GitHub costin, merged by romseygeek; branch_10_5 backport ad06ebcc7130c4d956e2461186b52d0d92e3a0f5 with the same hunks) added both the public method SortedNumericDocValues#rangeIntoBitSet and the Lucene90 sparse override with the unguarded start check [read]. Not a regression: the defect is as old as the API. The only later change to the method, #16285 (263c3a4765f, 2026-07-13, main and branch_10_6 only), added the GCD raw-value path and left the start-state lines unchanged",
   "introduced_date": "2026-06-10 (1c99a1eccf9 on main and the backport ad06ebcc713 on branch_10_5)",
   "first_affected_version": "10.5.0 [exec] (the first release with SortedNumericDocValues#rangeIntoBitSet; 10.4.0 has no such API [exec])",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2 and main ea57360912ed [exec]; not applicable to 10.4.0, 9.12.3 and older (the API is absent; the repro does not compile) [exec]; branch_10_6 (10.6.0, released 2026-10-29) has the same lines [read]; upstream main (last change to the file 1160d3c8a25, 2026-09-11; Lucene90DocValuesProducer.java:2210-2213 still unguarded, re-checked read-only 2026-10-26), branch_10_6 and branch_10x unfixed [read]; open PR #16835 would fix table-encoded entries only",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16835",
    "https://github.com/apache/lucene/issues/16166",
    "https://github.com/apache/lucene/issues/16253",
    "https://github.com/apache/lucene/issues/14529",
    "https://github.com/apache/lucene/issues/16832",
    "https://github.com/apache/lucene/issues/16869"
   ],
   "doc": "",
   "repro": "repro/LFV-415/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-142",
   "priority": "low",
   "priority_rank": 571,
   "novelty": "new",
   "withheld": false,
   "area": "index / MultiDocValues merged norms view (also the merged reader passed to MergePolicy.OneMerge#reorder)",
   "title": "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",
   "summary": "You read the norms of a multi-segment index as one merged iterator (MultiDocValues.getNormValues(reader, \"body\"), or LeafReader#getNormValues on the merged reader that IndexWriter hands to a custom OneMerge#reorder), where doc 0's segment has the text field \"body\", docs 1-2 sit in a segment without it and doc 3's segment has it again, and call advance(1) on a fresh iterator. You expect 3, the first document at or after the target that has a norm, as the DocIdSetIterator#advance contract says and as the merged numeric doc-values view of the same index returns. Instead advance(1) returns 0, a document before the target, because advance() falls back to nextDoc() before it records which segment comes next, so nextDoc() restarts from the first segment; queries over that view inherit the backward step (FieldExistsQuery with intra-segment partitions returns [0, 0, 0, 3] instead of [0, 3], and a conjunction can return a document that fails one of its FILTER clauses).",
   "impact_class": "minor",
   "introduced_commit": "f7aa200d406 (f7aa200d406dbd05a35d6116198302d90b92cb29) 'LUCENE-7407: switch doc values usage to an iterator API, based on DocIdSetIterator, instead of random acces, freeing codecs for future improvements' by mikemccand (JIRA LUCENE-7407, migrated as apache/lucene#8460; JIRA patch workflow, no GitHub PR): in the norms view's new advance() the assignment 'nextLeaf = readerIndex+1' comes after the early 'if (currentValues == null) return nextDoc();', while the numeric and binary views written in the same commit assign it before the null check; not a regression [read]",
   "introduced_date": "2016-09-21",
   "first_affected_version": "7.0.0 [exec]; public OneMerge#reorder path from 9.9.0 [read]",
   "affected_versions": "every release 7.0.0 through 10.6.0 (7.x, 8.x, 9.x, 10.x; the 10.6.0 release jars fail with -da [exec]) and main ea57360912ed; never fixed. Direct test executed failing: 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.3.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) [exec]; independently re-run by the independent reproduction on main (-ea and -da), 10.5.2 and 9.12.3 [exec]; 8.8.2-8.11.3 are not tagged in the history clone and are inferred affected between 8.8.1 (contains the commit) and 8.11.4 (fails) [read]; other releases by unchanged code (git tag --contains lists all 65 release tags 7.0.0-10.5.2) [read]. Public OneMerge#reorder path: 9.12.3, 10.5.2 and main (-ea and -da) fail [exec]; 9.9.0-9.11.x (two-argument hook) not executed [read]; absent before 9.9.0. Search-level effects: FieldExistsQuery duplicates with intra-segment partitions on main (-ea and -da) and 10.5.2 [exec]; FILTER-restriction bypass on main and 10.5.2 with -da [exec]. Not affected: 6.x and older (no doc-values iterator API) [exec]. Upstream main and branch_10x still have the code (MultiDocValues.java last changed 2023-10-11, formatting only) [read]; open PRs #14475 and #16847 keep the ordering [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-142.html",
   "repro": "repro/LFV-142/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-419",
   "priority": "low",
   "priority_rank": 572,
   "novelty": "new",
   "withheld": false,
   "area": "index / SortedDocValues bulk ordinal range (default implementation; Lucene90 sparse SORTED iterator)",
   "title": "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)",
   "summary": "On a default-codec index with docs {0: 'a', 1: no value, 2: 'b'} in a SORTED doc-values field, you call advanceExact(1) on the field's SortedDocValues (it returns false) and then ordinalRangeIntoBitSet(1, 3, ord(a), ord(a), bits, 0) on the same iterator. You expect no bit, because neither doc 1 nor doc 2 has the value 'a', and that is what the per-document advanceExact/ordValue evaluation the javadoc describes returns. Instead the default starts at docID() == 1, calls ordValue() there (which the API calls illegal after a false advanceExact), gets doc 0's ordinal and marks doc 1; with {0: no value, 1: 'a', 2: 'b'} and advanceExact(0), the same call throws RuntimeException(EOFException).",
   "impact_class": "silent wrong results",
   "introduced_commit": "04d33b4ce5dd9f0466ce7b525c3ef5a770925eb2 (GITHUB#16180 'add bulk intoBitSet for SortedDocValues ordinal ranges', by GitHub iprithv, merged by jimczi, milestone 10.6.0; branch_10x cherry-pick 8c58bbf22ba, contained in branch_10_6) added both the public method and its faulty default [exec]. Inside the PR, the first revision f5a83a8d11a (2026-07-04) used a correct per-doc advanceExact loop; after a review question about using advance/nextDoc instead, revision 03ccba9729b (2026-07-27) switched to the 'docID() >= fromDoc ? docID() : advance(fromDoc)' start and left the javadoc unchanged. Not a regression of a released API: the bug is as old as the method",
   "introduced_date": "2026-07-29 (04d33b4ce5d on main; cherry-pick 8c58bbf22ba on branch_10x the same day)",
   "first_affected_version": "10.6.0, released 2026-10-29 (#16180 is in the 10.6.0 section of CHANGES, and the branch_10_6 head cb17f8f865c fails the repro [exec]; lucene-core 10.6.0 was not yet published on 2026-10-26); no earlier release contains the method",
   "affected_versions": "main ea57360912ed [exec]; branch_10_6 head cb17f8f865c (10.6.0-SNAPSHOT) [exec]; introducing commit 04d33b4ce5d [exec]; branch_10x head 42df6b34707 (10.7.0-SNAPSHOT) and upstream main cf398bfb142 [read]; not applicable: 9.12.3, 10.5.1, 10.5.2 and the parent 62f29b6c915 (method absent; the repro does not compile) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-419.html",
   "repro": "repro/LFV-419/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b): 2 of 2 fail; 10.5.2 does not have SortedDocValues#ordinalRangeIntoBitSet."
  },
  {
   "id": "LFV-911",
   "priority": "low",
   "priority_rank": 573,
   "novelty": "known",
   "withheld": false,
   "area": "core / index: SlowCodecReaderWrapper vector reader metadata (KnnVectorsReader#getVectorCount, new in 10.6.0)",
   "title": "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",
   "summary": "You wrap a FilterLeafReader that exposes only some of a segment's vectors (in the repro the 3 even documents of 6) with SlowCodecReaderWrapper.wrap, as callers of IndexWriter.addIndexes do, and ask the resulting reader's KnnVectorsReader for getVectorCount(fieldInfo); you expect 3, because the javadoc says it 'has the same meaning as get*VectorValues(field).size()' and the same reader's getFloatVectorValues and getByteVectorValues return 3 vectors. Instead it returns 6, the stored count of the SegmentReader under the filter, because the wrapper strips every FilterLeafReader and FilterCodecReader layer before it asks; a custom vectors format sees the same 6 for the 3 vectors it merges during addIndexes. For a view that adds a vector field to a segment without vectors, the call throws NullPointerException instead of returning the count (the javadoc documents only IllegalArgumentException).",
   "impact_class": "silent wrong results",
   "introduced_commit": "874ba4d39afbcb8dbf0eeb844e5df1d01273c59b (main, 'Add KnnVectorsReader.getVectorCount to read vector counts from metadata (#16647)', by ChrisHegarty; 10.x backport #16650 = f839d8a36af + c49cb90d4e0 on branch_10x, inherited by branch_10_6) [exec]. The unconditional segment path was in the first PR commit 940efc4163b; review commit 4c5b5e36938 added the fallback to super only for readers that do not unwrap. The unwrap pattern itself comes from getOffHeapByteSize (#14426, 10.3.0), which has a different, physical contract.",
   "introduced_date": "2026-09-08 (author and commit date of 874ba4d39af, 08:23:03Z; the segment fast path is already in the first PR commit 940efc4163b, authored 2026-09-07; backport f839d8a36af / c49cb90d4e0 on branch_10x the same day)",
   "first_affected_version": "10.6.0 (released 2026-10-29; first in RC1 = branch_10_6 4ae946e5a9b [exec]); no earlier release has the method (10.5.2 and 9.12.3: compile error, getVectorCount(FieldInfo) not found [exec])",
   "affected_versions": "main from 874ba4d39af (2026-09-08) to 645d4fe14a2 (upstream head, 2026-10-29) [exec]; branch_10x from f839d8a36af / c49cb90d4e0 through 657014b3c57 [read]; branch_10_6 head 4ae946e5a9b = 10.6.0 RC1 [exec]. [exec] all on JDK 25: the finder's JUnit fails 4 of 5 on main a9779ef3c193 and ea57360912ed, on the branch_10_6 snapshot jars and on the 10.6.0 RC1 artifacts, -ea and -da; the independent reproduction's JUnit fails 5 of 6 on main and branch_10_6, -ea and -da; the intended-behaviour check re-ran the finder's JUnit on main (-ea, -da) and branch_10_6 (-da); the adjudication re-ran the independent reproduction's and the finder's JUnits on main (-ea, -da); the follow-up ran it on the introducing commit 874ba4d39af (-ea, -da). Not affected: every release up to 10.5.2 and 9.12.3 (no getVectorCount: compile error [exec], javap [exec]).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16647",
    "https://github.com/apache/lucene/issues/16650",
    "https://github.com/apache/lucene/issues/16905"
   ],
   "doc": "",
   "repro": "repro/LFV-911/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 artifacts (4ae946e5a9b): 4 of 5 fail with -ea and -da; 10.5.2 does not have getVectorCount."
  },
  {
   "id": "LFV-157",
   "priority": "low",
   "priority_rank": 574,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / block-tree terms dictionary (Lucene103 SegmentTermsEnum; also BlockTreeOrds and the Lucene90 block tree in backward-codecs)",
   "title": "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",
   "summary": "You take the TermState of a term (say 'banana') from one TermsEnum, or from TermStates the way TermQuery does, and use it to position a brand-new TermsEnum of the same field and segment with seekExact(term, state); term() and docFreq() then correctly report 'banana'. You expect next() to return the following term ('cherry'), as the comment inside next() promises and as every other terms dictionary does. Instead, with the default block-tree terms dictionary, next() returns the field's first term ('apple') and iteration starts over from the beginning, because next() mistakes the not-yet-loaded enum for a fresh one and throws the TermState position away.",
   "impact_class": "silent wrong results",
   "introduced_commit": "9e27723b3702 (LUCENE-3562 'stop caching thread-private TermsEnums in Terms', svn r1203294 on trunk, by mikemccand; the JIRA issue is now apache/lucene#4636; pre-GitHub, no PR): it moved the root-block load out of the SegmentTermsEnum constructor, made the IndexInput clone lazy ('so that consumers that just pull a TermsEnum to seekExact(TermState) don't pay this cost') and added the 'if (in == null) // Fresh TermsEnum; seek to first term' branch at the top of next(), ahead of the staticFrame catch-up re-seek [read]; carried into every later copy unchanged in substance: LUCENE-5675 (9ebab12f647, 2014, SegmentTermsEnum moved to its own file), LUCENE-5819 (BlockTreeOrds), LUCENE-9705 (lucene90), #14333 (878e23f7739, 2025, lucene103 trie index) [read]",
   "introduced_date": "2011-11-17",
   "first_affected_version": "4.0.0-alpha [exec] (the first release containing the commit; first GA release 4.0.0 [exec]); no release was ever unaffected: 3.6.2 and earlier have neither the TermsEnum/TermState API nor the block-tree terms dictionary [exec], and block tree existed without the bug only on unreleased trunk from 2011-08-20 to 2011-11-17 [read]",
   "affected_versions": "every release from 4.0.0-alpha through 10.6.0 and main ea57360912ed [exec] [read]; BlockTreeOrds (lucene/codecs) since 4.10.0 [exec]; the Lucene90 block tree, the default terms dictionary in 9.x-10.2, fails on 9.12.3 and 10.2.2 [exec] and has the same ordering in backward-codecs on main, which reads older indexes [read]; not fixed upstream: main, branch_10x, branch_10_6 and branch_9_12 still have the ordering and no open PR changes it [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-157.html",
   "repro": "repro/LFV-157/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-487",
   "priority": "low",
   "priority_rank": 575,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / BlockTreeOrds terms dictionary (lucene-codecs OrdsSegmentTermsEnum)",
   "title": "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",
   "summary": "You index a field with BlockTreeOrdsPostingsFormat (here 26 terms a00..a24 and b in one segment, default block sizes), position a TermsEnum with seekExact(0), take its termState() and call seekExact(term(), state) on the same enum, which the TermsEnum javadoc allows and which leaves it on a00. You expect a later seekExact(\"b\") to return true, seekCeil(\"b\") to return FOUND and next() after a24 to return \"b\", as they do without the extra TermState call and with every other terms dictionary. Instead seekExact(\"b\") returns false, seekCeil(\"b\") throws EOFException (or, in a segment whose terms file is larger than about 7 KB, returns NOT_FOUND with a made-up term) and next() after a24 throws, because seekExact(ord) loads only the target block and deliberately leaves the enum unpositioned, while the TermState seek's 'already on this term' shortcut marks it positioned anyway, so the next call reuses parent frames that were never loaded.",
   "impact_class": "silent wrong results",
   "introduced_commit": "80fe3c277f30c275573e4f4a72096b695c0c2dec (LUCENE-5819 'add terms dict and postings format that implement term ordinals', svn r1612080 on trunk, by mikemccand; the JIRA issue is now apache/lucene#6881; pre-GitHub, no PR) and its branch_4x svn merge 96c1de3589d (r1612213, identical seek logic), which shipped in 4.10.0. The commit derived OrdsSegmentTermsEnum from the core block-tree SegmentTermsEnum, kept the core TermState seek shortcut ('skip seek: already on target state'; safe in core, which has no positioned flag and whose seekExact(long) throws UnsupportedOperationException), added seekExact(long), which loads only the target block's frame and sets positioned = false ('Leave enum fully unpositioned, because we didn't set frames for each byte leading up to current term'), and set positioned = true unconditionally after the copied shortcut [read]. Not a regression [exec]",
   "introduced_date": "2014-07-20 (trunk 80fe3c277f3; branch_4x 96c1de3589d on 2014-07-21; first released in 4.10.0, tagged 2014-09-02)",
   "first_affected_version": "4.10.0 [exec] (the first release with the format, then Ords41PostingsFormat with SPI name OrdsLucene41, renamed BlockTreeOrdsPostingsFormat in 5.0); 4.9.0 and 4.9.1 have no blocktreeords package [exec], so no release was ever unaffected",
   "affected_versions": "every release from 4.10.0 through 10.6.0 (10.6.0 [exec] on its release jars, in the bug doc's runs) and main ea57360912ed; never fixed. [exec] main() ports of the same test on 4.10.0 (-ea, -da), 4.10.4, 5.5.5 (-ea, -da) and 6.6.6 (-ea, -da); the JUnit on 7.7.3 and 8.11.4 (repro/src-8x), 9.1.0 (finder), 9.12.3 (-ea, -da), 10.5.2 (-ea, -da) and main (-ea, -da): the same three symptoms everywhere (only the file offset in the next() assertion message differs), control passes; the independent reproduction and the intended-behaviour check re-ran on 10.5.2 and 9.12.3; the security probe on 10.5.2 (-da). [read] the unchanged logic at all 103 release tags that contain the commit in the history clone (4.10.0-8.8.1 and 9.0.0-10.5.2; 8.8.2-8.11.x are not tagged there, 8.11.4 was executed); upstream main, branch_10x, branch_10_6 and branch_9_12 still have it and no open PR changes either seek method (2026-10-26). The default codec's block-tree enum is not affected: its seekExact(long) throws UnsupportedOperationException. All runs used JDK 25 on aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-487.html",
   "repro": "repro/LFV-487/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-745",
   "priority": "low",
   "priority_rank": 576,
   "novelty": "new",
   "withheld": false,
   "area": "memory / MemoryIndex stored fields (StoredFieldVisitor protocol)",
   "title": "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",
   "summary": "You add a document with an indexed-only field body (TextField, Store.NO) and a stored field tag with two values t1, t2 to a MemoryIndex and read it through storedFields().document(0, visitor), with a visitor that records its needsField calls or with LazyDocument's lazy-loading pattern from TestLazyDocument, expecting what an IndexWriter index gives for the same document: one needsField(tag) per stored value, never a question about body, and the lazy values tag=t1, tag=t2. Instead MemoryIndex asks about body, which has no stored value, asks about tag only once and then delivers both values on that single YES, because its loop calls needsField once per field name before it checks whether the field has stored values. So LazyDocument's lazy body field throws ArrayIndexOutOfBoundsException when read and tag=t2 is silently missing (with -ea LazyDocument's own inverted assertion, LFV-697, throws instead), and a visitor that wants only the first value of tag gets both.",
   "impact_class": "silent wrong results",
   "introduced_commit": "66127f6e69637b081cbc8a2bbbdfac6d0b5dd81f (#11999 'Add support for stored fields to MemoryIndex', by romseygeek, approved by mkhludnev, jpountz and uschindler; branch_9x commit 89cfaa37720b) [read]: it replaced the no-op MemoryIndexReader.document(int, StoredFieldVisitor) with the current loop, which asks needsField once per field name before checking for stored values. The per-name loop was already in the PR's first commit 9ea631782934; the review discussed whether MemoryIndex should have stored fields and how to keep the values, not visitor call semantics. The bug came with the feature; there was no earlier correct implementation.",
   "introduced_date": "2022-12-08",
   "first_affected_version": "9.5.0 [exec] (the first release with MemoryIndex stored fields: CHANGES.txt 9.5.0 'GITHUB#11999: MemoryIndex now supports stored fields'); 9.4.2 and older are not affected because MemoryIndex had no stored fields (document() was a no-op [read]; a 9.x-API probe on 9.4.2 shows nothing offered and no value returned [exec])",
   "affected_versions": "Every release from 9.5.0 through 10.6.0 (27 releases: 9.5.0 to 9.12.3 and 10.0.0 to 10.6.0) and main (a9779ef3c193, 645d4fe14a20); never fixed. [exec] the finder's JUnit fails with the same two messages on the 26 releases 9.5.0 to 10.5.2 with -ea and on main, and with -da on 9.5.0, 9.12.3, 10.5.2 and main (follow-up); the minimal repro fails with -ea and -da on the 10.6.0 release jars (4ae946e5a9b, the commit of tag releases/lucene/10.6.0) and on main 645d4fe14a20; a 9.x-API probe fails on 9.5.0 and 9.12.3 and shows the boundary on 9.4.2; upstream main a95c754ee003, branch_10x and branch_10_6 have the byte-identical loop (not executed) and no open PR changes it. JDK 25.0.3, aarch64; pure Java logic.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-745.html",
   "repro": "repro/LFV-745/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-871",
   "priority": "low",
   "priority_rank": 577,
   "novelty": "known",
   "withheld": false,
   "area": "search / IndriAndQuery (clause Occur handling in matching and explain)",
   "title": "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",
   "summary": "You build an IndriAndQuery from BooleanClauses with Occur values other than SHOULD, for example [MUST f:a, FILTER acl:x] or [SHOULD f:a, MUST_NOT f:secret], which the public constructor accepts, and run it. You expect either the meaning that BooleanClause.Occur documents (the same clauses in a BooleanQuery give {0, 2} and {0, 1}) or a rejection, and in any case an explain that agrees with the hits. Instead IndriAndWeight builds one disjunction over all clauses whatever their Occur, so MUST and FILTER clauses do not restrict ({0, 1, 2, 3}), a MUST_NOT clause adds the very documents it names ({0, 1, 2}; a lone MUST_NOT clause returns exactly them), and IndriAndWeight.explain, which does treat MUST/FILTER clauses as required, explains such hits as non-matches.",
   "impact_class": "minor",
   "introduced_commit": "9cc5c9b7983cf181280e18819f8516dc16ccf1ef (LUCENE-9537 'Add initial Indri search engine functionality to Lucene', author cammiemw, merged by mikemccand; apache/lucene-solr#2097, feature issue now apache/lucene#10577), released through its branch_8x backport a6125fb93855 (same author date, committed 2021-01-29 16:38 -0500) [read]; not a regression: no later commit changed either behaviour",
   "introduced_date": "2021-01-29",
   "first_affected_version": "8.9.0 [exec] (first on the main line: 9.0.0)",
   "affected_versions": "Every release that has the class: 8.9.0 to 8.11.4, 9.0.0 to 9.12.3 and 10.0.0 to 10.5.2, 41 releases [exec]; the finder's JUnit fails on 9.1.0, 9.12.3, 10.0.0 and 10.5.2 (-ea) and the independent reproduction's on 10.5.2 and 9.12.3; the finder's JUnit does not compile on 9.0.0, whose test framework predates the 9.1.0 package rename (a harness limit, not a statement about the bug); branch_10_6 head 4ae946e5a9b9 (10.6.0, released 2026-10-29) [exec]; main a9779ef3c193 [exec]; upstream main c5ab3e57b9b (2026-10-28) unchanged [read]. Not applicable to 8.8.2 and earlier: IndriAndQuery does not exist [exec]. All runs on aarch64 Linux with JDK 25.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/463",
    "https://issues.apache.org/jira/browse/LUCENE-10157",
    "https://github.com/apache/lucene/issues/10577",
    "https://github.com/apache/lucene/issues/11194",
    "https://github.com/apache/lucene/issues/11290",
    "https://github.com/apache/lucene/issues/11928"
   ],
   "doc": "",
   "repro": "repro/LFV-871/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-785",
   "priority": "low",
   "priority_rank": 578,
   "novelty": "new",
   "withheld": false,
   "area": "memory / MemoryIndex reader FieldInfos (index options and norms of fields that index no terms); seen through the IndexWriter.addIndexes(CodecReader...) schema check and FieldExistsQuery",
   "title": "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",
   "summary": "You build a MemoryIndex from a Document with a TextField title and a NumericDocValuesField price=42 (or a StoredField, IntPoint or vector field) and read its FieldInfo for price, or copy the reader into an index with IndexWriter.addIndexes(SlowCodecReaderWrapper.wrap(reader)), and expect what IndexWriter records for the same document: price is not indexed (IndexOptions.NONE, no norms), so the copy fits next to natively indexed copies of the document. Instead MemoryIndex reports price as DOCS_AND_FREQS_AND_POSITIONS with norms although it holds no terms for it, so addIndexes into an index holding the same document throws 'cannot change field \"price\" from index options=NONE to inconsistent index options=DOCS_AND_FREQS_AND_POSITIONS'. A copy into an empty index succeeds but records price as indexed, and addDocument of the same document then throws the reverse message, also in a new writer session.",
   "impact_class": "crash",
   "introduced_commit": "cf3eea264066 on main (LUCENE-7091 'Added doc values support to memory index', a JIRA patch, now GitHub issue #8147, no PR; backports 559432fcdcd8 on branch_6x and bd0803fd41c6 on branch_6_0, the one in 6.0.0), widened in the same release by LUCENE-7093 (#8149, point values, fe58313de027 on branch_6_0) [read]. Before it every MemoryIndex field had a token stream, so the hard-coded 'storeOffsets ? DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS : DOCS_AND_FREQS_AND_POSITIONS' (from LUCENE-4515, 59476c30cf3, 2012) was accurate; LUCENE-7091 accepted fields without a token stream and gave them the same options. LUCENE-7679 (6696eafaae18; cecc44c731b in 6.5.0) moved the expression into createFieldInfo unchanged, LUCENE-9570 (7f8b7ffbcad2) only reformatted it. The visible exceptions come from the correct strict schema checks of LUCENE-9334 (d03662c48bfc, PR #11, 9.0.0), which are fed the wrong FieldInfo",
   "introduced_date": "2016-03-15 (committed; authored 2016-03-09); the addIndexes exceptions appear with LUCENE-9334, 2021-04-14",
   "first_affected_version": "6.0.0 [exec]; the addIndexes exceptions first in 9.0.0 [exec]",
   "affected_versions": "Reader-side defect in every release from 6.0.0 to 10.6.0 (10.6.0 [exec] on the release jars, in the doc) and on main a9779ef3c193. [exec] the version-portable history probe (doc-values-only and stored-only index options, norms, both addIndexes scenarios) on 6.0.0, 6.0.1, 6.1.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main, and the finder's probe on 6.4.2 and 6.5.0; the finder's JUnit fails on 9.1.0, 9.12.3, 10.5.2 and main (-ea and -da on main); the independent reproduction's JUnit on main (-ea and -da), 10.5.2 and 9.12.3. addIndexes exceptions on 9.0.0 to 10.6.0 and main [exec]; 6.0.0 to 8.11.4 accept the copy and the later addDocument without an error and persist the wrong FieldInfo [exec]. Not affected: 5.5.0 and 5.5.5, where MemoryIndex rejects doc-values, point and stored-only fields [exec]. [read] the releases between the executed points: all 83 release tags from 6.0.0 to 10.5.2 contain the hard-coded expression and none reads fieldType.indexOptions() when building the FieldInfo. Unfixed: upstream main f7bcc0abd81 (2026-10-27) has no change under lucene/memory, and no open apache/lucene PR changes createFieldInfo's index options. Not checked: unreleased branches past 10.6.0, x86",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-785.html",
   "repro": "repro/LFV-785/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1143",
   "priority": "low",
   "priority_rank": 579,
   "novelty": "new",
   "withheld": false,
   "area": "core / search (DisjunctionScorer two-phase verified matches vs DisjunctionDISIApproximation.docIDRunEnd)",
   "title": "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)",
   "summary": "You index two documents {0: \"b a c\", 1: \"c\"} and build BooleanQuery(SHOULD f:c, SHOULD phrase \"a b\") with ScoreMode.COMPLETE; you move a scorer to doc 0 with iterator().nextDoc() and ask twoPhaseIterator().approximation().docIDRunEnd() (it returns 1 and the scorer stays on doc 0). You expect score() to return 0.06880058, the f:c score a fresh scorer gives, because docIDRunEnd() is documented not to affect the iterator; you get 0.59193045 with no error, because the phrase, which does not match doc 0, is added in. docIDRunEnd() walks the lead heap's topList(), which rewrites the same DisiWrapper.next links that matches() used to build the list of verified matches, and if the phrase also matches doc 0 the list becomes a cycle and score() never returns.",
   "impact_class": "minor",
   "introduced_commit": "9792d88041ed61d0ce3a9a6c58a0c11ce0202a41 on main and its branch_10x cherry-pick 0e6911da5de89c21146beaef7149f01550f248aa, #14363 'Implement #docIDRunEnd() on DisjunctionDISIApproximation.' (jpountz): its docIDRunEnd() takes the maximum run end over approximation.topList(), and DisiPriorityQueue2.topList() rewrites DisiWrapper.next [exec]. #16142 (8e90c661ca6 on main, 023481ae9b1 on branch_10x, 'Optimize disjunction docIDRunEnd', first in 10.5.0) narrowed the walk to leadIterators.topList(), which still relinks, so the bug stayed. The other half of the aliasing, DisjunctionScorer.TwoPhase building its verified-match list through DisiWrapper.next, dates from 1967050202d (LUCENE-6815, 2015) and was harmless alone [read].",
   "introduced_date": "2025-03-17 (author date 2025-03-17T22:28:18+01:00; PR merged 2025-03-17T21:28:19Z; cherry-picked to branch_10x the same day)",
   "first_affected_version": "10.2.0 [exec]",
   "affected_versions": "every release from 10.2.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT). Executed with the finder's one-test JUnit: main (-ea and -da; finder, the intended-behaviour check, history and re-runs), 10.6.0 (-da; finder, the intended-behaviour check, history), 10.5.0 and 10.4.0 (-da, history), 10.2.0 (-ea and -da); with the independent reproduction's own test: main (-ea and -da; the independent reproduction and the adjudication), 10.6.0, 10.5.2 and 10.2.0 (-da) [exec]; 10.2.1, 10.2.2, 10.3.x and 10.5.1 by read (same loop, tag containment). Not affected: 10.1.0 and 9.12.3 (no docIDRunEnd API: compile error) [exec]. Not new in 10.6. Not fixed upstream: since 61e22dd3e60 (#16394, author date 2026-07-28, unrelated) no upstream main commit touches DisjunctionDISIApproximation, and DisjunctionScorer, DisiPriorityQueue2 and DisiWrapper have no commit since 2026-06-01 (author dates); main is 3 commits past 5adff78bb16, none in lucene/core's search package (one, #16964, edits CheckIndex.java in the index package) [read]. Executed on Linux aarch64 with JDK 25.0.3 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1143.html",
   "repro": "repro/LFV-1143/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1145",
   "priority": "low",
   "priority_rank": 580,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / doc values bulk range scan (Lucene90DocValuesProducer dense paths -> internal vectorization PanamaDocValuesRangeSupport)",
   "title": "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)",
   "summary": "You index 32 documents with NumericDocValuesField values 0..31 on the default codec (a dense field), run the JVM with the vector incubator module enabled, and call NumericDocValues.rangeIntoBitSet(20, 13, Long.MIN_VALUE, Long.MAX_VALUE, bits, 0); you expect no bit to be set, because the javadoc defines the result as the doc IDs in [fromDoc, toDoc), which is empty here, and the scalar provider, the default per-doc loop and Lucene90's own sorted-numeric overrides all set nothing. With the Panama provider doc 12 is set, with no error under -ea or -da. PanamaDocValuesRangeSupport.rangeIntoBitSet has no empty-range guard: loopBound = fromDoc + LONG_SPECIES.loopBound(toDoc - fromDoc) rounds the negative length down to a multiple of the lane count and lands below toDoc, the SIMD loop is skipped, and the scalar tail tests and sets the docs in [loopBound, toDoc) that were never requested (for [10, 5) with 4 lanes: docs 2, 3 and 4).",
   "impact_class": "minor",
   "introduced_commit": "6f0821d8ddad468057eb1c540ef306d626d8a4d5 on main and its branch_10x copy 84c424ac132ec1d3807f6a0d99fc527be4ac3353 (the one that shipped, in 10.5.0), #16050 / #16093 'Add SIMD-accelerated bulk range evaluation for dense numeric doc values' (sgup432): it added NumericDocValues.rangeIntoBitSet, the Lucene90 dense forwarding and PanamaDocValuesRangeSupport with the unguarded 'loopBound = fromDoc + LONG_SPECIES.loopBound(toDoc - fromDoc)' and the scalar tail 'for (int d = loopBound; d < toDoc; d++)', so the API and the defect arrived together [read]. Later edits kept the faulty lines: #16123 (1b41317f33d, 2026-05-27) changed only the SIMD-loop body; #16283 (42e71d8e73f, 2026-07-02) added the sibling sortedNumericRangeIntoBitSet, whose only caller guards 'fromDoc >= endDoc' first.",
   "introduced_date": "2026-05-20 (author date of 6f0821d8dda, 2026-05-20T03:02:41-07:00; PR #16050 merged 2026-05-20T10:02:41Z); the branch_10x copy 84c424ac132 has author date 2026-05-21 (#16093 merged 2026-05-21T07:43:36Z)",
   "first_affected_version": "10.5.0 [exec]; it is the first release with the API, so no release had rangeIntoBitSet without the bug; 10.4.0 and 9.12.3 have no NumericDocValues.rangeIntoBitSet (compile error) [exec]",
   "affected_versions": "10.5.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT), whenever the JVM runs the Panama provider (--add-modules jdk.incubator.vector). Executed (fail): main with -ea and -da (the finder, the independent reproduction, the intended-behaviour check, the adjudication and a separate re-run), main at 128-bit vectors (the independent reproduction, -XX:UseSVE=0, 2 lanes), 10.6.0 (the finder, the independent reproduction and the history step with -ea; a separate re-run with -da), 10.5.2 (the independent reproduction, history), 10.5.0 (finder, the independent reproduction, history) [exec]. By reading only: 10.5.1 (same line 48 and tail loop), branch_10_6 and branch_11x (same line 48, through the GitHub contents API). Not affected: any version with the default scalar provider [exec]; 10.4.0 and earlier (no API) [exec]. Not new in 10.6 (10.5.0 and 10.5.2 fail). Not fixed upstream: the last upstream commit on PanamaDocValuesRangeSupport.java on main is 42e71d8e73f (#16283, author date 2026-07-02); upstream main HEAD and branch_10_6 still have the unguarded line 48; open PR #16917 edits the method but guards only a new fast path that the repro does not take (by reading the diff). Executed on Linux aarch64 with JDK 25.0.3 only (256-bit and 128-bit vector widths); x86 not run.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1145.html",
   "repro": "repro/LFV-1145/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-205",
   "priority": "low",
   "priority_rank": 581,
   "novelty": "new",
   "withheld": false,
   "area": "store / NRTCachingDirectory (commit durability: IndexWriter.startCommit, SegmentInfos.prepareCommit/finishCommit)",
   "title": "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",
   "summary": "You index through NRTCachingDirectory (for example new NRTCachingDirectory(FSDirectory.open(path), 5.0, 60.0), the class javadoc's own example), call IndexWriter.commit(), and the machine crashes during that commit. You expect what Lucene's commit protocol and LUCENE-8048 are built for: after the crash the index opens to the previous commit or to the new one, because SegmentInfos.prepareCommit fsyncs the directory before the commit is published by renaming pending_segments_N to segments_N. Instead the newly flushed segment files are still in NRTCachingDirectory's RAM cache at that directory fsync; NRTCachingDirectory.sync creates them on disk only afterwards and fsyncs their bytes but never the directory, so the rename can become durable before the new files' names do, and in that crash state every open fails (CorruptSegmentInfoException: segment info file _1.si cannot be read), while the same steps on a plain FSDirectory open fine.",
   "impact_class": "index unusable",
   "introduced_commit": "4a5900728db6a84b4aea42545567a393989f25cf (master, merged by 0688be6c6677) and 2bfe7ed0f2f9 (branch_7x, the copy that shipped first, in 7.2.0): LUCENE-8048 'Filesystems do not guarantee order of directories updates' (committed by Erick Erickson from the JIRA patch; no PR; migrated as #9096) [read] [exec]. An incomplete fix, not a regression: it added the dir.syncMetaData() barrier at the start of SegmentInfos.prepareCommit, which IndexWriter.startCommit calls before directory.sync(filesToSync) (both lines b83dde502bc8, 2012), while NRTCachingDirectory.sync, which creates the cached files in the delegate inside that sync call (unCache -> copyFrom), has had the same logic since the class was added (LUCENE-3092, 3525ba940fa2 on trunk and 8035a5ecf0f on branch_3x, 2011-05-17) and has never called syncMetaData (git log --all -S syncMetaData on NRTCachingDirectory.java: no commit)",
   "introduced_date": "2017-12-05",
   "first_affected_version": "7.2.0 [exec] (release tag 2017-12-19; CHANGES 7.2.0 'Bug Fixes' lists LUCENE-8048). The 18 releases 6.2.0 to 7.1.0 [exec] fail the same crash test, but so does the plain-FSDirectory control, because no directory fsync preceded the rename at all (LUCENE-8048 itself), so they are not counted as this bug; 6.1.0 and earlier: no verdict (the crash-model hooks Directory.rename and Directory.syncMetaData arrived in 6.2.0 with LUCENE-7373; 6.1.0 does not compile)",
   "affected_versions": "every release from 7.2.0 through 10.5.2, 10.6.0 (run later in the bug doc's checks, see below) and main ea57360912ed. [exec] all 71 Maven Central releases from 7.2.0 to 10.5.2 with two independently written JUnit crash-model repros (the finder's, seed DEADBEEF, and the independent reproduction's, seed C0FFEE01): in each, the NRTCachingDirectory second-commit crash state cannot be opened while the plain-FSDirectory control and a never-caching NRTCachingDirectory(0.0, 0.0) control open with all documents; main fails under -ea and -da, and with the fix shadowed main passes. The wrapping exception differs by version (CorruptIndexException 'Unexpected file read error while reading index' on 7.2.0-10.5.2, CorruptSegmentInfoException on main); the cause is always NoSuchFileException for the new segment's .si. [read] not fixed upstream: NRTCachingDirectory.sync still has no syncMetaData on main, branch_10x, branch_10_6 and branch_9_12 (read-only check 2026-10-26); 10.6.0, released from branch_10_6 on 2026-10-29, is affected too: the bug doc's minimal test fails 1 of 1 on the 10.6.0 release jars with -ea and -da [exec]. History [read]: in 4.8-4.10 FSDirectory.sync fsynced the directory after the files (LUCENE-5588), which also covered the files NRTCachingDirectory had just created; 5.0 (LUCENE-5925) moved that directory fsync after the rename, opening the gap for every Directory, and 7.2 (LUCENE-8048) closed it only for files that already exist at prepareCommit. Before 5.0 the commit protocol had no rename and is not analysed. All runs on aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-205.html",
   "repro": "repro/LFV-205/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-839",
   "priority": "low",
   "priority_rank": 582,
   "novelty": "known",
   "withheld": false,
   "area": "index / commit protocol failure cleanup (SegmentInfos.finishCommit, IndexWriter.finishCommit and rollback)",
   "title": "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)",
   "summary": "You commit through a Directory whose rename(pending_segments_2, segments_2) creates segments_2 and then throws an IOException; commit() throws, the writer stays open (the failure is not tragic), and you expect the index to still be the last good commit segments_1, which is what LUCENE-9477 made Lucene do when the directory sync right after the rename fails. Instead SegmentInfos.finishCommit deletes only pending_segments_2, so segments_2 stays in the directory unknown to the writer; as soon as a merge removes the segments it references (a merge that finishes during the commit's fsync, or any merge before the writer is closed or rolled back) the writer deletes their files, and DirectoryReader.open, and after a restart a new IndexWriter, fail with CorruptSegmentInfoException '_1.si cannot be read' although segments_1 and its files are intact. Without a merge, rollback() or close() deletes the failed commit's files before the stray segments_2 with no directory fsync in between, so a process kill or OS crash in that window leaves the same unopenable index.",
   "impact_class": "index unusable",
   "introduced_commit": "b7047694256a8e5808b9a9ddf480643ff768d8a9 (svn branch_4x r1624362, the line released as 5.0.0) and its trunk twin bb0256f26076849b94de4e036cc5af055f0e6cd4 (r1624194, first released in 6.0.0), 'LUCENE-5925: use rename instead of segments_N fallback/segments.gen' (author rmuir; svn era, patch on JIRA, issue now apache/lucene#6987, no GitHub PR; reviewed by mikemccand and uschindler with no discussion of a rename that throws after taking effect) [exec]: it published commits by renaming pending_segments_N to segments_N, and its failure handler (rollbackCommit) deletes only pending_segments_N, while the 4.x code it replaced deleted segments_N on any finishCommit failure. Later changes [read]: LUCENE-7373 (df9efb8b6da, mikemccand, 2016-07-11, 6.2.0) split renameFile into rename + syncMetaData, adding a second path with the same defect; LUCENE-9477 (gh#10516, lucene-solr PR #1777, da095bc7da6, s1monw, 2020-08-24, 8.7.0) fixed only that syncMetaData path by deleting dest in an inner try that starts after the rename (executed: the syncMetaData branch fails on 6.2.0, 7.7.3 and 8.6.3 and is clean from 8.7.0, the rename branch fails throughout); #14913 (27d1272984f, 2025-07-14, main only) refactored try/finally to try/catch with the same semantics. git blame on main points dir.rename at df9efb8b6da and the outer catch at 27d1272984f; the behaviour-defining line (rollbackCommit deletes only pending_segments_N, SegmentInfos.java:954) blames to bb0256f2607",
   "introduced_date": "2014-09-11 (author and commit date of b7047694256, 18:56Z, and bb0256f2607, 05:04Z); first release 5.0.0 (tag dated 2015-02-19)",
   "first_affected_version": "5.0.0 [exec] (4.10.4 and earlier have no Directory rename: the 4.x commit wrote segments_N in place and deleted it on any finishCommit failure; a 4.x analog of the fault passes on 4.10.4 and on commit 1aaf4656ed3 [exec])",
   "affected_versions": "every release from 5.0.0 through 10.5.2, 10.6.0 (by reading) and main a9779ef3c193 [exec]; the releases in between share the unchanged rename-then-rollbackCommit code [read]; not fixed upstream: finishCommit is unchanged on upstream main 20ced71c1e6e, branch_10x and branch_10_6 [read], so the released 10.6.0 has it too. The failure signature varies by version: NoSuchFileException _1.si (5.x-6.x), CorruptIndexException 'Unexpected file read error while reading index' (7.x-10.x), CorruptSegmentInfoException '_1.si cannot be read' (main). The crash-state form (rollback or close, then a crash) was executed with the JUnit repro on 8.11.4, 9.12.3, 10.5.2 and main only. All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-7373",
    "https://issues.apache.org/jira/browse/LUCENE-8853",
    "https://issues.apache.org/jira/browse/LUCENE-9477",
    "https://github.com/apache/lucene/issues/13277",
    "https://github.com/apache/lucene/issues/6987",
    "https://issues.apache.org/jira/browse/LUCENE-5925"
   ],
   "doc": "",
   "repro": "repro/LFV-839/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1217",
   "priority": "low",
   "priority_rank": 583,
   "novelty": "new",
   "withheld": false,
   "area": "index / SegmentDocValues (per-generation doc-values producer cache shared by the SegmentReaders of one segment core; reopen with openIfChanged(reader, commit))",
   "title": "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",
   "summary": "You keep older commits, open a reader r1 on a commit whose segment has doc-values updates, reopen it onto an older commit as r2 (r2 shares r1's segment core but not the updated doc-values generation), and closing r1 fails with an I/O error from that generation's doc-values input. You expect r2, and any reader later opened from it, to keep working: openIfChanged(r2, newer commit) should return a usable reader of that commit, just as a fresh open of the commit does. Instead SegmentDocValues closed the producer before removing it from its cache and RefCount put the reference back when the close threw, so the reopened reader is handed the closed producer and its first doc-values read throws AlreadyClosedException ('Already closed.').",
   "impact_class": "minor",
   "introduced_commit": "d37b2cb90b12 on trunk (svn r1535526), 'LUCENE-5189: factor out SegmentDocValues from SegmentReader' by Shai Erera (shaie): it moved the generation-to-RefCount producer map from each SegmentReader into SegmentDocValues, which all SegmentReaders of one core share, and wrote the RefCount's release() as close, then remove from the map; the released line got it through the branch_4x merge 49684b82701 (svn r1537832, 'LUCENE-5189: add NumericDocValues field updates'). RefCount.decRef's 'Put reference back on failure' came earlier with trunk 1120e46961b (LUCENE-5189 'add NumericDocValues updates', 2013-09-15). No pull request (pre-GitHub; JIRA LUCENE-5189, migrated as #6253) [exec] [read]",
   "introduced_date": "2013-10-24 (d37b2cb90b1, trunk, author date = commit date); 2013-11-01 (branch_4x merge 49684b82701)",
   "first_affected_version": "4.6.0 [exec] (tagged 2013-11-22; the first release with doc-values updates at all); 4.5.1 and earlier lack the code: no IndexWriter.updateNumericDocValue, SegmentDocValues or RefCount [exec]",
   "affected_versions": "every release from 4.6.0 through 10.6.0, and main 5adff78bb168 [exec] [read]. In 4.6.0-6.5.1 r1.close() returned normally because SegmentDocValues.decRef swallowed the exception (fixed by LUCENE-7775 in 6.6.0 and 7.0.0), so the failed close was silent there; from 6.6.0 it throws; the cached closed producer is the same in both. On main the default doc-values overlays keep generation 1 referenced on the forward route (it fires there only with setMaxDocValuesOverlays(0)); the two-commit route fires with main's defaults. Not fixed upstream (main tip 1c2072f0284, 2026-11-02; the newest commits on SegmentDocValues.java and RefCount.java are dbaf97f5dcc, 2025-07-18, and 27d1272984f, 2025-07-14, author date = committer date, neither changes the order). Not new in 10.6 (10.5.2 and 9.12.3 fail). All runs used JDK 25 on one aarch64 Linux host; the two 2013 trunk jars were built from source (lucene-core only, javac --release 8, one build-only patch to a constructor failure path the probe never reaches), not official builds",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1217.html",
   "repro": "repro/LFV-1217/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-489",
   "priority": "low",
   "priority_rank": 584,
   "novelty": "new",
   "withheld": false,
   "area": "facet / taxonomy (SearcherTaxonomyManager NRT constructors: index and taxonomy reader open order)",
   "title": "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)",
   "summary": "You index documents with taxonomy facets in one thread and meanwhile create a SearcherTaxonomyManager from the IndexWriter and DirectoryTaxonomyWriter. You expect its first SearcherAndTaxonomy, documented as 'a matched pair', to know every category its searcher's documents use, because TaxonomyReader's javadoc says to open the taxonomy after the main index and the manager's own refresh does exactly that. Instead the constructor opens the taxonomy reader first, so a document indexed in between is visible to the searcher while its category is missing from the taxonomy reader: getOrdinal returns -1, FastTaxonomyFacetCounts throws ArrayIndexOutOfBoundsException, and maybeRefresh() keeps the broken pair until the index changes again.",
   "impact_class": "crash",
   "introduced_commit": "03694e7693092432701be0186607e25e4633ea2b (trunk, svn r1466548; backported to branch_4x as e9fb220401ef, svn r1466550, the same day), 'LUCENE-3786: add SearcherTaxonomyManager' by mikemccand; JIRA LUCENE-3786, now #4859; no pull request (SVN era) [read]. Present since the class was created, not a regression",
   "introduced_date": "2013-04-10",
   "first_affected_version": "4.3.0 [exec] (first release with SearcherTaxonomyManager; 4.2.1 does not have the class [exec])",
   "affected_versions": "every release from 4.3.0 through 10.6.0, and main ea57360912ed and 645d4fe14a20 [exec]; the constructor taking a RefreshCommitSupplier (10.3.0, #14443) and the 3-argument constructor (5.5.0, LUCENE-6980) share the same body; not fixed upstream on 2026-10-26 (main, branch_10x, branch_10_5 and branch_10_6 read through the read-only contents API, last change to the file f3796ecf22b6, 2025-05-18); the minimal test fails on the 10.6.0 release jars (4ae946e5a9b9, released 2026-10-29) and on main 645d4fe14a20, -ea and -da [exec], and the file is unchanged on upstream main through 2f424fd428da (2026-10-30) [read]. The Directory constructor has the same order but a javadoc NOTE warns that it can give an unsync'd pair, so it is not claimed",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-489.html",
   "repro": "repro/LFV-489/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-512",
   "priority": "low",
   "priority_rank": 585,
   "novelty": "known",
   "withheld": false,
   "area": "facet / taxonomy writer (DirectoryTaxonomyWriter lock-free getSize/getParent reads vs a concurrent addCategory: nextID is published before TaxonomyIndexArrays.add stores the parent)",
   "title": "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",
   "summary": "One thread adds categories dim/0, dim/1, ... to a DirectoryTaxonomyWriter while another thread reads n = getSize() and calls getParent(n - 1). You expect the parent of that category (ordinal 1, 'dim'), because TaxonomyWriter documents that the taxonomy contains ordinals 0 through getSize()-1 and that getParent throws only for an ordinal beyond the last available one. Instead addCategory makes the new ordinal visible through getSize() a moment before it stores the ordinal's parent, so getParent silently returns 0 (the root) or, while the parent array grows, throws ArrayIndexOutOfBoundsException (an AssertionError with -ea).",
   "impact_class": "silent wrong results",
   "introduced_commit": "da7991ea927ccfaff8dd97de9ef7dc22e3caa0d1 (trunk, SVN r1352038, LUCENE-4156 'Improve implementation of DirectoryTaxonomyWriter.getSize()', patch by shaie; JIRA LUCENE-4156 is now GitHub issue #5228; no pull request, SVN era), released through the branch_4x backport 841a1fd629e8ccbba71b054d27f4aa7c7d0d0899 (r1352039, the same day). It made getSize() unsynchronized, returning the volatile nextID instead of the synchronized indexWriter.maxDoc(), and made getParent check the ordinal against nextID; addCategoryDocument already incremented nextID before storing the parent, so from this commit a lock-free getSize() can count an ordinal whose parent is not stored yet [read]. The trunk revision itself was not built (2012 Ant build); the 4.0.0-minus-LUCENE-4156 shadow is the executable stand-in. Later changes kept the order: LUCENE-4596 (bc61e7cdc9b, 4.1.0), LUCENE-4565 (01fd342513a, 4.1.0), #11775 (bcc116057d1, 9.5.0), #12995 (2a0b7f20567, 9.10.0)",
   "introduced_date": "2012-06-20 (da7991ea927 on trunk and 841a1fd629e8 on branch_4x)",
   "first_affected_version": "4.0.0-ALPHA [exec] (tag 2012-06-29; the first GA release 4.0.0 [exec] too); not affected: the 3.x line, because getSize() is synchronized there [exec]",
   "affected_versions": "every release from 4.0.0-ALPHA through 10.5.2 (the last 10.x release before 10.6.0), including 9.12.3 (latest 9.x) and 8.11.4 (latest 8.x), plus main ea57360912ed; never fixed. [exec] fails: 4.0.0-ALPHA and 4.0.0 (-ea and -da, 20 of 20), 4.10.4, 5.5.5, 6.6.6, 7.7.3 and 8.11.4 (-ea, 10 of 10 each), 8.11.2 and 9.0.0 (-ea, finder), 9.12.3, 10.5.2 and main (-ea and -da, 20 of 20). [read] at all 123 release tags 4.0.0-ALPHA to 10.5.2 in the history clone the nextID increment precedes the parent store and getSize/getParent are unsynchronized, and none of the 108 trunk/main commits that touch the file reorders them. Upstream main and branch_10x are unchanged on 2026-10-26 (read-only contents API) and no open PR changes the order. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/5661",
    "https://issues.apache.org/jira/browse/LUCENE-4596",
    "https://github.com/apache/lucene/issues/5228",
    "https://issues.apache.org/jira/browse/LUCENE-4156",
    "https://github.com/apache/lucene/issues/11775",
    "https://github.com/apache/lucene/issues/12995"
   ],
   "doc": "",
   "repro": "repro/LFV-512/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-650",
   "priority": "low",
   "priority_rank": 586,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / TeeSinkTokenFilter (sinks: newSinkTokenStream() attribute snapshot, SinkTokenStream replay through AttributeSource.restoreState)",
   "title": "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",
   "summary": "You create a sink with tee.newSinkTokenStream() and then wrap the tee in a further filter, as the class javadoc example does (sinks first, then final1 = new LowerCaseFilter(source1)), and expect the sink to replay every token the tee consumed, as newSinkTokenStream() promises. If that later filter adds an attribute the tee did not have yet, for example PorterStemFilter adding KeywordAttribute for a stemmed field next to an unstemmed sink field, the sink lacks it, because its attributes are a cloneAttributes() snapshot taken when it was created, and its restoreState throws IllegalArgumentException ('State contains AttributeImpl of type ...KeywordAttributeImpl that is not in in this AttributeSource') on the first token, so addDocument rejects the document. With LowerCaseFilter, the javadoc's own filter, nothing is added and the example works; creating the sink after the stemmer also works.",
   "impact_class": "crash",
   "introduced_commit": "31a5f0edcc474f739e8392eac7261b9483fc60bf (LUCENE-1693 'AttributeSource/TokenStream API improvements', GitHub #2767, svn r797665, by Michael Busch; SVN/JIRA era, no PR): it added TeeSinkTokenFilter, whose newSinkTokenStream() builds the sink from this.cloneAttributes() and whose sinks replay the tee's captured states with restoreState() [read]. The reported trigger became reachable with LUCENE-3042 'AttributeSource can have an invalid computed state' (GitHub #4115; branch_3x 7904c536011, svn r1096078, first release 3.2.0; trunk 49ab81b316c, svn r1096073, first release 4.0.0), a correct fix of a stale per-instance state cache that had hidden the late attribute from the tee's captured states [exec]",
   "introduced_date": "2009-07-24 (root cause, 31a5f0edcc4); 2011-04-22 (exposed by LUCENE-3042, 7904c536011 / 49ab81b316c)",
   "first_affected_version": "3.2.0 [exec] for the reported trigger (an attribute-adding filter put on the tee after the sink was created); 2.9.0, 2.9.4, 3.0.0, 3.0.3 and 3.1.0 pass that trigger [exec] only because the pre-LUCENE-3042 stale state cache masked it. The narrower variant in which the tee's own consumer calls tee.addAttribute(...) after the sink was created fails from 2.9.0 [exec], the first release with TeeSinkTokenFilter (2.4.1 has no such class; its predecessor TeeTokenFilter/SinkTokenizer replays correctly [exec])",
   "affected_versions": "Every release from 3.2.0 to 10.6.0 (10.6.0 [exec] on its release jars, -ea and -da, 2026-10-30) and main a9779ef3c193; never fixed. [exec] follow-up version-specific main() probes, each failing case with a same-version control that differs only in creation order and passes (145 runs over 21 releases and main): the stemmer trigger fails on 3.2.0, 3.6.2, 4.0.0, 4.8.1, 4.9.0, 4.10.4, 5.0.0, 5.5.5, 6.0.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main; the DelimitedPayloadTokenFilter trigger fails at the executed points from 4.0.0 to main (3.x not run); the StopFilter trigger fails 3.2.0 to 4.8.1 and passes from 4.9.0, where the default PackedTokenAttributeImpl (LUCENE-5640) already provides the position increment [read]; the finder's JUnit fails 2 of 2 on main (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 3 of 6 on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's probe fails on main and 10.5.2. [read] versions between executed points are inferred from the unchanged cloneAttributes()/captureState()/restoreState() code; upstream main a95c754ee003 and branch_10x have no behavioural change to TeeSinkTokenFilter.java or AttributeSource.java since LUCENE-6973 (2016) and no open PR touches them, so the unreleased 10.x and 11.0 lines are affected (not executed). JDK 25.0.3, aarch64; pure Java logic.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-650.html",
   "repro": "repro/LFV-650/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-894",
   "priority": "low",
   "priority_rank": 587,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / compound hyphenation (TernaryTree.compact via HyphenationTree.loadPatterns and HyphenationCompoundWordTokenFilter)",
   "title": "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)",
   "summary": "You load a well-formed FOP-format hyphenation grammar with HyphenationCompoundWordTokenFilter.getHyphenationTree (or HyphenationTree.loadPatterns, or the factory's hyphenator file) and expect it to load, as the TernaryTree javadoc's 'room for about 65000 nodes' suggests. For some grammars, for example the current TeX Afrikaans patterns or the repro's 1,310 random 4-8-letter patterns, loading instead throws ArrayIndexOutOfBoundsException: Index 2048 out of bounds for length 2048 from TernaryTree.insert, called by compact() during trimToSize(). The cause: insert(char[] key, int start, char val) reserves room for strlen(key) + 1 nodes counted from index 0 instead of from start, and its only caller with start > 0, compact(), passes a key array whose index 0 is an empty string, so it reserves one node and a multi-node insert that crosses the 2048-node block boundary writes past the arrays; with strlen(key, start), the bound the String overload already uses, every failing grammar loads with all values right.",
   "impact_class": "crash",
   "introduced_commit": "7a27cdcbc901cd5e5ebb44065e3158866156dc08 (svn r657027), LUCENE-1166 / #2243 'A tokenfilter to decompose compound words' (pre-GitHub, no PR; CHANGES 2.4.0: 'LUCENE-1166: Decomposition tokenfilter for languages like German and Swedish') [read]. The patch copied the hyphenation classes, TernaryTree included, from Apache FOP (the class javadoc says so), and the defective line came with that copy; Apache FOP's current TernaryTree still has it. When it entered FOP was not traced.",
   "introduced_date": "2008-05-16 (author and commit date 2008-05-16T12:22:50Z); first released in 2.4.0 (2008-10)",
   "first_affected_version": "2.4.0 [exec] (the first release containing 7a27cdcbc901: the version-portable main() repro fails there, and passes with the one-line fix shadowed; the introducing commit's own sources fail the same way). 2.3.2 and earlier are not affected because the API is absent [exec].",
   "affected_versions": "Every release from 2.4.0 to 10.5.2 (all 138 release tags that ship TernaryTree have the same line and the same loadPatterns -> trimToSize -> compact call path [read]), 10.6.0 (executed as the branch_10_6 head 4ae946e5a9b9), branch_10x and main a9779ef3c193; no upstream fix. [exec] [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-894.html",
   "repro": "repro/LFV-894/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-933",
   "priority": "low",
   "priority_rank": 588,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / hunspell WordStorage (dictionary word hash table)",
   "title": "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)",
   "summary": "You load a Hunspell dictionary, for example the stock en_US dictionary plus a custom list of 300 words through HunspellStemFilterFactory's documented dictionary=\"en_US.dic,custom.dic\" pattern, and expect it to load as it does with 299 or 301 custom words. Instead the Dictionary constructor throws RuntimeException 'Too many collisions. Try a larger Dictionary#hashFactor (now 1.0). If this doesn't help, please report this to dev@lucene.apache.org', so the analyzer cannot be built. WordStorage puts every word into slot Math.abs(String.hashCode() % tableSize) with tableSize = entry count x hashFactor (default 1.0); when that size is a multiple of 961 = 31*31, the slot of a short word depends almost only on its last two letters (31^2 divides every earlier term of the unmixed radix-31 hash), so short words with a common ending (six-letter '-er' words in en_US) pile into a few slots and one exceeds the hard limit of 20 entries.",
   "impact_class": "crash",
   "introduced_commit": "4842e0c9cab35239b6d1da619b94a640e7227510 (LUCENE-9825 'Hunspell: reverse the \"words\" trie for faster word lookup/suggestions', apache/lucene-solr#2459 by donnerpeter, issue apache/lucene#10864; reached main through the merge f5012a4cdaf (apache/lucene#2, 2021-03-10) and branch_8x through the squashed hunspell backport c6b964a1157 (apache/lucene-solr#2499, listed in CHANGES under 8.9.0 as LUCENE-9687)); it brought the slot formula, table size = entry count and the 20-entry limit together [exec] [read]. Second stage: 1af68bf2d7e (#12464, branch_9x 64afaf5784b) made the table size (int) (wordCount * hashFactor) with a protected Dictionary#hashFactor() (default 1.0) and added the 'Try a larger Dictionary#hashFactor' advice, without changing the slot formula or the limit [read]",
   "introduced_date": "2021-03-05 (author date of 4842e0c9cab; merged to main 2021-03-10; branch_8x backport c6b964a1157 2021-05-28); hashFactor stage 1af68bf2d7e 2023-07-28",
   "first_affected_version": "8.9.0 [exec] (first release with WordStorage, through the branch_8x backport; 8.8.2 and earlier store the words in an FST and load all test lists [exec]); 9.0.0 on the main line [exec]",
   "affected_versions": "every release from 8.9.0 to 10.6.0 (10.6.0 run as its release revision, branch_10_6 head 4ae946e5a9b9) and main a9779ef3c193. [exec] the follow-up's public-API probe fails on all 41 releases it ran from 8.9.0 to 10.5.2 (8.9.0, 8.10.0, 8.10.1, 8.11.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2) and on branch_10_6 head 4ae946e5a9b9 and main (-ea and -da), and passes on the 5 releases it ran before 8.9.0; from 8.9.0 to 9.7.0 the message has no hashFactor advice (no hashFactor API), from 9.8.0 on the advised factor 2.0 also fails for the synthetic list; the finder's JUnit fails on 8.9.0 and 8.11.4 (8.x variant), 9.0.0 (pre-9.8 variant), 9.8.0, 9.12.3, 10.5.2, branch_10_6 and main; the independent reproduction reproduces on 10.5.2 and 9.12.3, the cross-model review step on 10.5.2, and the intended-behaviour check on 10.5.2 and 9.12.3 (en_US plus 300 words). [read] upstream main 645d4fe14a20 (2026-10-28) is unchanged at the fix site",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-933.html",
   "repro": "repro/LFV-933/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-929",
   "priority": "low",
   "priority_rank": 589,
   "novelty": "known",
   "withheld": false,
   "area": "analysis / WordDelimiterGraphFilterFactory and WordDelimiterFilterFactory types option (parseTypes) versus the getLines resource-file format",
   "title": "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",
   "summary": "You give WordDelimiterGraphFilterFactory a types file that holds no rule yet, for example only a '# custom character types' comment, an empty file, or the single rule '# => ALPHA' (which the loader drops, because a line that starts with '#' is a comment), and expect the analyzer to build and tokenize exactly as without the option: getLines documents that comment and blank lines are skipped, and the other resource files (the same factory's protected words, stop words, mapping rules) load such a file as empty. Instead inform() throws java.util.NoSuchElementException with a null message from TreeMap.lastKey(), because parseTypes sizes its table from the largest mapped character without checking that any rule was read. A file with one real rule works, and a two-line guard that returns no custom table when the rule map is empty fixes both factories.",
   "impact_class": "crash",
   "introduced_commit": "33cc5a041e8125a5ecf8e58c994fece4cfb03c7f (SOLR-2059 'Add types attribute to WordDelimiterFilterFactory', SVN r990451 on trunk, by GitHub rmuir; SVN/JIRA patch era, no GitHub PR) and its same-day branch_3x twin 878a697766c (r990456), which shipped in Solr 3.1: they add the types option, parseTypes and the unguarded 'typeMap.lastKey() + 1' table sizing [read]. The class moved into Lucene with LUCENE-2510 (fe2d1194fb6 on trunk, 2012-07-24; branch_4x merge 677846e6a0f, 2012-07-25) and WordDelimiterGraphFilterFactory got a verbatim copy of parseTypes in LUCENE-7619 (by GitHub mikemccand; 637915b890d on main, 4e4ec082caa on branch_6x, 2017-01-17) [read]. The line reader already skipped '#' and blank lines at 33cc5a041e8 (SolrResourceLoader.getLines, moved to WordlistLoader.getLines in LUCENE-4257, 8bfa167a731), so a rule-less file was reachable from the first day. Not a regression: present since the option was added",
   "introduced_date": "2010-08-28 (SOLR-2059, author date = commit date 21:25:44 UTC on trunk; branch_3x the same day); into Lucene 2012-07-24/25 (LUCENE-2510 move); WordDelimiterGraphFilterFactory copy 2017-01-17 (LUCENE-7619)",
   "first_affected_version": "Lucene 4.0.0-BETA [exec] (first Lucene artifact with WordDelimiterFilterFactory, tag 2012-08-10; first GA 4.0.0 [exec]; 4.0.0-ALPHA has neither factory [exec]); WordDelimiterGraphFilterFactory from 6.5.0 [exec] (6.4.2 has no such factory [exec]); before that as Solr code from Solr 3.1 [read]",
   "affected_versions": "every Lucene release from 4.0.0-BETA to 10.6.0 (WordDelimiterFilterFactory, deprecated since 6.5.0 and listed for removal in 11.0 in open issue #16918), every release from 6.5.0 to 10.6.0 (WordDelimiterGraphFilterFactory), and main a9779ef3c193 (both; 10.6.0 run as its release revision, the branch_10_6 head 4ae946e5a9b). [exec] follow-up history probe (public SPI factory plus an in-memory resource loader, -da; rule-less files: comment-only, empty, blank-only, BOM plus comment, sole '# => ALPHANUM' rule; both controls pass) fails on 4.0.0-BETA, 4.0.0, 4.10.4, 5.5.5 and 6.4.2 (WordDelimiterFilterFactory; the graph factory is absent) and on 6.5.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (both factories), and passes on main with the fix shadowed; the finder's JUnit (4 run, 3 failed) fails on 9.1.0, 9.12.3, 10.0.0, 10.5.2, the branch_10_6 head jars and main (-ea and -da) (it does not compile on 9.0.0 and older because of the test-framework package layout); the independent reproduction's JUnit (8 run, 5 failed) fails on main (-ea and -da), 10.5.2 and 9.12.3. [read] releases between the executed ones: the statement is unchanged (git log -G lastKey); Solr 3.1 to 3.6 as Solr code. Not affected: Lucene 4.0.0-ALPHA and older (no factory in Lucene artifacts) [exec]; Solr 1.4.1 and older (no types option) [read]. Not fixed upstream: upstream main 645d4fe14a20 (2026-10-28) last changed either factory in 378ca8d1bbf3 (author date 2026-01-15, javadoc markup only)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/311",
    "https://issues.apache.org/jira/browse/LUCENE-10097",
    "https://github.com/apache/lucene/issues/16911",
    "https://github.com/apache/lucene/issues/16918",
    "https://github.com/apache/lucene/issues/202",
    "https://issues.apache.org/jira/browse/LUCENE-8682"
   ],
   "doc": "",
   "repro": "repro/LFV-929/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-928",
   "priority": "low",
   "priority_rank": 590,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / hunspell (Dictionary SET encoding lookup)",
   "title": "Hunspell Dictionary cannot load SET ISO8859-10, or ISO8859-14 spelled any way except exactly \"ISO8859-14\" (UnsupportedCharsetException at load)",
   "summary": "You load a Hunspell dictionary whose affix file says SET ISO8859-10 (Latin-6, Nordic), a value the hunspell(5) man page lists among the possible SET values, or says ISO8859-14 (Latin-8, Celtic) spelled ISO-8859-14 or iso8859-14, and expect it to load: C Hunspell lower-cases the SET value and drops non-alphanumerics before its table lookup, and in Lucene every other listed ISO-8859 part loads in its hyphenated and lower-case spellings (ISO-8859-2, iso8859-2, ...). Instead the Dictionary constructor throws java.nio.charset.UnsupportedCharsetException, because Dictionary.getDecoder uses Lucene's own ISO8859_14Decoder only for the exact string \"ISO8859-14\" and otherwise calls Charset.forName, and the JDK has no ISO-8859-10 or ISO-8859-14 charset under any name. Spellings that do load decode every letter byte correctly, so nothing is silently wrong; the dictionary is refused.",
   "impact_class": "crash",
   "introduced_commit": "e3172b9239cda3c53769a9e1dd82ea122178b93b (LUCENE-3414 'Added Hunspell for Lucene', trunk svn r1167467, issue = GitHub #4487, no PR; same-day branch_3x twin 1e084f1d08e48f93edafea047282f5b984655909, svn r1167505, shipped in 3.5.0): the first Hunspell code, whose encoding lookup (getJavaEncoding) was a bare Charset.forName, with the javadoc still on main ('This isn't perfect as I think ISCII-DEVANAGARI and MICROSOFT-CP1251 etc are allowed...'). Partial fix: LUCENE-5468 (#6531; dev-branch commit 2e0fc562bc2 of 2014-02-24, branch_4x 055557d04c9 and trunk 06173592e3d of 2014-02-27, released in 4.8.0) added ISO8859_14Decoder, used only when the SET value equals exactly 'ISO8859-14', and the two CHARSET_ALIASES entries; ISO8859-10 and the other ISO8859-14 spellings were left failing. Later changes are behaviour-preserving (LUCENE-9570 8ef6a0da568 reformat; LUCENE-9716 8f75933f3da rename to getDecoder). [read]",
   "introduced_date": "2011-09-10 (LUCENE-3414; current form since the LUCENE-5468 partial fix of 2014-02-24/27)",
   "first_affected_version": "3.5.0 [exec] (tagged 2011-11-25), the first release with the Hunspell module; 3.4.0 has no Hunspell API [exec]. Current form (only the exact 'ISO8859-14' of the two values loads) since 4.8.0 [exec]",
   "affected_versions": "Every release that has the Hunspell module, 3.5.0 to 10.5.2, plus 10.6.0 (branch_10_6 4ae946e5a9b, the RC1 revision) and main a9779ef3c193 [exec]. Two eras: 3.5.0-4.7.2 fail for every spelling of both values, including the exact 'ISO8859-14'; 4.8.0 onwards fail for every spelling of ISO8859-10 and every spelling of ISO8859-14 except the exact one. [read] the lookup has one of three bodies at all 127 release tags with the module in the history clone (3.5.0-4.7.2 bare Charset.forName; 4.8.0-8.8.1 exact-match plus aliases; 9.0.0-10.5.2 the same logic renamed getDecoder); Dictionary.java on upstream main 645d4fe14a20, branch_11x, branch_10x, branch_10_6 and branch_9_12 keeps the exact-match test and has no ISO-8859-10 handling (2026-10-28). Not fixed upstream. All runs on Linux aarch64 with JDK 25.0.3; older JDKs not tested",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-928.html",
   "repro": "repro/LFV-928/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-329",
   "priority": "low",
   "priority_rank": 591,
   "novelty": "new",
   "withheld": false,
   "area": "search / rescoring",
   "title": "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",
   "summary": "You search an index that has no segments yet (for example a freshly created or emptied index, or an empty shard), get the expected 0 hits, and pass them to a DoubleValuesSourceRescorer or LateInteractionRescorer. You expect 0 rescored hits, which is what QueryRescorer and SortRescorer return for the same input. Instead rescore() throws java.util.NoSuchElementException, because it takes the reader's first segment with leaves().getFirst() before it looks at the hits, and there is no first segment.",
   "impact_class": "crash",
   "introduced_commit": "c8147c9e6fa1 (apache/lucene#14776 'Add a rescorer that uses DoubleValuesSource values to re-score first pass hits', by GitHub vigyasharma, main), branch_10x backport 02f5dc30e2fe, first released in 10.3.0 [read]. The unguarded getFirst() is in the first version of the class, so this is not a regression. LateInteractionRescorer (d9618080b340, #14729, 2025-07-08; backport 7de24ce973d0) extends the class from its first version and inherits rescore()",
   "introduced_date": "2025-06-15 (#14776 merged 2025-06-15T04:12:47Z, author date 2025-06-14; branch_10x backport committed 2025-06-15T04:21:01Z)",
   "first_affected_version": "10.3.0 [exec] (the first release with DoubleValuesSourceRescorer and LateInteractionRescorer; 10.2.2 and 9.12.3 do not have the classes [exec])",
   "affected_versions": "10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main ea57360912ed [exec]; not applicable to 10.2.2 and earlier or to any 9.x, where the API does not exist [exec]; upstream main, branch_10x and branch_10_6 (10.6.0, released 2026-10-29) still have leaves.getFirst() at line 53 as read on 2026-10-26 [read]; main 645d4fe14a20 [exec]; branch_11x f85446cb1af [read]; branch_10x 657014b3c57 and branch_10_6 4ae946e5a9b identical to 10.5.2 [read]; not fixed anywhere",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-329.html",
   "repro": "repro/LFV-329/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-251",
   "priority": "low",
   "priority_rank": 592,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / ternary search tree suggester (TSTLookup.lookup and get, TSTAutocomplete.prefixCompletion)",
   "title": "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)",
   "summary": "You build a TSTLookup suggester and call get('') or lookup('', false, 5), for example because a user cleared the search box. You expect null from get(''), whose javadoc says it returns null if the key does not exist (the empty key is never stored), and a list, possibly empty, from lookup(''). Instead both throw StringIndexOutOfBoundsException 'Index 0 out of bounds for length 0', because TSTAutocomplete.prefixCompletion reads key.charAt(0) on its first loop step before it checks the key length, and the tree's root node is never null; non-empty keys work normally on the same lookup.",
   "impact_class": "crash",
   "introduced_commit": "ad8bfb3bc4de0d9eed8e4d44116ea216ca711766 ('SOLR-1316 Create autosuggest component.', trunk svn r988120, 2010-08-23; Subversion era, no pull request): it added TSTAutocomplete.prefixCompletion with the unguarded s.charAt(x) loop and TSTLookup.lookup calling prefixCompletion(root, key, 0) [read]; get('') fails the same way since SOLR-2375 (e71e68235205, 2011-03-01; branch_3x ab2691c7740), which made TSTLookup.get call prefixCompletion [read]; the later moves LUCENE-2995 (f5048293b54), LUCENE-3135 (571ae5043c8) and LUCENE-3965 (e8e4245d9b3) and LUCENE-6829 (c855dd5a33f) left the loop unchanged [read]",
   "introduced_date": "2010-08-23 (SOLR-1316, trunk); 2011-03-01 (SOLR-2375, get); first Lucene release 3.3.0 (2011-06-30)",
   "first_affected_version": "3.3.0 [exec] (2011-06-30; the first Lucene release with org.apache.lucene.search.suggest.tst, in the lucene-spellchecker contrib jar through LUCENE-3135; on the trunk line the first is 4.0.0-alpha, lucene-suggest module); the code first shipped in Solr 3.1.0 as org.apache.solr.spelling.suggest.tst, also affected [exec]; Lucene 3.2.0 and earlier have no such API [exec]",
   "affected_versions": "every Lucene release from 3.3.0 through 10.5.2 and main ea57360912ed; never fixed. [exec] 3.3.0, 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.0.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da), plus Solr 3.1.0's copy: the follow-up's history probe (lookup('') with onlyMorePopular false and true, get(''), lookup('') on an empty dictionary) throws in 4 of 4 calls on each while the non-empty control works; the finder's JUnit also fails on 10.5.2, 9.12.3, 8.11.4 and 6.6.6, the independent reproduction's on 10.5.2 and 9.12.3, and the intended-behaviour check's probe on 10.5.2. [read] all 131 release tags in the history clone that contain TSTAutocomplete.java have the same loop and no empty-key guard in TSTLookup (regex source check); main ea57360912e and branch_10x 1309534296e are unguarded. Not affected: Lucene 3.2.0 and earlier (API absent; 3.2.0 [exec]). All runs on aarch64 with JDK 25.0.3; the defect is plain string index logic, so the JDK changes only the message text.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-251.html",
   "repro": "repro/LFV-251/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-985",
   "priority": "low",
   "priority_rank": 593,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / ternary search tree suggester (TSTLookup add, build, store, load and ramBytesUsed; TSTAutocomplete.insert; TernaryTreeNode.sizeInBytes)",
   "title": "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)",
   "summary": "You add the 20,992 CJK Unified Ideographs to a TSTLookup in code-point order, or build one from a single suggestion of 20,000 characters, and expect to store it, load it back and ask its size, as Lookup.store and Lookup.load promise (they document failure only as a false return or an IOException) and as WFSTCompletionLookup does with the same 20,000-character suggestion. Instead add(), get() and lookup() work, but store(), load() and ramBytesUsed() throw StackOverflowError on the JVM's default thread stack, and for the long suggestion build() itself overflows, because TSTAutocomplete.insert, TSTLookup.writeRecursively and readRecursively and TernaryTreeNode.sizeInBytes each use one Java stack frame per tree level. Adding keys in sorted order turns each level's lo/hi links into a chain (that sorted insertion unbalances this tree was noted by its author, Ankul Garg, on SOLR-1316 in 2009, as a speed concern), so the tree gets about as deep as the number of distinct first characters, and every character of a key adds one more level even in build().",
   "impact_class": "crash",
   "introduced_commit": "ad8bfb3bc4de0d9eed8e4d44116ea216ca711766 (SOLR-1316 'Create autosuggest component', svn r988120, committed by Andrzej Bialecki; branch_3x port d2353e16e2e2; a Solr JIRA patch, no GitHub PR): the recursive TSTAutocomplete.insert behind add() and build() [read]; the store/load leg came with e71e68235205 (SOLR-2375 'Store & Load functionality for Suggester Lookup implementations', branch_3x ab2691c77406), whose writeRecursively/readRecursively recursion is unchanged on main (TSTLookup.java:218-265) [read]; the ramBytesUsed leg with fab92b83d0df (LUCENE-5463, apache/lucene#6526, Adrien Grand; branch_4x 7e95e51347d4), which made TernaryTreeNode.sizeInBytes recursive [read]. Not a regression: the recursion has been there since the first release that shipped the suggester.",
   "introduced_date": "2010-08-23 (insert: add/build leg); 2011-03-01 (store/load leg); 2014-02-24 (ramBytesUsed leg)",
   "first_affected_version": "3.3.0 [exec] (first Lucene release with TSTLookup, lucene-spellchecker via LUCENE-3135; the same code shipped first in Solr 3.1.0's solr-core [exec]); Lucene 3.2.0 and Solr 1.4.1 have no TST classes [exec]; the ramBytesUsed leg first in 4.8.0 [exec] (4.7.2's sizeInBytes was not recursive [exec])",
   "affected_versions": "every Lucene release from 3.3.0 through 10.5.2, 10.6.0 (released 2026-10-29; branch_10_6 head 4ae946e5a9b9) and main a9779ef3c193, plus Solr 3.1.0 and 3.2.0 (solr-core); not fixed upstream. [exec] main with -ea and -da, the 10.6 RC, 10.5.2, 9.12.3, 8.11.4, 7.7.3 and 6.6.6 (all three legs: sorted add fails in store, a long key in build, ramBytesUsed); 5.5.5 and 4.10.4 (sorted-add leg); 4.0.0, 3.6.2, 3.3.0 and Solr 3.1.0 (sorted-add and long-key legs); 4.8.0 (ramBytesUsed leg). [read] all 123 release tags 4.0.0-alpha to 10.5.2 in the history clone and all 8 tags 3.1 to 3.6.2 have the 4 recursive insert calls and the 6 recursive store/load calls, and every tag from 4.8.0 the 3 recursive sizeInBytes calls; upstream has not changed the tst package since 8e2c6aa1d58 (author date 2025-06-27). All runs on JDK 25.0.3 (aarch64), mostly on 1 MiB threads; the step that fails and the depth at which it fails depend on the stack size and the JIT state.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-985.html",
   "repro": "repro/LFV-985/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-786",
   "priority": "low",
   "priority_rank": 594,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / ternary search tree suggester (TSTLookup.build: rebuild failure atomicity and rebuild consistency)",
   "title": "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",
   "summary": "You build a TSTLookup from {foo/10, bar/5}, rebuild it from a dictionary whose stream throws IOException after its first line, catch the exception and keep using the lookup. You expect either the previous build (lookup('fo') returns foo and getCount() 2), which FSTCompletionLookup, WFSTCompletionLookup and AnalyzingSuggester keep after the same failed rebuild, or an empty lookup with getCount() 0. Instead lookup('fo') returns nothing while getCount() still returns 2, and store()+load() carry that state into a new lookup, because build() replaces the tree with an empty one before it reads and sorts the input and resets the count only after that; for the same reason a lookup made while a rebuild is still reading its input finds nothing.",
   "impact_class": "minor",
   "introduced_commit": "b5926da2d67820f5fdf8c8ec9b2e642b74d12070 (trunk, svn r1565810, 'LUCENE-5404: Add .getCount method to all suggesters (Lookup), persist count metadata on .store(), ...'; issue LUCENE-5404, migrated as apache/lucene#6467; JIRA patch era, no pull request) [read]: it placed 'count = 0' after the SortedInputIterator constructor, which reads and sorts the whole input (main TSTLookup.java:130), and count++ in the copy loop (:139), next to the older 'root = new TernaryTreeNode()' before the input is read (:125), so a build that throws while its input is read leaves an empty tree next to the previous count; it reached a release through 55594bad9b07af90de4ab2a2fb0bac8e8c2b0b3c (LUCENE-5944, Robert Muir, 2014-09-18), the commit that backported trunk's changes into the newly created branch_5x (the branch was created that day by c046bec1445, whose TSTLookup.build has no count lines). The tree reset alone (the during-rebuild half, and the loss of the previous suggestions after a failed rebuild) comes from ad8bfb3bc4de0d9eed8e4d44116ea216ca711766 (SOLR-1316, 2010-08-23) and is in every Lucene release since 3.3. The branch_4x commit of LUCENE-5404 (fdf4595051a) omitted the two count lines, so 4.7.0-4.10.4 report getCount() 0 after every build and a failed rebuild there leaves a consistent empty lookup.",
   "introduced_date": "2014-02-07 (trunk commit b5926da2d67); 2014-09-18 (branch_5x commit 55594bad9b0); first release 5.0.0, tagged 2015-02-19. Tree reset before the read: 2010-08-23 (ad8bfb3bc4de)",
   "first_affected_version": "5.0.0 [exec] for the failed-rebuild state (empty tree with the previous count); 4.10.4 is the last release without it [exec]. The during-rebuild half fails on every executed release back to 3.6.2 and is in Lucene since 3.3 [read]",
   "affected_versions": "Failed-rebuild half: every release from 5.0.0 through 10.6.0 (the latest) and main a9779ef3c193; not fixed upstream. [exec] the follow-up's version-portable probe fails on 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.8.2, 8.9.0, 8.10.0, 8.10.1, 8.11.0-8.11.4, 9.0.0, 9.1.0, 9.2.0, 9.12.3, 10.0.0, 10.5.2 and main (state count=2 fo->[] after the failed rebuild and after store/load); the finder's JUnit fails 2 of 2 on main (-ea and -da), 10.5.2, 9.12.3 and 8.11.4; the independent reproduction's JUnit fails 3 of 3 on main (-ea and -da), 10.5.2 and 9.12.3; [exec] on the 10.6.0 jars (Maven Central, SHA-1 verified, manifest 10.6.0 4ae946e5a9b9) the one-test repro fails with -ea and -da and a failed-rebuild probe gives lookup(ba)=[] count=1 after the failed rebuild and after store/load. [read] every tagged release from 5.0.0 to 10.5.2 (98 tags in the history clone) has the same build() ordering. During-rebuild half: [exec] fails on 3.6.2, 4.0.0, 4.6.1, 4.7.0, 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.1.0, 9.2.0, 9.12.3, 10.0.0, 10.5.2, 10.6.0 (fact check) and main; [read] since 3.3. The upstream file is unchanged since 8e2c6aa1d587 (2025-06-27) and no open PR touches lucene/suggest/.../tst/ (prior-report record, 2026-10-27).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-786.html",
   "repro": "repro/LFV-786/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-666",
   "priority": "low",
   "priority_rank": 595,
   "novelty": "new",
   "withheld": false,
   "area": "spatial-extras / prefix-tree heatmap faceting (HeatmapFacetCounter.calcFacets, reached through PrefixTreeStrategy.calcFacets)",
   "title": "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",
   "summary": "You configure a non-geo SpatialContext (geo=false) with Web Mercator world bounds such as ENVELOPE(-20037508.34, 20037508.34, 20037508.34, -20037508.34), index points with RecursivePrefixTreeStrategy over the default 12-level QuadPrefixTree, and ask PrefixTreeStrategy.calcFacets for the heatmap of a box inside the world that ends at its east edge, for example x in [3,000 km, east edge], y in [0, 1,000 km] at facet level 5. You expect a heatmap whose region covers the box (14 columns by 1 row), as the calcFacets javadoc describes, or at worst the documented too-many-cells IllegalArgumentException. Instead calcRowsOrCols computes range / cellWidth = 14.000000000000002 in floating point, Math.ceil makes that 15 columns, the region would end a whole cell past the east edge, the non-geo code takes the branch commented 'wraps dateline (won't happen if !geo)' and makes maxX negative, and building the region throws InvalidShapeException 'maxX must be >= minX'; the same box at the north edge throws 'Y values [...] not in boundary'.",
   "impact_class": "crash",
   "introduced_commit": "248121bb3f74a8af032ccd66f903904eaa3e1c59 (trunk, svn r1658298) and its branch_5x backport b1c673bcca4d1d8493812121f8bb32acef3040dc (svn r1658302, the commit that shipped in 5.1.0): LUCENE-6191 'Spatial 2D heatmap for PrefixTreeStrategy' (migrated as apache/lucene#7253), by GitHub dsmiley, committed directly to svn with no PR [read]. Not a regression: the defect is as old as the API.",
   "introduced_date": "2015-02-09",
   "first_affected_version": "5.1.0 [exec]; 5.0.0 has no HeatmapFacetCounter [exec]",
   "affected_versions": "Every release from 5.1.0 through 10.6.0 (10.6.0 [exec] on its release jars by the bug doc's test, -ea and -da) and main a9779ef3c193; not fixed. [exec] the follow-up's version-portable main() (four edge cases and a 1-m-inside control) fails 4 of 4 with the control OK on 5.1.0 (-ea, -da), 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.2.0 and 8.3.0 (before and after the LUCENE-8755 getCell change), 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (-ea, -da) and main (-ea, -da), with byte-identical messages, and passes on main with the fix shadowed; the independent reproduction's JUnit fails 3 of 4 on main, 10.5.2 and 9.12.3; the intended-behaviour check's JUnit fails 4 of 7 on main, 10.5.2 and 9.12.3; the finder's JUnit or main() variant fails on 7.7.3, 8.2.0, 8.11.2, 9.12.3, 10.5.2 and main. [read] the three code regions (calcRowsOrCols, the column/row computation, the heatMax snap/wrap block), normalised for comments, whitespace and the spatial4j rename, are identical at all 97 release tags 5.1.0-10.5.2 in the local clones (the 8.8.2-8.11.4 tags are missing there; 8.11.4 was executed). No commit to HeatmapFacetCounter.java on main and no open PR touches it (read 2026-10-27).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-666.html",
   "repro": "repro/LFV-666/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-478",
   "priority": "low",
   "priority_rank": 596,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / FileDictionary (text-file dictionary for Lookup.build)",
   "title": "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",
   "summary": "You build a suggester from a text file with lines such as 'foo bar|10|p1', read with new FileDictionary(reader, \"|\"), and expect the entry (suggestion 'foo bar', weight 10, payload 'p1') that the class javadoc's line format describes. Instead FileDictionary passes the delimiter to String.split, which reads it as a regular expression: '|' (an empty alternation) splits between every character, so getEntryIterator() throws IllegalArgumentException 'More than 3 fields in one line'; '.' and '+' throw ArrayIndexOutOfBoundsException and PatternSyntaxException. With '$' or '^' no line is ever split, so every line silently becomes one suggestion such as 'foo bar$10$p1' with weight 1 and no payload, and a suggester built from it returns that key.",
   "impact_class": "wrong error",
   "introduced_commit": "99255ff0da685e6727d08833ed1c7feca18525ce (trunk, svn r1541341) and its branch_4x backport afdc5611a1c9af803e90d0e3833c1f88d60274c0 (svn r1541360), LUCENE-5337 'Add Payload support to FileDictionary (Suggest) and make it more configurable' (now apache/lucene#6401; JIRA and svn patch era, no PR; patch by areek, committed by ErickErickson). It added the constructors FileDictionary(Reader, String) and FileDictionary(InputStream, String) and replaced line.split(\"\\t\") with line.split(fieldDelimiter) [read] [exec]",
   "introduced_date": "2013-11-13 (trunk 00:56:37 UTC, branch_4x 02:22:58 UTC)",
   "first_affected_version": "4.7.0 [exec]; 4.6.1 and older are not affected [exec]: the delimiter constructors do not exist there and the only delimiter is a hard-coded literal TAB",
   "affected_versions": "Every release from 4.7.0 through 10.5.2 (110 release tags [read]: git tag --contains gives 27 tags 4.7.0-5.5.5 via afdc5611a1c and 83 tags 6.0.0-10.5.2 via 99255ff0da6), 10.6.0 (released 2026-10-29; the doc's minimal test fails on its release jar [exec]) and main ea57360912ed. [exec] with a portable public-API probe, identical output on every one: 4.7.0 (-ea, -da), 4.10.4, 5.5.5, 6.0.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea, -da); the finder's JUnit fails 4 of 4 on 9.12.3, 10.0.0, 10.5.2 and main (-ea, -da); the independent reproduction's JUnit fails 6 of 6 on 9.12.3, 10.5.2 and main (-ea, -da). Releases between the executed points are affected by [read] only. Not fixed upstream: main a9779ef3c193 (2026-10-26) still calls line.split(fieldDelimiter) [read]. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-478.html",
   "repro": "repro/LFV-478/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-455",
   "priority": "low",
   "priority_rank": 597,
   "novelty": "new",
   "withheld": false,
   "area": "queries / intervals (PayloadFilteredTermIntervalsSource per-segment hasPayloads check)",
   "title": "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",
   "summary": "Index a text field in which only some tokens carry payloads (for example with DelimitedPayloadTokenFilter: 'big|adj dog|noun' next to 'dog walks') and search it with Intervals.term(\"dog\", payloadFilter). You expect the documents whose 'dog' payload passes the filter, however the documents happen to be split into segments. Instead, as soon as one segment contains only documents without payloads for that field, the whole search throws IllegalArgumentException 'Cannot create a payload-filtered iterator over field f because it has no indexed payloads', while the same documents after forceMerge(1) return the right hits.",
   "impact_class": "crash",
   "introduced_commit": "5ca25249274bd4232b0faa049814d2b3b192abdb (master; branch_8x backport 13aac3becde7770c8c4e6b33102432f7dee99a10), LUCENE-8694 'IntervalsSource that filters by payload' (now apache/lucene#9740), committed by romseygeek from the JIRA patch (no GitHub PR): the class was added together with both hasPayloads() == false checks, modelled on the hasPositions() check above them; the later commits to the file (f1782d0dd11 LUCENE-8477, 46cc24d77ec LUCENE-8856 move to the queries module, 7c1ba1aebee LUCENE-9099, 8ef6a0da568 LUCENE-9570 reformat only, 4991e3a1f47 #12827) left the checks unchanged [read]",
   "introduced_date": "2019-03-18 (commit date; author date 2019-02-15)",
   "first_affected_version": "8.1.0 [exec] (sandbox module, package org.apache.lucene.search.intervals; queries module from 8.2.0 [exec], LUCENE-8856); 8.0.0 has no Intervals.term(term, payloadFilter) [exec]",
   "affected_versions": "every release that has Intervals.term(term, payloadFilter): 8.1.0-8.1.1 (sandbox), 8.2.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.6.0 and main ea57360912ed and 645d4fe14a20 [exec]; the point releases not executed rest on the tag sweep (both checks present in every tag 8.1.0..10.5.2) and, for 8.8.2-8.11.4, on a bytecode check of the release jars [read]; upstream main 49483e82b357 and the branch_10x and branch_10_6 heads still have both checks [read], and on 2026-10-30 the file's last commit on upstream main 716d6f216f52, branch_11x and branch_10_6 is still #12827 [read]; not fixed upstream; all runs on aarch64 with JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-455.html",
   "repro": "repro/LFV-455/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-776",
   "priority": "low",
   "priority_rank": 598,
   "novelty": "new",
   "withheld": false,
   "area": "facet / range drill-down and filter queries (DoubleRange/LongRange.ValueSourceQuery)",
   "title": "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",
   "summary": "You build a range filter with DoubleRange#getQuery(null, DoubleValuesSource.fromQuery(new TermQuery(...))) (or LongRange#getQuery with the source's toLongValuesSource() view) and run it on an IndexSearcher, and expect it to match the documents whose query score falls in the range, as FunctionMatchQuery does with the same source, because core says Queries that use a DoubleValuesSource call rewrite() in createWeight. Instead the search throws UnsupportedOperationException 'This DoubleValuesSource must be rewritten': the range query hands the source to getValues without ever rewriting it against the searcher. With a legacy QueryValueSource view on a searcher that uses ClassicSimilarity the same omission is silent: the source scores with a fresh default-Similarity searcher, and the range [top score, top score] matches 0 documents where FunctionMatchQuery matches 3.",
   "impact_class": "crash",
   "introduced_commit": "03afeb7766a39996de3c85e8a6ab24d2a352dd1c on branch_7x (first released in 7.2.0); master equivalent 2a4dd499bbd2f5ed1f481e17eeaee4f32b927185 (first released in 8.0.0). LUCENE-7736 'Expose some IndexReader stats via DoubleValuesSources' (apache/lucene#8787; JIRA patch, no GitHub PR; author romseygeek, reviewed by jpountz) added DoubleValuesSource/LongValuesSource#rewrite(IndexSearcher) with the rule that Queries call rewrite() in createWeight, updated FunctionMatchQuery and FunctionScoreQuery, and left the facet DoubleRange/LongRange ValueSourceQuery unchanged [read]. The no-rewrite line valueSource.getValues(context, null) comes from LUCENE-7610 (713b65d1dcc on master, a238610bab1 on branch_6x, first in 6.4.0), written before any rewrite step existed; DoubleValuesSource.fromQuery, the main throwing trigger, came the next day with LUCENE-7998 (c6171019d5f on branch_7x, 423677f20e6 on master), in the same 7.2.0 release.",
   "introduced_date": "2017-11-15 (LUCENE-7736 committed on branch_7x and master; author date 2017-03-28); LUCENE-7998 committed 2017-11-16; the getValues line from LUCENE-7610, committed 2017-01-07",
   "first_affected_version": "7.2.0 [exec]: the 5-check probe fails 5 of 5 with its controls passing, and the no-rewrite probe gives [] where FunctionMatchQuery gives [0, 1, 4]; 7.1.0 is the last unaffected release (no rewrite API: the 5-check probe does not compile, and the no-rewrite probe passes on 6.5.0, 6.6.6, 7.0.0 and 7.1.0 [exec], where the facet query and FunctionMatchQuery both ignore the searcher); the direct overloads exist since 6.4.0.",
   "affected_versions": "every release from 7.2.0 to 10.5.2 (71 releases: 7.2.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2), 10.6.0 [exec] and main a9779ef3c193 (unreleased 11.0); branch_10_6 and branch_10x [read]; upstream main f7bcc0abd816 (2026-10-27) has the same code; never fixed upstream. [exec] the follow-up's 5-check probe fails on 7.2.0, 7.2.1, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da on 7.2.0, 10.5.2 and main), the finder's JUnit 3 of 3 and the independent reproduction's JUnit 5 of 7 on 9.12.3, 10.5.2 and main; [read] a static scan of every other 6.x-10.x release tag in the history clone (no release ever calls valueSource.rewrite in these classes); 8.8.2-8.11.3 are not tagged in the clone and are inferred from 8.8.1 (scan) and 8.11.4 (exec). On 7.2.0-7.7.1 and 8.0.0 (before LUCENE-8726) a QueryValueSource view already rewritten by another consumer carries the searcher into the facet query and masks the silent variant; fresh instances show it there too, and the throwing triggers are not affected.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-776.html",
   "repro": "repro/LFV-776/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-893",
   "priority": "low",
   "priority_rank": 599,
   "novelty": "new",
   "withheld": false,
   "area": "queries / function queries (ValueSource to DoubleValuesSource/LongValuesSource bridge: asDoubleValuesSource, asLongValuesSource)",
   "title": "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",
   "summary": "You expose a ValueSource as a DoubleValuesSource with asDoubleValuesSource() and score with it through FunctionScoreQuery (for example FunctionScoreQuery.boostByValue, the documented replacement for the removed BoostedQuery), or sort by asLongValuesSource().getSortField(), and expect the per-document values the same ValueSource gives through FunctionQuery or its own getSortField (3 for ttf(text, test) in the repro). Instead the bridge builds a fresh context in getValues and explain and calls in.getValues without ever calling in.createWeight, so ttf and sttf, which compute their statistic in createWeight and return context.get(this) from getValues, throw NullPointerException ('this.val$fv' is null at ValueSource.java:210 or :144), and a user ValueSource that stores per-query state in createWeight, as the ValueSource javadoc describes, finds its context entry missing. FunctionQuery, FunctionRangeQuery and ValueSource#getSortField all call createWeight first, and the bridge's rewrite(searcher) already holds the searcher such a call needs.",
   "impact_class": "crash",
   "introduced_commit": "713b65d1dcc (master) / a238610bab1 (branch_6x backport), 'LUCENE-7610: Deprecate ValueSource methods in facets module' (issue LUCENE-7610, now #8661; pre-GitHub-PR era, patch on the issue) [read]; not a regression: the bridge has never called createWeight, and none of the 77 tagged releases 6.4.0-10.5.2 adds the call",
   "introduced_date": "2017-01-06 (author date of 713b65d1dcc and a238610bab1; committed 2017-01-07); first released in 6.4.0",
   "first_affected_version": "6.4.0 [exec] (the first release with the bridge API, CHANGES 'Lucene 6.4.0 / API Changes / LUCENE-7610'; a 6.x port fails 4 of 6 there with -ea and -da, through the bridges' getSortField, because FunctionScoreQuery only arrived in 6.5.0). 6.3.0 is not affected because the API is absent [exec].",
   "affected_versions": "Every release from 6.4.0 to 10.5.2 (77 tagged releases) [read], branch_10_6 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193; not fixed upstream (ValueSource.java unchanged since #15406, author date 2025-12-02; upstream main c5ab3e57b9ba) [exec].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-893.html",
   "repro": "repro/LFV-893/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-886",
   "priority": "low",
   "priority_rank": 600,
   "novelty": "new",
   "withheld": false,
   "area": "queries / function queries (RangeMapFloatFunction, map(): createWeight propagation to sub-ValueSources)",
   "title": "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",
   "summary": "You build map(x, 0, 2, ttf(text, test)) as new RangeMapFloatFunction(source, 0, 2, new TotalTermFreqValueSource(...), null) and score it with FunctionQuery, expecting every document whose x lies in [0, 2] to get the target's value (3 in the repro, the score FunctionQuery(ttf) gives on its own). Instead the search throws NullPointerException ('this.val$targets' is null at RangeMapFloatFunction.java:84); sttf as the default fails the same way (:85), and a user ValueSource that stores a per-query statistic in createWeight, as the ValueSource javadoc describes, finds its context entry missing. The cause: RangeMapFloatFunction.createWeight forwards only to source, while getValues also asks target and default for their values on the same context, whereas every other composite ValueSource forwards createWeight to all of its children.",
   "impact_class": "crash",
   "introduced_commit": "4109c6db3365a901de47c97dcb41e673ee62ec95 (trunk, svn r1546926; branch_4x backport b7ac9803c82619b77529af906f36e149e1d53cae, svn r1546927), SOLR-1871 'Function Query \"map\" variant that allows \"target\" to be an arbitrary ValueSource' (pre-GitHub, no PR; CHANGES 4.7.0: 'SOLR-1871: The RangeMapFloatFunction accepts an arbitrary ValueSource as target and default values.') [read]: it turned target and default from float constants into ValueSources and made getValues call target.getValues and defaultVal.getValues on the query context, but left createWeight forwarding only to source. That method dates from SOLR-1432 (1eb46979775, 2009-09-17), when target and default were constants and forwarding to source was complete. git log -S 'target.createWeight' and -S 'defaultVal.createWeight' find no commit that ever added the forwarding.",
   "introduced_date": "2013-12-02 (trunk 4109c6db336 at 08:33:33Z, branch_4x b7ac9803c82 at 08:35:09Z; author date = commit date for both); first released in 4.7.0",
   "first_affected_version": "4.7.0 [exec] (the first release with the ValueSource target/default constructor; an era-ported main() probe fails the same 4 of 13 checks there with -ea and -da). 4.6.1 and earlier are not affected because the API is absent [exec].",
   "affected_versions": "Every release from 4.7.0 to 10.5.2 (119 releases listed in the follow-up), branch_10_6 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193; no upstream fix. [exec] [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-886.html",
   "repro": "repro/LFV-886/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-299",
   "priority": "low",
   "priority_rank": 601,
   "novelty": "known",
   "withheld": false,
   "area": "search / IndriAndQuery (composite query clause rewriting)",
   "title": "IndriAndQuery does not rewrite its clauses, so a PrefixQuery, WildcardQuery, FuzzyQuery or other rewrite-only clause makes search, count and explain throw UnsupportedOperationException",
   "summary": "You build an IndriAndQuery from ordinary clauses, for example a TermQuery and the PrefixQuery f:ban*, and search with it. You expect the documents the clauses match, as with the same IndriAndQuery built from clauses that IndexSearcher.rewrite has already rewritten. Instead the search throws UnsupportedOperationException 'Query f:ban* does not implement createWeight', because IndriAndQuery keeps the default rewrite (it returns itself) and IndriAndWeight creates a Weight for each clause exactly as given, which only primitive queries support.",
   "impact_class": "crash",
   "introduced_commit": "9cc5c9b7983c (LUCENE-9537 'Add initial Indri search engine functionality to Lucene', by GitHub cammiemw; apache/lucene-solr#2097, now apache/lucene#10577, merged by mikemccand), released through its branch_8x backport a6125fb93855 [read]; not a regression: the clause loop has called createWeight on the clause as given since the class was added",
   "introduced_date": "2021-01-29 (lucene-solr#2097 merged and backported to branch_8x the same day)",
   "first_affected_version": "8.9.0 [exec]",
   "affected_versions": "8.9.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main ea57360912ed [exec]; every release from 8.9.0 on (8.9.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2) [read]; not applicable to 8.8.2 and earlier, where IndriAndQuery does not exist and the repro does not compile [exec]; upstream main cb19aecba8f3 and branch_10x unchanged as of 2026-10-26 [read]; not fixed anywhere",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene-solr/pull/2097",
    "https://github.com/apache/lucene/issues/11194",
    "https://issues.apache.org/jira/browse/LUCENE-10157",
    "https://github.com/apache/lucene/issues/10577",
    "https://issues.apache.org/jira/browse/LUCENE-9537",
    "https://github.com/apache/lucene/issues/463"
   ],
   "doc": "",
   "repro": "repro/LFV-299/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-463",
   "priority": "low",
   "priority_rank": 602,
   "novelty": "known",
   "withheld": false,
   "area": "queries / intervals (PayloadFilteredTermIntervalsSource Matches API; UnifiedHighlighter WEIGHT_MATCHES)",
   "title": "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",
   "summary": "Index a field with payloads (for example 'big|adj dog|noun' through DelimitedPayloadTokenFilter), search it with Intervals.ordered(Intervals.term(\"big\"), Intervals.term(\"dog\", payloadFilter)), then ask Weight#matches for the match positions of a hit or highlight the hit with the UnifiedHighlighter. You expect the positions and a highlighted snippet, as with the plain Intervals.term(\"dog\"). Instead Weight#matches throws UnsupportedOperationException for every matching document (ordered, unordered, maxgaps, atLeast), and highlighting throws for those and also for phrase, containing and containedBy, because the payload-filtered term's match iterator throws from getQuery(), which MatchesIterator#getQuery says returns a TermQuery for the current match; search and count still return the right hits.",
   "impact_class": "crash",
   "introduced_commit": "5ca25249274bd4232b0faa049814d2b3b192abdb (master; branch_8x backport 13aac3becde), LUCENE-8694 'Payload-filtered term intervals' (now apache/lucene#9740) by romseygeek, no pull request named: it created PayloadFilteredTermIntervalsSource with 'getQuery() { throw new UnsupportedOperationException(); }', lines that git blame -C -C traces to TermIntervalsSource, whose placeholder came from LUCENE-8422 (1acfca5ebcc). It became a defect of this class alone with fc5cad931f3 (LUCENE-9031, 8.4.0), which implemented getQuery() in TermIntervalsSource, MultiTermIntervalsSource, CachingMatchesIterator and IntervalMatches but not here, and made CachingMatchesIterator.cache() call getQuery(); ca073c98fa8 (LUCENE-10140, #370, 9.0.0) made Weight#matches itself throw, and 2719cf6630e (LUCENE-9431, #362, 9.0.0) made WEIGHT_MATCHES the UnifiedHighlighter default [read]",
   "introduced_date": "2019-02-15 (author date; committed 2019-03-18 on master and branch_8x); payload-specific since fc5cad931f3 (authored 2019-11-14, committed 2019-11-24)",
   "first_affected_version": "8.1.0 [exec] (sandbox module, package org.apache.lucene.search.intervals; queries module from 8.2.0); on 8.1.0-8.3.1 plain Intervals.term failed the same way (the general LUCENE-9031 bug); from 8.4.0 [exec] only the payload-filtered term still throws; Weight#matches itself and default-flag highlighting throw from 9.0.0 [exec]; 8.0.0 has no Intervals.term(term, payloadFilter) [exec]",
   "affected_versions": "every release from 8.1.0 to 10.5.2 and main ea57360912ed [exec]; the other point releases rest on a source scan of the tags 8.1.0-8.8.1 and 9.0.0-10.5.2 and a bytecode check of the 8.8.2-8.11.4 jars [read]; upstream main 49483e82b357, branch_10x and branch_10_6 still throw at line 241 [read], so 10.6.0 (released 2026-10-29) is very likely affected [not executed]; not fixed upstream; all runs on aarch64 with JDK 25.0.3",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/10074",
    "https://issues.apache.org/jira/browse/LUCENE-9031",
    "https://github.com/apache/lucene/issues/12827",
    "https://github.com/apache/lucene/issues/9468",
    "https://issues.apache.org/jira/browse/LUCENE-8422",
    "https://github.com/apache/lucene/issues/9740"
   ],
   "doc": "",
   "repro": "repro/LFV-463/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-604",
   "priority": "low",
   "priority_rank": 603,
   "novelty": "new",
   "withheld": false,
   "area": "queries / intervals (MultiTermIntervalsSource behind Intervals.prefix, wildcard, regexp, range, fuzzyTerm and multiterm; IntervalQuery search and Weight#matches)",
   "title": "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",
   "summary": "You index 'alpha beta' into a field with IndexOptions.DOCS_AND_FREQS (no positions) and search IntervalQuery(\"body\", Intervals.ordered(Intervals.prefix(\"alph\"), Intervals.prefix(\"bet\"))). You expect IllegalArgumentException ('... because it has no indexed positions'), because the IndexOptions javadoc says positional queries on such a field throw and the same query written with Intervals.term(\"alpha\") and Intervals.term(\"beta\") does throw. Instead MultiTermIntervalsSource never checks Terms#hasPositions(), runs the interval logic on the position -1 that the postings return, and silently reports 0 hits (1 of 2 on a MultiReader that also holds a positioned copy of the document); wildcard, regexp, fuzzyTerm, range and multiterm leaves behave the same way.",
   "impact_class": "wrong error",
   "introduced_commit": "7d7ab14776b7257e09679d840182a4286928e452 (master) and its branch_8x backport ceadb5f1339fe5bf09f9818470872d4957b63ba5, both 'LUCENE-8646: Add multi-term intervals' (JIRA patch by GitHub romseygeek, no GitHub PR; migrated issue apache/lucene#9692), which created MultiTermIntervalsSource on top of new static helpers TermIntervalsSource.intervals(BytesRef, TermsEnum) and matches(TermsEnum, int) that start after the hasPositions() guard of the instance methods (the guard and its test date from LUCENE-8196, 7.4.0) [read]",
   "introduced_date": "2019-01-22 (committed to master and branch_8x; authored 2019-01-17)",
   "first_affected_version": "8.0.0 [exec], the first release with multi-term interval sources (then in lucene-sandbox, package org.apache.lucene.search.intervals; in lucene-queries from 8.2.0, LUCENE-8856); 7.7.3 has no Intervals.prefix [exec] and its only interval leaf, Intervals.term, throws as documented [exec]",
   "affected_versions": "every release from 8.0.0 through 10.6.0 (10.6.0 [exec]) and main a9779ef3c193 [exec]. 8.0.x-8.1.x is sandbox code; from 8.2.0 the class is in lucene-queries. Each factory is affected from the release that added it [read]: prefix and wildcard 8.0.0, multiterm 8.4.0, fuzzyTerm 9.1.0 (also StandardQueryParser fn:wildcard / fn:fuzzyTerm), regexp and range 9.12.0. The independent reproduction's JUnit (all six factories on DOCS and DOCS_AND_FREQS) fails on main (-ea, -da), 10.5.2 (-ea, -da) and 9.12.3 (-ea) [exec]. Not fixed upstream: upstream main's MultiTermIntervalsSource is byte-identical to a9779ef3c193, and branch_10x and branch_10_6 have no guard [read]. Tags 8.8.2-8.11.4 are not in the history clone; for those the result comes from executing the release jars.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-604.html",
   "repro": "repro/LFV-604/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-393",
   "priority": "low",
   "priority_rank": 604,
   "novelty": "new",
   "withheld": false,
   "area": "classification / NearestFuzzyQuery (KNearestFuzzyClassifier)",
   "title": "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)",
   "summary": "You index 6 documents containing 'apple' (class fruit), delete 5 of them under NoMergePolicy (or soft-delete them and keep them with SoftDeletesRetentionMergePolicy), and then search NearestFuzzyQuery('apple') or call KNearestFuzzyClassifier.assignClass('apple'), expecting the one live document and the class fruit. Instead both throw IllegalArgumentException 'boost must be a positive float, got -0.25276297'. NearestFuzzyQuery computes idf = ln((numDocs+1)/(docFreq+1)) + 1 from reader.numDocs(), which counts only live documents, and reader.docFreq(), which still counts the 5 deleted copies, so idf = ln(2/7) + 1 < 0, and since LUCENE-7996 (8.0.0) BoostQuery rejects the resulting negative boost.",
   "impact_class": "crash",
   "introduced_commit": "92e460389dc9b0af83c445cb029e3a51799a37dc 'LUCENE-7838 - removed dep from sandbox, created a minimal FLT version specific for knn classification' (by GitHub tteofili; issue apache/lucene#8889; committed directly to master, no pull request) created NearestFuzzyQuery and wrote every defective line: corpusNumDocs = reader.numDocs() (:140 on main), df = reader.docFreq(startTerm) (:155), score = edit^2 * idf(df, corpusNumDocs) (:187), the idf formula (:198-199; line 199 later reformatted by 7f8b7ffbcad, LUCENE-9570, same expression) and new BoostQuery(tq, st.score) (:248, :256) [read]. The exception comes from a later, correct change, not from the defect: a8a63464e7da63b3dbc884634fd0e00b3f0c140b 'LUCENE-7996: Queries are now required to produce positive scores' (by GitHub jpountz; apache/lucene#9044) added the BoostQuery positive-boost check [exec]",
   "introduced_date": "2017-06-29 (92e460389dc9, the defect); 2017-12-06 (a8a63464e7da, LUCENE-7996, which turns it into an exception)",
   "first_affected_version": "8.0.0 [exec] for the IllegalArgumentException (the first release with the LUCENE-7996 BoostQuery check). The defective idf is in every release since 7.0.0, the first release with NearestFuzzyQuery and KNearestFuzzyClassifier (6.6.6: API absent, compile error [exec]); on 7.0.0 and 7.7.3 [exec] the same input silently gives a negative boost (-0.25276297) and a negative hit score (-0.3893675) instead of throwing",
   "affected_versions": "Exception: every release from 8.0.0 to 10.6.0 and main ea57360912ed (10.6.0 [exec] on its release jars, -ea and -da, in the bug doc's re-check). [exec] the follow-up history matrix (same seed, same thrown value -0.25276297): 8.0.0 (-ea and -da), 8.11.4 (-ea and -da), 9.0.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) fail; the finder's JUnit fails 2 of 2 on main (-ea and -da), 10.5.2 and 9.12.3 (9.x accessor variant repro/src-9x); the independent reproduction's JUnit fails 3 of 4 (its control passes) on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's LogByteSizeMergePolicy/LogDocMergePolicy JUnit fails 2 of 2 on main (-ea and -da) and 10.5.2. [read] The NearestFuzzyQuery lines are identical at every release tag from 7.0.0 to 10.5.2 apart from the 9.0.0 reformat, and BoostQuery has the check at every tag from 8.0.0; 8.8.2-8.11.3 are not tagged in the history clone (bracketed by the 8.0.0 and 8.11.4 runs). Same root cause, different symptom: 7.0.0-7.7.3 return a negative boost and score without an exception [exec]. Not affected: 6.x and earlier (API absent). Not fixed upstream: the file's last upstream change is a7704f5242d (2025-06-18) and upstream main still has the numDocs line (the intended-behaviour check, the prior-report record, 2026-10-26)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-393.html",
   "repro": "repro/LFV-393/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-559",
   "priority": "low",
   "priority_rank": 605,
   "novelty": "new",
   "withheld": false,
   "area": "queries / MoreLikeThis boosted query construction (MoreLikeThis.createQuery boost normalisation)",
   "title": "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)",
   "summary": "You enable boosting on MoreLikeThis (setBoost(true)) with a custom TFIDFSimilarity whose idf is 0 for a term that is in every document, as the textbook idf log(N/df) is, and call like(...) on text that contains that term and a rarer one. You expect a query with finite, non-negative boosts: the same call works with setBoost(false), and BoostQuery accepts a boost of 0. Instead createQuery divides each term's score by the first score popped from its ascending queue, which is the lowest selected score (0 here), so the zero-score term's boost is 0/0 = NaN and like() throws IllegalArgumentException 'boost must be a positive float, got NaN' on 8.0 and later, or builds the query with NaN and Infinity boosts on 4.10 to 7.x.",
   "impact_class": "crash",
   "introduced_commit": "173a44e67c7c3c1a9ffbe7259ea8b45f1f53b015 (trunk, svn r1609474; the line main descends from, shipped from 6.0.0 on) and its branch_4x backport 1427d574d3dae460d638b8d6584116baf4756214 (svn r1609493, shipped in 4.10.0 and 5.x): LUCENE-5795 'More Like This: ensures selection of best terms is indeed O(n)' (now apache/lucene#6857; a JIRA patch committed by s1monw; SVN era, no pull request; CHANGES 4.10.0 'Optimizations') [read]. It flipped the term queue from highest-first (FreqQ.lessThan 'fa > fb') to ascending ('a.score < b.score') but kept createQuery's 'first popped term = bestScore' normaliser, so the divisor became the lowest selected score; the issue thread (9 comments) never mentions boosts. Symptom change: LUCENE-7996 (a8a63464e7da, 2017-12-06, first released in 8.0.0) made the BoostQuery constructor reject non-finite boosts, so the NaN became an exception. Later edits kept the arithmetic: LUCENE-6590 (962313b83ba / fb2a8aaac40, 5.4.0, setBoost -> BoostQuery) and #14761 (a7704f5242d, 2025-06-18, main only, FreqQ -> PriorityQueue.usingComparator, same ascending order)",
   "introduced_date": "2014-07-10",
   "first_affected_version": "4.10.0 [exec]; IllegalArgumentException from 8.0.0 [exec] (first release with the LUCENE-7996 BoostQuery check). Caveat: when every selected term scores 0, 4.9.1 already gave 0/0 [exec]; LUCENE-5795 widened that to any selection containing a zero-score term",
   "affected_versions": "every release from 4.10.0 through 10.6.0 and main ea57360912ed [exec]; not affected for a mixed zero/positive selection: 4.9.1 [exec], which still fails for an all-zero selection [exec]; not fixed upstream [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-559.html",
   "repro": "repro/LFV-559/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-263",
   "priority": "low",
   "priority_rank": 606,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / analyzing infix suggester (AnalyzingInfixSuggester NRT add/update/refresh after build(); inherited unchanged by BlendedInfixSuggester [read])",
   "title": "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",
   "summary": "You build an AnalyzingInfixSuggester with the default closeIndexWriterOnBuild=true, add() a suggestion and call refresh(), and you expect the addition to become visible, as the add()/update() javadoc says, or at worst refresh() to be the no-op its own comment describes. The first add() after build() runs ensureOpen(), which assigns the writer field before it installs the SearcherManager opened on that writer, and refresh() (no lock) reads writer != null as 'the current manager is live', so in that gap it refreshes build()'s old manager, whose writer is closed, and throws AlreadyClosedException 'this IndexWriter is closed'. The gap is transient when refresh() runs on another thread during that first add() (or, contested, during a rebuild), and permanent after one IOException while ensureOpen() opens the manager: writer stays set, no later add() repairs it, and every refresh() fails until build() or a reopen.",
   "impact_class": "wrong error",
   "introduced_commit": "f9a0693bf98a4000b6568e7c63f3e303118470bd (sarowe, 2016-11-16, LUCENE-7564 / #8615 'AnalyzingInfixSuggester should close its IndexWriter by default at the end of build()', a JIRA patch with no pull request; branch_6x backport 4fedb640ab66920ea11c26ad520639912c95ff2c, the commit in 6.4.0) [exec]. It made build() close its writer by default while leaving the SearcherManager opened on that writer installed, added refresh()'s 'writer != null' gate, and so made the first add() after build() reopen a writer through ensureOpen(). The writer-before-SearcherManager order and the missing rollback in ensureOpen() are older (LUCENE-5889 / #6951, 4a485d68771 on trunk and e4731cf8a36, first released in 5.0.0) but could not reach a closed writer before 6.4.0. The rebuild-path symptom (AlreadyClosedException from refresh() during build(), instead of IllegalStateException 'suggester was not built') dates from 5015dc6dbb89a2d3f9c2cd0eb1674f6f146d09b4 (hossman, 2022-04-08, LUCENE-10292 / #11328; branch_9x b11b0714297ab5f8005aa01001824acc6ef488e7, 9.2.0), which keeps the old manager installed during build()",
   "introduced_date": "2016-11-16 (LUCENE-7564: the add path and the single-threaded I/O-error path); 2022-04-08 (LUCENE-10292: the AlreadyClosedException form of the contested rebuild path)",
   "first_affected_version": "6.4.0 [exec]; the rebuild-path AlreadyClosedException first appears in 9.2.0 [exec] (6.3.0 to 9.1.0 fail a refresh() during build() with IllegalStateException 'suggester was not built' instead)",
   "affected_versions": "6.4.0 through 10.6.0 and main ea57360912ed; not fixed upstream as of 2026-10-26 [exec]. Not affected: 6.3.0 and older [exec]. Caveats: releases before 10.x were run on JDK 25 with API ports of the probe; unreleased maintenance branches were not checked; BlendedInfixSuggester was not executed",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-263.html",
   "repro": "repro/LFV-263/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-769",
   "priority": "low",
   "priority_rank": 607,
   "novelty": "new",
   "withheld": false,
   "area": "monitor / QueryIndex term-filter map (searcher refresh vs concurrent match, writable and read-only Monitor)",
   "title": "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",
   "summary": "You share one Monitor between threads: some threads call Monitor.match on documents while another registers new queries, and each register commits and opens a new query-index searcher, which the Monitor's design for searches during commits allows. You expect every match of a valid document to return its matching queries. Instead, when the internal map from searcher to term filter (a plain java.util.HashMap) grows, a concurrent match can look up its own searcher's entry and get null, and Monitor.match throws NullPointerException from TermFilteredPresearcher.buildQuery; the read-only Monitor fails the same way while its refresh runs.",
   "impact_class": "crash",
   "introduced_commit": "251dbe7cea8126cb7ecadc921ba444c63d06c618 (main, 2019-06-13, 'LUCENE-8766: Add monitor subproject', by GitHub romseygeek), with the branch_8x twin b8773d13ad8e249a045862249bf476c30a444461 (same message and date); LUCENE-8766 is GitHub #9811, reviewed on apache/lucene-solr#648, which was closed unmerged because the code was committed directly. Its QueryIndex already had the whole race: the plain HashMap (QueryIndex.java:88), the put and the addClosedListener(termFilters::remove) in the SearcherFactory (:146-147), and the unlocked get in search (:279), with commit() holding the purge read lock only in shared mode around maybeRefresh(). The map came with the code donated from the Luwak library (Luwak commit f2f3868f54d1, 2015-12-28, 'Move QueryTermFilters into QueryIndex'). LUCENE-10422 / #679 (be9917895645 on main, 72cf36a2b8d8 on branch_9x, first released in 9.2.0) moved the put and remove into TermsHashBuilder and gave the new read-only Monitor the same map: a second trigger path, not the introduction. [read]. Latent since the module was added, not a regression.",
   "introduced_date": "2019-06-13 (251dbe7cea8 on main and b8773d13ad8 on branch_8x); read-only path 2022-03-21 (#679)",
   "first_affected_version": "8.2.0 [exec] (the first lucene-monitor release; 8.1.1 has no monitor module, lucene-monitor 8.1.1 is not on Maven Central). Read-only Monitor path: 9.2.0 [exec] (the read-only API does not exist in 9.1.0)",
   "affected_versions": "Every release that ships lucene-monitor, 8.2.0 to 10.6.0 (10.6.0 [exec] on the release jars in the doc's tie-break checks), plus main a9779ef3c193. [exec] the finder's writable JUnit fails on 8.2.0, 8.11.4 and 9.0.0 (there with only the LuceneTestCase import changed), 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); its read-only JUnit fails on 9.2.0, 9.12.3, 10.5.2 and main; the independent reproduction's JUnit fails on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's replays fail on main (-ea and -da) and 10.5.2; 8.2.0 with the ConcurrentHashMap fix shadowed passes 200 rounds. [read] the same plain HashMap, put, closed-listener remove and unlocked get at every release tag 8.2.0-8.8.1 and 9.0.0-10.5.2 in the history clone (48 tags); the released 8.8.2-8.11.4 jars construct termFilters as java.util.HashMap (javap). Not affected: 8.1.1 and earlier (no monitor module); the read-only path does not exist before 9.2.0. Not fixed upstream: on upstream main f7bcc0abd816 (2026-10-27) QueryIndex, TermsHashBuilder, WritableQueryIndex and ReadonlyQueryIndex are byte-identical to a9779ef3c193, branch_10x 657014b3c579 and branch_10_6 4ae946e5a9b9 keep the plain HashMap, and no open PR changes the map. Each version was run once with a latch amplifier, so its failed/total match counts measure neither field frequency nor differences between versions. Not executed: x86; 8.3.0-8.11.3, 9.1.0 (writable), 9.3.0-9.12.2 and 10.1.0-10.5.1 (by reading only).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-769.html",
   "repro": "repro/LFV-769/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-399",
   "priority": "low",
   "priority_rank": 608,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / analyzing suggester (AnalyzingSuggester.build payload check, inherited by FuzzySuggester)",
   "title": "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",
   "summary": "You build an AnalyzingSuggester or FuzzySuggester with payloads from your own InputIterator whose surface forms are BytesRef slices of a larger byte array, for example \"ab\" at offset 1 of {0x1F, 'a', 'b'}, and expect it to behave exactly as for compact copies of the same bytes. Instead build() looks for the reserved separator U+001F in bytes[0, length) of the backing array, ignoring the slice's offset, while two lines later it writes the real slice: the valid slice \"ab\" is rejected with IllegalArgumentException 'surface form cannot contain unit separator character U+001F', and \"a<U+001F>b\" at offset 3 of {'x','x','x','a',0x1F,'b'}, whose compact copy is rejected, is accepted. The accepted entry is then split at the wrong place: without EXACT_FIRST, lookup(\"a\") returns key \"a\" with payload \"b<U+001F>p\" instead of payload \"p\"; with the default EXACT_FIRST it returns nothing for that entry with -da and throws AssertionError with -ea.",
   "impact_class": "crash",
   "introduced_commit": "234fa47dba438452a9952f748208ce8da6eea252 (LUCENE-4820 'add optional payload to Analyzing/FuzzySuggester', by mikemccand; trunk svn r1456095, 2013-03-13; branch_4x backport d11bc054c4e2f7239ddc74db3aa88722708af79f, svn r1456098, the same day, which is the commit the 4.x and 5.x release tags contain; no pull request, Subversion era; migrated issue #5885) [read: git log -L on the loop lists only this commit and the google-java-format reformat 2cbf261032d (LUCENE-9570, 2021-01-05); git log -G 'surfaceForm\\.bytes\\[' on the file finds only this commit]. The same commit added the payload API, PAYLOAD_SEP and the check, and its own lookup-side split honours the offset; the offset-aware write of the surface form predates it (LUCENE-3842, f2f91bae46c, 2012-09-28). A before/after run of the commit is impossible because it introduced the API; substitutes [exec]: a no-payload build of the same slice passes on 4.2.0, 4.2.1 and 4.3.0, and the 4.3.0 AnalyzingSuggester source with only the one-line offset fix makes the 4.3.0 run pass",
   "introduced_date": "2013-03-13",
   "first_affected_version": "4.3.0 [exec] (released 2013-05-06; the first release with suggester payloads); 4.2.0 and 4.2.1 lack the payload API, so the payload repro does not compile there [exec], and their no-payload build of the same slice works [exec]",
   "affected_versions": "every release from 4.3.0 through 10.6.0 (10.6.0 by reading) and main ea57360912ed; not fixed on upstream main or branch_10_6 as of 2026-10-26 [exec] [read]. Caveats: releases before 9.1.0 ran API ports of the scenario (main() programs for 4.3-4.5, 4.6-5.5 and 6.0+ API generations, the canonical JUnit with pre-9.1 test-framework imports on 8.11.4 and 9.0.0), all on JDK 25; versions between those listed were checked by tag scan only; FuzzySuggester inherits build() unchanged (read at 4.3.0 and main) and was executed on main, 10.5.2 and 9.12.3 only; 10.6.0 was released 2026-10-29 and its branch has the unchanged line (not executed)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-399.html",
   "repro": "repro/LFV-399/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-600",
   "priority": "low",
   "priority_rank": 609,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / FreeTextSuggester (n-gram model joined with an in-band separator byte; build-side separator check)",
   "title": "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)",
   "summary": "You build a FreeTextSuggester with the default bigram model and separator U+001E over the single entry 'foo\\u001ebar' (the upstream test input 'foo\\u001ebar baz' without its neighbour 'baz'), using an analyzer that keeps it as one token such as UnicodeWhitespaceAnalyzer, and expect build() to throw IllegalArgumentException, as the constructor javadoc promises and as it does for 'foo\\u001ebar baz'. Instead build() succeeds, because it only rejects an indexed shingle whose separator count implies more than grams words, so the token is stored as if it were the bigram (foo, bar) with no unigram 'foo'. A later lookup('foo ') then fails inside the suggester with AssertionError at FreeTextSuggester.java:576 (-ea) or NullPointerException in decodeWeight (-da), and lookup('f') returns the token itself with a wrong score.",
   "impact_class": "wrong error",
   "introduced_commit": "b50a2edbb2389797a7354775414052df91b108f6 (trunk, svn r1528517) and its branch_4x backport 9494be7ec2ae84e88b6fc07046c35cac15e790d2 (svn r1528521, the commit 4.6.0 contains): LUCENE-5214 'Add new FreeTextSuggester, to handle \"long tail\" suggestions' (migrated issue apache/lucene#6278; Subversion era, no pull request; by GitHub mikemccand), which added in one change the 4-arg constructor javadoc promise, the DEFAULT_SEPARATOR javadoc, the build-side check on shingled terms read back from a temporary index, countGrams, the exact per-token lookup-side check, the lookup assert and testIllegalByteDuringBuild [read]. Original defect, not a regression. The introducing tree itself was not built (2013 ant build); exec at release granularity: 4.5.1 has no FreeTextSuggester (compile error), 4.6.0 reproduces 4/4 with -ea and -da",
   "introduced_date": "2013-10-02",
   "first_affected_version": "4.6.0 [exec], the first release with FreeTextSuggester; 4.5.1 and older do not have the class [exec]",
   "affected_versions": "every release from 4.6.0 through 10.5.2 (121 releases), 10.6.0 [exec] and main a9779ef3c193; not fixed on upstream main a95c754ee003, branch_10x 1309534296e3 or branch_10_6 2763db11b0a7 (local clone, read 2026-10-26). [exec] 4/4 contract cases fail on 4.6.0 (-ea and -da), 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da); with the candidate fix shadowed on main all four inputs are rejected. [exec] the finder's JUnit fails 4/4 on main (-ea, -da), 10.5.2 and 9.12.3; the independent reproduction's fails 4/6 on main, 10.5.2 and 9.12.3 (-ea and -da; its 2 controls pass); the intended-behaviour check's probe fails 2/7 on main (-ea, -da), 10.5.2 and 9.12.3 (its 5 controls pass). [read] the check and countGrams are text-identical after whitespace normalisation in all 112 release tags of the history clone that contain the file; 8.8.2 to 8.11.3 are not tagged there and are inferred (bracketed by 8.8.1, read, and 8.11.4, executed). Releases were run on JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-600.html",
   "repro": "repro/LFV-600/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-431",
   "priority": "low",
   "priority_rank": 610,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / analyzing suggester (AnalyzingSuggester.build and getCount, inherited by FuzzySuggester)",
   "title": "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",
   "summary": "You build an AnalyzingSuggester or FuzzySuggester from the two entries 'fast car' and 'red car' with an analyzer whose synonym rule maps fast to {fast, quick}, and you expect getCount() to return 2, because Lookup#getCount is documented as 'the number of entries the lookup was built with'. It returns 3: build() increments its counter once for every analyzed path of an entry ('fast car' and 'quick car' here), not once per entry, so each entry counts as often as its token graph has paths (8 for the single entry 'wifi wifi wifi' with one stacked synonym), and store() and load() keep the inflated number. Lookups are correct, and analyzers that produce no token graph give the right count.",
   "impact_class": "minor",
   "introduced_commit": "3d8bfad40b0217a9a2faa193e3086e876caab041 (trunk, svn r1689192) and its branch_5x backport 9a3ec6ce7778e8b6cf23f99e4524827b12263baf (svn r1689193), the one in the first affected release: LUCENE-6365 'Optimized iteration of finite strings' (migrated issue apache/lucene#7425; Subversion era, reviewed as JIRA patches, no GitHub PR; committed by mikemccand; the loop-header increment is already in the contributor patch FiniteStrings_noreuse.patch of 2015-07-03) [read]. No commit-level bisect. Regression: Lookup#getCount was added by LUCENE-5404 (apache/lucene#6467; b5926da2d67 on trunk, fdf4595051a on branch_4x, 2014-02-07, first released in 4.7.0), which counted once per entry; LUCENE-10292 (5015dc6dbb8, apache/lucene#11328) later renamed the counter to newCount and kept the per-path increment",
   "introduced_date": "2015-07-04 (3d8bfad40b0 on trunk and 9a3ec6ce777 on branch_5x; first release 5.3.0, 2015-08-20)",
   "first_affected_version": "5.3.0 [exec]; 5.2.1 is the last unaffected release [exec]",
   "affected_versions": "every release from 5.3.0 to 10.5.2 (103 releases: 5.3.0-5.5.5, 6.0.0-6.6.6, 7.0.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2) and main ea57360912ed [exec]; not affected: 4.7.0-4.10.4 (never received LUCENE-6365) and 5.0.0-5.2.1 [exec]; 4.6.1 and earlier have no getCount() [exec]; upstream main cf398bfb142c and branch_10x still have the per-path increment [read]; other unreleased maintenance branches not checked; not fixed anywhere. Caveats: old releases ran on JDK 25; the portable repro uses a hand-written posInc=0 stacking TokenFilter because SynonymGraphFilter exists only from 6.4",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-431.html",
   "repro": "repro/LFV-431/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-296",
   "priority": "low",
   "priority_rank": 611,
   "novelty": "new",
   "withheld": false,
   "area": "core / index: SegmentOrder (query-time segment re-ordering) and leaf core cache helpers",
   "title": "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)",
   "summary": "You call SegmentOrder.fromSort(new Sort(new SortField(\"f\", SortField.Type.LONG, true))).reorder(reader) to visit the segments with the highest f values first, on a reader whose leaves do not support caching, for example a ParallelCompositeReader over two DirectoryReaders with two segments each. You expect a re-ordered view, because reorder() accepts any IndexReader and LeafReader#getCoreCacheHelper documents null as a legal return value ('not suited for caching') that other consumers such as LRUQueryCache and QueryBitSetProducer simply skip. Instead reorder() throws NullPointerException at SegmentOrder.java:137, where the leaf comparator's memo calls reader.getCoreCacheHelper().getKey() without a null check.",
   "impact_class": "crash",
   "introduced_commit": "d455fefc6b63f90216c938fda061286918fee37e on main and its branch_10x backport 7b71560832c6, 'Add SegmentOrder utility class for per-query segment re-ordering', apache/lucene#15591 by romseygeek [read]. Not a regression: the unguarded key has been there since the class was created; the contract it misses is older (LeafReader#getCoreCacheHelper may return null and ParallelLeafReader returns null over more than one reader since LUCENE-7410, df6f8307230, 2017, 7.0.0)",
   "introduced_date": "2026-01-23 (#15591 merged; backport committed the same day)",
   "first_affected_version": "10.4.0 [exec] (first release with SegmentOrder; 10.3.2 and 9.12.3 give compile_error because the class is absent)",
   "affected_versions": "10.4.0, 10.5.0, 10.5.1, 10.5.2 and main ea57360912ed [exec] (the finder's JUnit fails 1 of 1 on each with the same NPE at SegmentOrder.java:137; 10.5.2 and main also with -da; the independent reproduction's JUnit fails 3 of 4 on main -ea/-da, 10.5.2 and 10.4.0); 10.6.0 (released 2026-10-29; branch_10_6 RC1 4ae946e5a9b) [exec] and branch_10x 657014b3c579 [read]; main 645d4fe14a2 [exec]. Not affected: every release up to 10.3.2 and all 9.x (API absent). Not fixed upstream: line 137 is unchanged on upstream main 645d4fe14a2 (2026-10-29), branch_10x 657014b3c579 and branch_10_6, and no open PR touches SegmentOrder.java [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-296.html",
   "repro": "repro/LFV-296/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1187",
   "priority": "low",
   "priority_rank": 612,
   "novelty": "new",
   "withheld": false,
   "area": "core / index: SegmentOrder (query-time segment re-ordering helper)",
   "title": "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)",
   "summary": "You build one SegmentOrder with SegmentOrder.fromSort(new Sort(new SortField(\"f\", SortField.Type.LONG, true))) and share it between searches, as you would a Sort or a Query, so two threads call order.reorder(reader) on the same freshly opened reader at the same time. You expect each call to return a re-ordered view: the strategy is built from an immutable Sort, its API exposes no state, and its javadoc says nothing about threads. Instead every reorder() of that strategy sorts the leaves with one comparator whose per-segment memo is a plain HashMap filled with containsKey/put/get and no lock, so a concurrent put or resize can make Map.get return null and reorder() throws NullPointerException 'Cannot invoke \"java.lang.Long.longValue()\" because the return value of \"java.util.Map.get(Object)\" is null' at SegmentOrder.java:141.",
   "impact_class": "minor",
   "introduced_commit": "d455fefc6b63f90216c938fda061286918fee37e on main and its branch_10x copy 7b71560832c6f81cc6b7f91f536b6cf618dbbd65: apache/lucene#15591 'Add SegmentOrder utility class for per-query segment re-ordering' (author @romseygeek; CHANGES.txt credits Alan Woodward). It created SegmentOrder, whose numericSorter() builds one NumericFieldReaderContextComparator, with a HashMap memo keyed by the leaf's core cache key, outside reorder(), so every reorder() of the returned strategy sorts with that one instance [read] [exec]. Design history: the closed, unmerged predecessor #15436 built a fresh comparator per search with a memo keyed by LeafReaderContext.ord; #15591's first commit 91bbb0f9d68 moved the comparator up into numericSorter and switched to the core cache key; no review comment on either PR discusses threads, sharing or the memo's lifetime. Not a regression: the shared memo has been there since the class was created.",
   "introduced_date": "2026-01-23 (author and commit date of d455fefc6b6, 2026-01-23T10:34:54Z; branch_10x copy 7b71560832c committed 2026-01-23T10:43:40Z; PR #15591 merged 2026-01-23T10:34:54Z)",
   "first_affected_version": "10.4.0 [exec] [read]",
   "affected_versions": "10.4.0, 10.5.0, 10.5.1, 10.5.2, 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT) [read] [exec]. Not affected: 10.3.2 and earlier and all of 9.x (API absent; compile error on 10.3.2 and 9.12.3 [exec]). Not fixed upstream: upstream main 1c2072f0284 (2026-11-02) has the same SegmentOrder.java, branch_10_6 has the same code, the newest commit on the file is still 1593f87193b (author date 2026-07-14), and no open PR touches SegmentOrder.java or TestSegmentReordering.java [read]. Not new in 10.6. The counts are hit rates of a race that cannot be made deterministic (they vary with host load), not differences between versions. All runs used JDK 25.0.3 on one aarch64 Linux host.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1187.html",
   "repro": "repro/LFV-1187/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-438",
   "priority": "low",
   "priority_rank": 613,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter passage selection (FieldHighlighter.highlightOffsetsEnums passage-queue sizing; maxPassages is never range-checked by UnifiedHighlighter.highlightFieldsAsObjects)",
   "title": "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)",
   "summary": "You ask the UnifiedHighlighter for at most Integer.MAX_VALUE passages, meaning 'no limit', and expect the same snippet that 1000 or Integer.MAX_VALUE - 1 gives (or, if the value is not allowed, an IllegalArgumentException that says so). Instead, for every document that has a match, FieldHighlighter.highlightOffsetsEnums sizes its passage queue with Math.min(64, maxPassages + 1); the + 1 wraps to Integer.MIN_VALUE, Math.min returns it, and the java.util.PriorityQueue constructor throws an IllegalArgumentException with no message. With per-field counts such as {1, MAX_VALUE} the field that asked for one passage loses its snippet too, because the whole call throws.",
   "impact_class": "wrong error",
   "introduced_commit": "722e82712435ecf46c9868137d885484152f749b on master and its branch_6x twin 4b6794368df373df1f68ccf27f7556914efeb95e (LUCENE-7438 'New UnifiedHighlighter' by dsmiley, 2016-10-04; JIRA issue now GitHub #8490, reviewed in apache/lucene-solr#79, which was closed without a GitHub merge; the commits were made directly; FieldHighlighter.java blob 7c8f048d171e is identical in both) [read]. The first FieldHighlighter.highlightOffsetsEnums already wrote 'new PriorityQueue<>(Math.min(64, maxPassages + 1), ...)'. Later commits did not change the expression: LUCENE-7559 (c51e89014ac / 23b8bb66935, 6.4.0) changed only the comparator body, LUCENE-8145 (9422609a5d4 / aa5c3a5c222, 7.3.0) added an early return for documents without a match before the queue (narrowing the bug), and LUCENE-9570 (6faa4f98e04, 9.0.0) only reformatted it, which is why plain git blame on main names that commit; the predecessor PostingsHighlighter sized the queue new PriorityQueue<>(n, ...) without a cap and failed for both Integer.MAX_VALUE and Integer.MAX_VALUE - 1 with OutOfMemoryError [exec], so the wrap is new with the UnifiedHighlighter's cap; not a regression within the UnifiedHighlighter",
   "introduced_date": "2016-10-04",
   "first_affected_version": "6.3.0 [exec] (first release with the UnifiedHighlighter, from branch_6x commit 4b6794368df; 7.0.0 is the first release of the master commit and is affected [exec]); 6.2.1 has no org.apache.lucene.search.uhighlight package (the probe does not compile there) [exec]",
   "affected_versions": "every release that has the UnifiedHighlighter: all 87 Maven Central releases from 6.3.0 to 10.5.2 (13 in 6.x, 14 in 7.x, 27 in 8.x including 8.8.2-8.11.4, which have no tag in the history clone and are covered by execution only, 21 in 9.x, 12 in 10.x) and main ea57360912ed [exec]; scope differs by release [exec]: in 6.3.0-7.2.1 every highlighted document with non-empty content throws, with or without a match, and from 7.3.0 on (LUCENE-8145) only documents with at least one match throw; not affected: releases up to 6.2.1, which have no UnifiedHighlighter; not fixed upstream (FieldHighlighter.java:143 unchanged on upstream main cf398bfb142c and on branch_10x as of 2026-10-26, no open PR touches FieldHighlighter.java) [read]; release branches after 10.5.2 other than branch_10x were not checked",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-438.html",
   "repro": "repro/LFV-438/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-964",
   "priority": "low",
   "priority_rank": 614,
   "novelty": "new",
   "withheld": false,
   "area": "grouping / GroupingSearch (term, function, cached two-pass and doc-block grouping) x the first-pass, TopGroups and block collector managers",
   "title": "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)",
   "summary": "You call GroupingSearch.search(searcher, query, 0, Integer.MAX_VALUE) or setGroupDocsLimit(Integer.MAX_VALUE) to get every group, or every document of each group, and expect the same TopGroups as with a limit of maxDoc, the way IndexSearcher.search(query, Integer.MAX_VALUE) returns every hit. Instead the search throws: with offset 0 a NegativeArraySizeException -2147483648, an OutOfMemoryError 'Requested array size exceeds VM limit' or a queue-size IllegalArgumentException, and with offset 1 an IllegalArgumentException such as 'topNGroups must be >= 1 (got -2147483648)' or 'numHits must be > 0'. GroupingSearch hands the limits on uncapped to collectors that add offset + limit in int and pre-size their queues by the limit; nothing is ever returned wrong.",
   "impact_class": "wrong error",
   "introduced_commit": "89b55566d8392657be86e1441a329373e9132257 (2012-03-22, 'LUCENE-3778: Added a grouping utility class that makes it easier to use result grouping for pure Lucene apps', by martijnvg; LUCENE-3778 is apache/lucene#4851; JIRA-patch era, no pull request; committed to trunk only, first shipped in 4.0.0): the new GroupingSearch computed 'int topN = groupOffset + groupLimit' and 'groupDocsOffset + groupDocsLimit' and passed the caller's limits on with no cap [read]. The bug was born with the class and is not a regression. The sums later moved into FirstPassGroupingCollectorManager (636e8e9f587, #15574), TopGroupsCollectorManager (e26a959e2c7, #15603) and BlockGroupingCollectorManager (d27d080d101, #15936), and GroupingSearch's term path switched to the managers in 3afffeef5a8 (#16247), all by gaobinlong in 2026, with the same effect. The first-pass pre-sizing by topNGroups + 1 dates from LUCENE-1421 (9083cedb922, 2011), a caller-sized low-level collector that is not itself the bug.",
   "introduced_date": "2012-03-22 (author and commit date of 89b55566d83)",
   "first_affected_version": "4.0.0 (released 2012-10-11) [exec]; 3.6.x is not affected because it has no GroupingSearch (LUCENE-3778 went to trunk only; 3.5.0 and 3.6.2 executed: API absent; 3.6.0/3.6.1 jar listings)",
   "affected_versions": "[exec] 4.0.0-ALPHA, 4.0.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0 and 10.5.2 fail with the follow-up's version-specific history probes (8 of 8 cases in 4.x, 4 of 4 term-grouping cases from 5.0.0 on, -da), the finder's JUnit fails 8 of 8 on 10.0.0, 10.5.2, branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193 (-ea and -da), the independent reproduction's own JUnit fails 8 of 10 (both controls pass) on main (-ea and -da), 10.5.2 and 9.12.3, and the registration check re-ran the finder's JUnit on main (-da, seed 5EED0387: 8 run, 8 failed). [read] every other point release from 4.0.0 to 10.5.2 is inferred affected: the int sums are present in every tag read and GroupingSearch's history has no capping change. The wrapped-sum message 'topNGroups must be >= 1 (got -2147483648)' for groupOffset 1 is identical in every version; the offset-0 symptoms vary with the collector internals (field-sorted groupDocsLimit = MAX_VALUE: OutOfMemoryError on 4.0.x and main, NegativeArraySizeException 4.10.4-6.6.6, PriorityQueue maxSize IllegalArgumentException 7.7.3-10.5.2). Not fixed upstream: upstream main 645d4fe14a20 (author date 2026-10-28) has no grouping commit after a9779ef3c193. All runs on Linux aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-964.html",
   "repro": "repro/LFV-964/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1004",
   "priority": "low",
   "priority_rank": 615,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / Lookup.lookup result sizing (AnalyzingInfixSuggester, WFSTCompletionLookup, FreeTextSuggester)",
   "title": "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",
   "summary": "You build an AnalyzingInfixSuggester, WFSTCompletionLookup or FreeTextSuggester from 8 entries that start with 'luc' and call lookup(\"luc\", false, Integer.MAX_VALUE) to get every suggestion; num is documented as the 'maximum number of results to return', so you expect the 8 suggestions that num = 1000 returns, which is what TSTLookup and FSTCompletionLookup give for the same call. Instead each of the three sizes its result storage by num before it knows how many entries match (AnalyzingInfixSuggester builds a TopFieldCollectorManager of num slots that, unlike IndexSearcher.search, it never caps at maxDoc; the other two call new ArrayList<>(num)), so the call throws OutOfMemoryError 'Requested array size exceeds VM limit' (on 9.12.3, 10.5.2 and the 10.6 RC, AnalyzingInfixSuggester throws IllegalArgumentException 'maxSize must be >= 0 and < 2147483631' instead). A smaller but still large num succeeds and allocates memory in proportion to num rather than to the matches: 114 MiB per lookup for AnalyzingInfixSuggester and 38 MiB for the other two at num = 10^7.",
   "impact_class": "crash",
   "introduced_commit": "No regression point: each site arrived with the class that contains it [read]. WFSTCompletionLookup: a519b630eea (trunk) and its same-day branch_3x backport d9a6ee8b125, LUCENE-3714 'add weighted FST suggester impl' (#4788; Robert Muir, CHANGES credit Mike McCandless, Dawid Weiss, Robert Muir; JIRA patch era, no pull request), with new ArrayList<LookupResult>(num). AnalyzingInfixSuggester: 63fa645aa80 (trunk), 39f54258327 (lucene_solr_4_4) and d0fe1baf093 (branch_4x), LUCENE-4845 'add AnalyzingInfixSuggester' (#5910; Michael McCandless), whose collector was sized by num from the start (FirstNDocsCollector, new int[topN], in 4.4.0-4.7.2; TopFieldCollector.create(SORT, num, ...) from LUCENE-5477, 02e3fd09eb5, 4.8.0; new TopFieldCollectorManager(SORT, num, null, 1) since #13977, bc18828fccc, 2024). FreeTextSuggester: b50a2edbb23 (trunk) and 9494be7ec2a (branch_4x), LUCENE-5214 'add FreeTextSuggester' (#6278; Michael McCandless), with new ArrayList<>(num)",
   "introduced_date": "2012-02-19 (WFSTCompletionLookup); 2013-07-15 (AnalyzingInfixSuggester); 2013-10-02 (FreeTextSuggester)",
   "first_affected_version": "3.6.0 [exec] (WFSTCompletionLookup, shipped in the contrib spellchecker jar; 3.5.0 has none of the three classes [exec]); AnalyzingInfixSuggester since 4.4.0 [exec] (4.3.1 lacks it [exec]); FreeTextSuggester since 4.6.0 [exec] (4.5.1 lacks it [exec])",
   "affected_versions": "Every release from 3.6.0 to 10.5.2, 10.6.0 (released 2026-10-29; run as its RC) and main [exec]; every release tag that contains one of the classes has its num-sized allocation without a cap [read]. Error at num = Integer.MAX_VALUE: WFSTCompletionLookup and FreeTextSuggester throw OutOfMemoryError 'Requested array size exceeds VM limit' on every version; AnalyzingInfixSuggester throws OutOfMemoryError in 4.4.0-4.7.2 (int[num]), IllegalArgumentException 'maxSize must be <= 2147483391' in 4.8.0-4.9.0 (the SOLR-5661 PriorityQueue guard), NegativeArraySizeException in 4.9.1-7.4.0, IllegalArgumentException 'maxSize must be >= 0 and < 2147483631' in 7.5.0 to 10.6.0, and OutOfMemoryError on main, where #14873 builds the sort comparators before PriorityQueue's size guard (LFV-993) [exec]. Below Integer.MAX_VALUE all three allocate in proportion to num on every version (num = 10^7 on 8 matches: 38 MiB each, 114 MiB for AnalyzingInfixSuggester since 4.8.0). Not fixed: the newest commits on the three files on upstream main are 54283150a81 (AnalyzingInfixSuggester, FreeTextSuggester; build tooling, author and committer date 2026-06-14) and 644feeb02a9 (WFSTCompletionLookup, 2024-09-17), neither touching the sizing [read]. Caveat: all runs used JDK 25.0.3 on Linux aarch64; the allocation sizes assume compressed object pointers; 10.6.0 was checked only as RC jars",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1004.html",
   "repro": "repro/LFV-1004/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1007",
   "priority": "low",
   "priority_rank": 616,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / n-gram tokenizers (NGramTokenizer.init buffer sizing, shared by EdgeNGramTokenizer; NGramTokenizerFactory and EdgeNGramTokenizerFactory pass maxGramSize through unchecked)",
   "title": "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)",
   "summary": "You build EdgeNGramTokenizer(1, Integer.MAX_VALUE) (or NGramTokenizer, or a factory with maxGramSize=2147483647) to mean 'all n-grams, no upper limit', and you expect the same tokens as with maxGram = text length, or else a clear IllegalArgumentException from the constructor, which validates maxGram and accepts it. Instead init computes the buffer sizes 2 * maxGram + 1024 and 2 * maxGram in int, which wrap to 1022 and -2, so the tokenizer gets a 1022-char read buffer and keeps its 16-char default term buffer. Texts of up to 16 chars come out right, but the first text of 17 or more chars throws ArrayIndexOutOfBoundsException 'Index 16 out of bounds for length 16' from incrementToken (from 1022 chars, an IllegalArgumentException about a buffer size the caller never passed).",
   "impact_class": "crash",
   "introduced_commit": "e021451d6c08433d2e442456b3b5925f4cdb7129 (trunk) / e6ce05111fe7c22b871fb87901d23970bc6b10b3 (branch_4x backport, the released code): LUCENE-5042 'Fix the n-gram tokenizers and filters' (Adrien Grand; JIRA issue now apache/lucene#6106; SVN era, no PR) [read] [exec]. LUCENE-5042 doubled the factor to 2 * maxGram + 1024, so the top 511 values wrap back to a small positive size, made termAtt.resizeBuffer(2 * maxGram) a no-op for maxGram >= 2^30, and made EdgeNGramTokenizer a subclass of NGramTokenizer. Not a regression of a later change.",
   "introduced_date": "2013-06-12",
   "first_affected_version": "4.4.0 [exec]; 4.3.1, the last release before it, passes [exec]",
   "affected_versions": "every release from 4.4.0 to 10.6.0 (the 10.6 RC, branch_10_6 4ae946e5a9b) and main 645d4fe14a20 [exec] [read]; in 4.4.0-5.5.5 only on the current-version path (factories with luceneMatchVersion < 4.4 used the unaffected Lucene43NGramTokenizer/Lucene43EdgeNGramTokenizer, removed in 6.0) [read]; not affected: 2.1.0-4.3.1 [read]; not fixed upstream (NGramTokenizer.java and EdgeNGramTokenizer.java last changed by 8ef6a0da568, author date 2020-12-28, reformatting only; upstream main head is 645d4fe14a20, author date 2026-10-28; no open PR changes the sizing). JDK 25.0.3 for all versions.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1007.html",
   "repro": "repro/LFV-1007/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-994",
   "priority": "low",
   "priority_rank": 617,
   "novelty": "new",
   "withheld": false,
   "area": "facet / SortedSetDocValues child queue (AbstractSortedSetDocValueFacetCounts.computeTopChildren, inherited by SortedSetDocValuesFacetCounts and ConcurrentSortedSetDocValuesFacetCounts)",
   "title": "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",
   "summary": "You index a SortedSetDocValues facet dim with three labels and call getTopChildren(Integer.MAX_VALUE, dim) to get all of them, expecting the same result as getTopChildren(1000, dim), because Facets.validateTopN accepts every topN > 0 and taxonomy facets return all three labels for exactly this call. Instead AbstractSortedSetDocValueFacetCounts.computeTopChildren builds new TopOrdAndIntQueue(topN) without capping topN at the number of labels, so PriorityQueue throws IllegalArgumentException 'maxSize must be >= 0 and < 2147483631; got: 2147483647', and getAllDims(Integer.MAX_VALUE) and getTopDims(10, Integer.MAX_VALUE) fail the same way. Below that limit the same line pre-allocates topN + 1 slots: getTopChildren(2^24, dim) over 3 labels allocates about 64 MiB to return 3 results.",
   "impact_class": "wrong error",
   "introduced_commit": "5458dbf2484f398b710ce40296d98e19969bf3c0 ('LUCENE-5339: current patch', lucene5339 feature branch, svn r1542025, Michael McCandless): the rewritten SortedSetDocValuesFacetCounts builds its child queue as 'q = new TopOrdCountQueue(topN)' (renamed TopOrdAndIntQueue by f6cd7fda747); released through the branch_4x port 7477fde1cb06 ('LUCENE-5371, LUCENE-5339: ... simplify facet APIs', svn r1555342) and the trunk merge 9d0b60388da8. Issue LUCENE-5339 'Simplify the facet module APIs' (#6403); SVN-era patches, no pull request [read]. A regression: the pre-4.7 code it replaced (SortedSetDocValuesAccumulator, LUCENE-4795, removed by 92b1e230715) returned all children without a queue when numResults covered the ordinal range, and the pre-4.7 FacetRequest javadoc documented Integer.MAX_VALUE as 'all'; in the same rewrite 189feaacb6f capped every taxonomy queue with Math.min(taxoReader.getSize(), topN) and ported the Integer.MAX_VALUE test to taxonomy only. Later moves kept the expression: LUCENE-7811 (3e425d39873, ConcurrentSortedSetDocValuesFacetCounts, 6.6.0) and LUCENE-10585 (8db1e41fc072, #915, merge into AbstractSortedSetDocValueFacetCounts, 9.3.0).",
   "introduced_date": "2013-11-14 (5458dbf2484, feature branch; author date equals commit date); 2014-01-04 (7477fde1cb06, reached branch_4x)",
   "first_affected_version": "4.7.0 (tag 2014-02-25) [exec]; last unaffected 4.6.1 [exec]; SortedSetDocValues faceting starts in 4.3.0 (4.3.0 and 4.6.0 also pass; 4.2.1 has no sortedset package)",
   "affected_versions": "every release from 4.7.0 to 10.5.2 (all 4.7.x-10.x lines), 10.6.0 (released 2026-10-29; run as its RC, branch_10_6 head 4ae946e5a9b9) and main a9779ef3c193; never fixed. [exec] follow-up history runs (release-portable main() on the core and facet jars, -da, JDK 25): 4.7.0, 4.9.0, 4.9.1, 4.10.4, 5.5.5, 6.6.0, 6.6.6, 7.4.0, 7.5.0, 7.7.3, 8.11.4, 9.1.0, 9.2.0, 9.12.3, 10.5.2, branch_10_6 and main all FAIL with the taxonomy control passing; the exception changes with core PriorityQueue (IllegalArgumentException 4.7.0-4.9.0, NegativeArraySizeException -2147483648 4.9.1-7.4.0, IllegalArgumentException 'maxSize must be >= 0 and < 2147483631' 7.5.0-main); ConcurrentSortedSetDocValuesFacetCounts is affected from 6.6.0 and getTopDims(.., topNChildren) from 9.2.0. The finder's JUnit on main (-ea, -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit on main (-ea, -da), 10.5.2 and 9.12.3; the intended-behaviour check on main and 10.5.2. [read] the releases in between: git log -S/-G shows the uncapped queue expression unchanged in every SortedSetDocValues counts class since 2013 (moves only). Upstream main 645d4fe14a20 (2026-10-28) has no change at the fix site.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-994.html",
   "repro": "repro/LFV-994/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-983",
   "priority": "low",
   "priority_rank": 618,
   "novelty": "new",
   "withheld": false,
   "area": "facet / getTopDims dimension queue (AbstractSortedSetDocValueFacetCounts and TaxonomyFacets overrides, inherited by SortedSetDocValuesFacetCounts, ConcurrentSortedSetDocValuesFacetCounts, FastTaxonomyFacetCounts, TaxonomyFacetIntAssociations and TaxonomyFacetFloatAssociations)",
   "title": "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",
   "summary": "You index two flat facet dims, call getAllDims(10) on SortedSetDocValuesFacetCounts or FastTaxonomyFacetCounts and get both dims, then call getTopDims(Integer.MAX_VALUE, 10) to ask for 'all dims' and expect the same list, because the getTopDims javadoc says results should be the same as calling getAllDims and then only using the first topNDims, and the default Facets#getTopDims caps with Math.min(topNDims, allResults.size()). Instead the optimized overrides in AbstractSortedSetDocValueFacetCounts and TaxonomyFacets build PriorityQueue.usingComparator(topNDims, ...) before they look at any dim, so the call throws IllegalArgumentException 'maxSize must be >= 0 and < 2147483631; got: 2147483647' in all five SortedSetDocValues and taxonomy implementations. Below that limit the same line pre-allocates topNDims + 1 slots: getTopDims(2^24, 10) over 2 dims allocates about 64 MiB to return 2 results.",
   "impact_class": "crash",
   "introduced_commit": "7c33f04d3746f855479da5177df8f19b6fdbbe84 ('LUCENE-10325: Add getTopDims functionality to Facets (#747)', issue #11361; branch_9x backport 77ccf2fb359e, #773) [read]: SortedSetDocValuesFacetCounts.getTopDims built new PriorityQueue<>(topNDims), while the same commit added the capped default Facets#getTopDims. The concurrent-SSDV and taxonomy overrides came with the same uncapped queue in LUCENE-10488 (issue #11524): ef43242d77a2 (#777, ConcurrentSortedSetDocValuesFacetCounts), 57f8cb2fd6bc (#779, IntTaxonomyFacets) and f0ec22616723 (#806, FloatTaxonomyFacets), branch_9x backport 87655fd015ce (#889). Written by Yuting Gan (Yuti-G), merged by Greg Miller (gsmiller), who also authored the backports. Later refactors kept the capacity: 8db1e41fc07 (#915, SSDV overrides merged into AbstractSortedSetDocValueFacetCounts), 9ba4af7b883 (#12966, taxonomy overrides merged into TaxonomyFacets) and a7704f5242d (#14761, PriorityQueue.usingComparator). Not a regression.",
   "introduced_date": "2022-03-28 (SSDV site, author date of 7c33f04d374, equal to its commit date); 2022-05-13 (concurrent-SSDV and taxonomy sites, LUCENE-10488)",
   "first_affected_version": "9.2.0 [exec]: all five classes throw for getTopDims(Integer.MAX_VALUE, 10) and allocate about 64 MiB for getTopDims(2^24, 10) over 2 dims; 9.1.0 has no Facets#getTopDims [exec]",
   "affected_versions": "every release from 9.2.0 to 10.5.2 (all 9.2.x-9.12.x and 10.x), 10.6.0 (released 2026-10-29; run as its RC, branch_10_6 head 4ae946e5a9b9) and main a9779ef3c193; never fixed. [exec] follow-up history runs (release-portable main() over the core and facet jars, -da): 9.2.0, 9.3.0, 9.10.0, 9.11.0, 9.12.3, 10.0.0, 10.5.2, branch_10_6 and main all FAIL, with the default-getTopDims control passing on each; the finder's JUnit on main (-ea, -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit on main (-ea, -da), 10.5.2 (-ea, -da), 9.12.3 and 9.2.0; the intended-behaviour check on 10.5.2. [read] the releases in between: git grep on every 9.x/10.x release tag finds the topNDims-sized dim queue at each override site (4 sites in 9.2.0, 3 in 9.3.0-9.10.0, 2 from 9.11.0 on) and no Math.min(topNDims ...) in the facet module except the default Facets#getTopDims. Upstream main 645d4fe14a (2026-10-28) has no change at the fix sites. JDK 25.0.3, aarch64; plain Java arithmetic.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-983.html",
   "repro": "repro/LFV-983/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-995",
   "priority": "low",
   "priority_rank": 619,
   "novelty": "new",
   "withheld": false,
   "area": "search / top-n rescoring and geo nearest search (queue sizing: RescoreTopNQuery.rewrite; LatLonPoint.nearest -> NearestNeighbor)",
   "title": "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",
   "summary": "You search with new RescoreTopNQuery(query, source, Integer.MAX_VALUE), or call LatLonPoint.nearest(searcher, field, lat, lon, Integer.MAX_VALUE), to get every candidate, and expect them all back, as n = 1000 (or 100) gives on a 9-document index and as nearest's documented equivalent, a MatchAllDocsQuery search sorted by distance, gives for Integer.MAX_VALUE. Instead both build a priority queue of n + 1 slots before looking at the index: Integer.MAX_VALUE throws IllegalArgumentException('maxSize must be >= 0 and < 2147483631') from inside the search, and a large n below that throws OutOfMemoryError (n = 3*10^8 under a 1 GB heap). IndexSearcher.search has capped the same request at maxDoc since LUCENE-2119, as Michael McCandless proposed there; the analogous fix caps RescoreTopNQuery's queue at maxDoc and nearest's at the number of indexed points (not maxDoc, because nearest returns a multi-valued document once per point).",
   "impact_class": "crash",
   "introduced_commit": "fcd98fd3370b on main (#897, LUCENE-10266 'Move nearest-neighbor search on points to core', Rushabh Shah / shahrs87, merged 2022-06-13, main only, first released in 10.0.0) moved LatLonPoint.nearest and its n-sized hit queue into core unchanged; the queue code was written in f6c7fc7a2658 (LUCENE-7069 / #8125, Mike McCandless, 2016-04-14, sandbox, out of scope), and ad86feca097 (2016-04-15) added the n >= 1 check and the equivalence javadoc. RescoreTopNQuery.rewrite's 'new HitQueue(n, false)' came with 3404496b3d77 (#14009, Dzung Bui / dungba88, author date 2025-06-28; branch_10x backport 4fcb6d6d50d, #14860, merged 2025-06-29) [read]. Neither site is a regression: each sized its queue from n from its first commit. #16154 (f5622b061ce, Prithvi S / iprithv, 2026-06-01, first in 10.5.0) only changed nearest's n = Integer.MAX_VALUE failure from OutOfMemoryError to IllegalArgumentException.",
   "introduced_date": "2022-06-13 (#897, core LatLonPoint.nearest); 2025-06-28 (#14009, RescoreTopNQuery; backport #14860 merged 2025-06-29); the sandbox queue code 2016-04-14 (LUCENE-7069)",
   "first_affected_version": "10.0.0 [exec] for LatLonPoint.nearest (first release with #897; 9.12.3 has no core nearest [exec]); 10.3.0 [exec] for RescoreTopNQuery (10.2.2 has no such class [exec])",
   "affected_versions": "LatLonPoint.nearest: 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2, 10.6.0 (released 2026-10-29; run as its RC, branch_10_6 4ae946e5a9b) and main a9779ef3c193 [exec]; RescoreTopNQuery: 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2, 10.6.0 and main [exec]. At n = Integer.MAX_VALUE nearest throws OutOfMemoryError 'Requested array size exceeds VM limit' up to 10.4.0 and IllegalArgumentException from 10.5.0 (#16154); n = 2147483630 gives OutOfMemoryError 'Java heap space' in every affected release. The out-of-scope sandbox predecessor of nearest (6.1.0-9.12.3) has the same queue [exec]. Not fixed upstream: upstream main 645d4fe14a20 still has both lines (2026-10-29) [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-995.html",
   "repro": "repro/LFV-995/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1005",
   "priority": "low",
   "priority_rank": 620,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / matchhighlight passage selection (PassageSelector.pickBest passage-queue sizing; used by MatchHighlighter through FieldValueHighlighters.highlighted, which passes maxPassages through unchecked)",
   "title": "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",
   "summary": "You call PassageSelector.pickBest on a short text with two matches (or MatchHighlighter with FieldValueHighlighters.highlighted) and pass maxPassages = Integer.MAX_VALUE to mean 'all passages', and you expect the same two passages that maxPassages = 10 returns, because maxPassages only caps the result (the method clamps its result to it) and there can never be more passages than matches. Instead pickBest builds its priority queue with Math.max(16, maxPassages) slots before it reads any match, so the call throws IllegalArgumentException 'maxSize must be >= 0 and < 2147483631; got: 2147483647'. A smaller but still large maxPassages succeeds and allocates memory in proportion to maxPassages rather than to the matches: about 64 MiB per call at 2^24.",
   "impact_class": "wrong error",
   "introduced_commit": "150a8dacb59712c731e66db1a56068326a0439f4 (LUCENE-9463 'Query match region retrieval component, passage scoring and formatting', apache/lucene-solr#1750, Dawid Weiss, reviewed earlier by Alan Woodward in apache/lucene-solr#1721; JIRA issue now apache/lucene#10503) [read]. The class was created with 'new PriorityQueue<>(maxPassages)' built before any marker is read. #11990 (72ff140f5a6 on main, 07866ec2674 on branch_9x, Alan Woodward, 2022-12-01, first released in 9.5.0) changed the size to Math.max(16, maxPassages) and added the result clamp, which leaves the size unchanged for maxPassages >= 16; #14705, #14817 and #16255 (main only) kept the size argument. Not a regression.",
   "introduced_date": "2020-08-14",
   "first_affected_version": "9.0.0 [exec] (the first release with matchhighlight); 8.6.1 and 8.11.4 have no PassageSelector [exec]",
   "affected_versions": "every release that ships matchhighlight, 9.0.0 to 10.5.2, 10.6.0 (released 2026-10-29; run as its RC, branch_10_6 4ae946e5a9b) and main 645d4fe14a20 [exec] [read]; the same IllegalArgumentException on every affected version, from PassageSelector.pickBest:92 in 9.0.0-9.4.2 and :96 from 9.5.0 on; not affected: 8.x (no matchhighlight) [exec]; not fixed upstream (PassageSelector.java:93 unchanged on upstream main 645d4fe14a20, author date 2026-10-28; the newest commit on the file is 54283150a81, 2026-06-14, unrelated; no open PR touches it). JDK 25.0.3 for all versions.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1005.html",
   "repro": "repro/LFV-1005/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-265",
   "priority": "low",
   "priority_rank": 621,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter passage selection (FieldHighlighter.maybeAddPassage; maxPassages is never range-checked by UnifiedHighlighter.highlightFieldsAsObjects)",
   "title": "UnifiedHighlighter with maxPassages=0 throws NullPointerException for every document that has a match (a per-field 0 makes the whole multi-field call fail)",
   "summary": "You call UnifiedHighlighter.highlight(field, query, topDocs, 0), or highlightFields with a per-field count of 0, and expect what the same call already does for a document without a match: a null snippet (or, if 0 is not allowed, an IllegalArgumentException that says so). Instead, for every document that has a match in the field, FieldHighlighter.maybeAddPassage tests passageQueue.size() == maxPassages (0 == 0) while the passage queue is still empty and then calls passageQueue.peek().getScore(), so a NullPointerException escapes the call. With {title: 0, body: 1} the body field, which asked for one passage, loses its snippet too, because the whole call throws.",
   "impact_class": "wrong error",
   "introduced_commit": "722e82712435ecf46c9868137d885484152f749b on master and its branch_6x twin 4b6794368df373df1f68ccf27f7556914efeb95e (LUCENE-7438 'New UnifiedHighlighter' by dsmiley, 2016-10-04; JIRA issue now GitHub #8490, reviewed in apache/lucene-solr#79, which was closed without a GitHub merge; the commits were made directly) [read]. The first version of FieldHighlighter.highlightOffsetsEnums already sized the queue Math.min(64, maxPassages + 1) and had the unguarded check 'passageQueue.size() == maxPassages && passage.score < passageQueue.peek().score'. Later commits only renamed or moved it: LUCENE-7559 (c51e89014ac / 23b8bb66935, 6.4.0) switched to getScore(), LUCENE-8145 (9422609a5d4 / aa5c3a5c222, 7.3.0) moved the check unchanged into maybeAddPassage (git blame on main names this commit for line 212), and LUCENE-9570 (6faa4f98e04) reformatted it. The predecessor PostingsHighlighter had the same unguarded check, but its new PriorityQueue<>(n, ...) threw the JDK's message-less IllegalArgumentException for n = 0 first [exec], so the NullPointerException is new with the UnifiedHighlighter's queue sizing; not a regression within the UnifiedHighlighter",
   "introduced_date": "2016-10-04",
   "first_affected_version": "6.3.0 [exec] (first release with the UnifiedHighlighter, from branch_6x commit 4b6794368df; 7.0.0 is the first release of the master commit and is affected [exec]); 6.2.1 has no org.apache.lucene.search.uhighlight package (the probe does not compile there) [exec]",
   "affected_versions": "every release that has the UnifiedHighlighter: all 87 Maven Central releases from 6.3.0 to 10.5.2 (13 in 6.x, 14 in 7.x, 27 in 8.x, 21 in 9.x, 12 in 10.x), 10.6.0 [exec] and main ea57360912ed [exec]; not affected: releases up to 6.2.1, which have no UnifiedHighlighter; not fixed on main (FieldHighlighter.java:212 unchanged, and no open PR touches FieldHighlighter.java or the handling of maxPassages); release branches after 10.5.2 were not checked apart from the 10.6.0 release jars",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-265.html",
   "repro": "repro/LFV-265/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-493",
   "priority": "low",
   "priority_rank": 622,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter break iterators (LengthGoalBreakIterator.next on the no-match default-summary path, FieldHighlighter.getSummaryPassagesNoHighlight)",
   "title": "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)",
   "summary": "You give the UnifiedHighlighter LengthGoalBreakIterator.createMinLength(base, 0, a) or createClosestToLength(base, 0, a): both factories accept a goal of 0, and with it matches are highlighted exactly as with the base iterator. When a hit has no match in the field, you expect the documented default summary, the first maxPassages sentences (for example 'First sentence. '). Instead next() computes the target 0 + 0 = 0 and calls the base iterator's following(-1), which every java.text.BreakIterator rejects, so IllegalArgumentException 'offset out of bounds' escapes and the whole highlight call fails; goal 0 worked on this path from 6.4.0 through 8.4.1.",
   "impact_class": "crash",
   "introduced_commit": "4c9cc2cefd7f3593c4b4e1e5a087e3d206298989 on master and its branch_8x twin 5874b9c7933233712da14c5a5b9bb4f916eb77f8 (LUCENE-9093 'UnifiedHighlighter LengthGoalBreakIterator frag align. Matches in passages should be centered better on average', issue now apache/lucene#10135; the changes of apache/lucene-solr#1123, which GitHub shows as closed because the change was committed directly with 'Closes #1123') [read]. It changed next() from 'return following(current());' to 'return following(currentCache, currentCache + lengthGoal);'. The throwing call baseIter.following(targetIdx - 1) (:173) dates from LUCENE-7620 (ea49989524e, 6.4.0), where its argument could not be negative; LUCENE-9093 made it reachable with -1 by routing next() through it",
   "introduced_date": "2020-01-01",
   "first_affected_version": "8.5.0 [exec] (first release that contains 5874b9c7933; first 9.x release 9.0.0 [exec]); last unaffected release 8.4.1 [exec]; the class exists since 6.4.0 (LUCENE-7620), and the probe does not compile on 6.3.0, which lacks it [exec]",
   "affected_versions": "every release from 8.5.0 on: 8.5.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.6.0 (10.6.0 [exec] on its release jars, in the bug doc's runs), and main ea57360912ed [exec]; not affected: all 34 releases 6.4.0-8.4.1 [exec], including the whole 7.x line, which never received the change; not fixed upstream [read]; 10.6.0, the one release after 10.5.2, was executed only in the bug doc's runs (its release jars: fail)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-493.html",
   "repro": "repro/LFV-493/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-546",
   "priority": "low",
   "priority_rank": 623,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter no-match default summary (FieldHighlighter.highlightFieldForDoc maps only '== -1' to maxPassages; FieldHighlighter.getSummaryPassagesNoHighlight)",
   "title": "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",
   "summary": "You build a UnifiedHighlighter with withMaxNoHighlightPassages(-2), or any other negative value except -1, relying on the getMaxNoHighlightPassages javadoc: 'If it's less than 0 (the default) then this defaults to the maxPassages parameter given for each request.' For a document with no match in the field you expect the same default summary as with -1, for example 'First sentence. '. Instead FieldHighlighter maps only exactly -1 to maxPassages and passes -2 on to getSummaryPassagesNoHighlight, whose new ArrayList<>(Math.min(-2, 10)) throws IllegalArgumentException 'Illegal Capacity: -2', so the highlight call fails.",
   "impact_class": "wrong error",
   "introduced_commit": "722e82712435ecf46c9868137d885484152f749b (LUCENE-7438 'New UnifiedHighlighter', committed directly by dsmiley; issue now apache/lucene#8490; the work of apache/lucene-solr#79 by Timothy055, which GitHub shows as closed unmerged) and its branch_6x backport 4b6794368df373df1f68ccf27f7556914efeb95e [read]. The '== -1' check (FieldHighlighter.java:93 today), the ArrayList capacity line (:112) and the 'less than 0 (the default)' javadoc all arrived in this commit, so there is no regression window; the '== -1' test already existed on the PR branch (f0340e27, 2016-09-04)",
   "introduced_date": "2016-10-04",
   "first_affected_version": "6.3.0 [exec] (first release with the UnifiedHighlighter, from the branch_6x backport 4b6794368df); 6.2.1 has no org.apache.lucene.search.uhighlight package [exec] and its predecessor PostingsHighlighter had no maxNoHighlightPassages option [read]; first release from master containing 722e827: 7.0.0 [exec]",
   "affected_versions": "every release that has the UnifiedHighlighter: 6.3.0-6.6.6, 7.0.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.6.0, and main ea57360912ed [exec] [read]; not fixed upstream [read]; the 10.6.0 release jars (4ae946e5a9b) fail the doc's minimal JUnit with -ea [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-546.html",
   "repro": "repro/LFV-546/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-808",
   "priority": "low",
   "priority_rank": 624,
   "novelty": "known",
   "withheld": false,
   "area": "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",
   "title": "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",
   "summary": "You search with a TermInSetQuery of the two terms 'short' and a 1001-byte term on a field indexed with offsets, get the hit, and highlight it with a UnifiedHighlighter built with withWeightMatches(false), expecting 'a <b>short</b> text', which is what the documented equivalent (a ConstantScoreQuery over a BooleanQuery of SHOULD TermQuery clauses) gives. Instead highlight() throws IllegalArgumentException 'This builder doesn't allow terms that are larger than 1000 UTF-8 bytes', and any QueryVisitor that asks the query for its automaton gets the same exception. For more than one term TermInSetQuery#visit hands visitors a supplier that builds Automata.makeBinaryStringUnion over all terms, and that builder rejects terms longer than Automata.MAX_STRING_UNION_TERM_LENGTH (1000 bytes, a guard for its recursive construction), although the query itself accepts such terms and searches with them.",
   "impact_class": "crash",
   "introduced_commit": "267d70b66b6ac30db1d48f131b294512420f468c (master, first released in 9.0.0) and its branch_8x backport 4be69c8540b51f52355f9926cd84f3b3de985180 (first released in 8.6.0): 'LUCENE-9349: TermInSetQuery should use consumeMatchingTerms in visit() (#1465)' (apache/lucene-solr#1465, issue now apache/lucene#10389, author romseygeek), which switched TermInSetQuery.visit from consumeTerms(term list) to consumeTermsMatching(this::asByteRunAutomaton) for more than one term and introduced the Supplier signature; the supplier then failed in Operations.isFinite (recursion cap MAX_RECURSION_LEVEL = 1000, LUCENE-7914) through CompiledAutomaton [exec]. GITHUB#12320 (52ace7eb3564 on main, 349b458e8895 on branch_9x, 2023-06-02, author gsmiller, first released in 9.7.0) moved the supplier to Automata.makeBinaryStringUnion, so since 9.7.0 the limit is the string-union builder's 1000-byte term limit from LUCENE-8429 (d78feb22361, 2018) [read]; the bug was kept, only the message changed.",
   "introduced_date": "2020-04-29 (LUCENE-9349, 267d70b66b6 and 4be69c8540b); mechanism change 2023-06-02 (#12320); builder limit 2018-07-27 (LUCENE-8429)",
   "first_affected_version": "8.6.0 [exec] (8.5.2 passes [exec]: TermInSetQuery.visit still reported the term list and the supplier API did not exist); with the default UnifiedHighlighter in 8.6.0-8.11.4 [exec]; from 9.0.0 (LUCENE-9431, WEIGHT_MATCHES on by default) only with WEIGHT_MATCHES off or through a visitor that calls the supplier",
   "affected_versions": "every release from 8.6.0 to 10.5.2 (the last before 10.6.0) and main a9779ef3c193 [exec]. Message 'input automaton is too large: 1001' through 9.6.0, 'This builder doesn't allow terms that are larger than 1000 characters' from 9.7.0, '... 1000 UTF-8 bytes' since the 9.9.0 rewording; the boundary is 1000 bytes in every executed version (1000 passes, 1001 fails). branch_10_6 head 2763db11b0a has the same TermInSetQuery, StringsToAutomaton, QueryVisitor, MultiTermHighlighting and UnifiedHighlighter code as 10.5.2 [read], so 10.6.0 (released 2026-10-29) ships it (not executed). Not affected: 8.5.2 and older [exec]. Not fixed on main, branch_10x or branch_10_6.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/11808",
    "https://github.com/apache/lucene/issues/10696",
    "https://issues.apache.org/jira/browse/LUCENE-9657",
    "https://github.com/apache/lucene/issues/12320",
    "https://github.com/apache/lucene/issues/9475",
    "https://issues.apache.org/jira/browse/LUCENE-8429"
   ],
   "doc": "",
   "repro": "repro/LFV-808/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-574",
   "priority": "low",
   "priority_rank": 625,
   "novelty": "new",
   "withheld": false,
   "area": "queries / MoreLikeThis interesting-terms convenience API (MoreLikeThis.retrieveInterestingTerms(int) and retrieveInterestingTerms(Reader, String))",
   "title": "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",
   "summary": "You set MoreLikeThis.setMaxQueryTerms(Integer.MAX_VALUE), meaning 'no limit', and call retrieveInterestingTerms(...) on a one-word document. You expect that one word back, just as like() with the same setting returns a one-clause query. Instead both overloads begin with 'new ArrayList<>(maxQueryTerms)' (MoreLikeThis.java:889 and :914), sized from the limit rather than from the number of terms found, and throw java.lang.OutOfMemoryError: Requested array size exceeds VM limit.",
   "impact_class": "crash",
   "introduced_commit": "175cf8a9fd876aa7baaf7da1a2273e6ea984e8b1 (svn r169508, lucene/java/trunk, author dspencer, 2005-05-10: '[2] Added convenience routine retrieveInterestingTerms()', contrib/similarity; no issue and no pull request) introduced 'ArrayList al = new ArrayList( maxQueryTerms);' [read]. The same body, pre-size included, was copied into retrieveInterestingTerms(int docNum) by LUCENE-1295 (1979d756055, 2008, first released in 2.4.0) and into retrieveInterestingTerms(Reader, String) by LUCENE-3326 (bfea7d6a155 on 3.x / 07bfe50eda6 on trunk, 2011, 3.4.0 / 4.0.0); later edits kept it: LUCENE-1257 generics (5b83cc59b2e), LUCENE-5512 diamond (3b67b174932), LUCENE-5795 (1427d574d3d / 173a44e67c7, 2014, which capped createQueue at min(maxQueryTerms, #terms) and so made like() safe) and f9f6d3a3ac4 (2017, ArrayList<String>, current blame of both lines)",
   "introduced_date": "2005-05-10",
   "first_affected_version": "1.9 (first release tag containing the line, 2006-02-27; already in 1.9-rc1, 2006-02-21) [read]; the earliest release on Maven Central, 1.9.1 (identical MoreLikeThis.java), fails [exec]; no earlier release ships MoreLikeThis (1.4.3 and older [read]), so there is no last unaffected release",
   "affected_versions": "every release that ships MoreLikeThis, 1.9 through 10.6.0, and main ea57360912ed; never fixed [exec] [read]; retrieveInterestingTerms(int docNum) is affected from 2.4.0 and retrieveInterestingTerms(Reader, String) from 3.4.0, and the deprecated retrieveInterestingTerms(Reader) (1.9 to 3.6.x) has the pre-size or delegates to the (Reader, String) overload; upstream main a95c754ee003 (2026-10-26) has a byte-identical MoreLikeThis.java and branch_10x the same lines [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-574.html",
   "repro": "repro/LFV-574/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-958",
   "priority": "low",
   "priority_rank": 626,
   "novelty": "new",
   "withheld": false,
   "area": "grouping / SearchGroup.merge (merging first-pass top groups across shards or slices; reduce step of FirstPassGroupingCollectorManager)",
   "title": "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)",
   "summary": "You merge the first-pass top groups of two shards (three groups in all) with SearchGroup.merge(shardGroups, 0, Integer.MAX_VALUE, groupSort) to get every group, and expect the three groups, the same as topN = 10 returns, as 6.1.0 and earlier returned for the same call, and as core TopDocs.merge(0, Integer.MAX_VALUE, ...) does for hits. Instead merge throws OutOfMemoryError 'Requested array size exceeds VM limit', because since 6.2.0 (LUCENE-7356) it pre-sizes its result list with new ArrayList<>(topN). With offset 1 it throws NullPointerException, because maxQueueSize = offset + topN wraps to a negative int and the pruning loop polls an empty queue (NoSuchElementException on 3.x).",
   "impact_class": "crash",
   "introduced_commit": "pre-size leg (OutOfMemoryError, the key's name): e0c45f400f83aab397b58ff2f83b2b11229576a7 (master) and its branch_6x commit 0c43ae2b5c2a13e16a14897335ea6facf7a3db43, LUCENE-7356 'SearchGroup tweaks (initialCapacity, size==0 vs. isEmpty)' (apache/lucene#8410; JIRA patch era, no pull request; author cpoerschke, one '+1' from jpountz, no discussion of large topN), which changed new ArrayList<>() to new ArrayList<>(topN) [read]. Overflow leg (offset >= 1): a1e74fd6c9463558e3c052f61dfd53c00328902f (trunk) and c0713158f8c466146a09d2a4d974c656b379c209 (branch_3x), LUCENE-3191 (apache/lucene#4264, mikemccand), the change that added SearchGroup.merge with 'final int maxQueueSize = offset + topN' [read]; b843dfe8396 (LUCENE-3239, 2011-06-30) later changed queue.last() to pollLast(), which turned the 3.x NoSuchElementException into the NullPointerException from 4.0.0 on.",
   "introduced_date": "2016-06-28 (author date of e0c45f400f8 and 0c43ae2b5c2, pre-size leg); 2011-06-15 (a1e74fd6c946, trunk) and 2011-06-16 (c0713158f8c, branch_3x), overflow leg",
   "first_affected_version": "6.2.0 for the OutOfMemoryError (offset 0, topN = Integer.MAX_VALUE) [exec]; 3.3.0, the first release with SearchGroup.merge, for the offset >= 1 crash (NoSuchElementException on 3.3.0-3.6.2, NullPointerException from 4.0.0) [exec]; 3.2.0 has no merge method [exec]",
   "affected_versions": "[exec] sweep of 136 releases from 3.3.0 to 10.5.2, one -da probe run each (public SearchGroup.merge on two hand-built shards, oracle topN = 10): offset 0 with topN MAX returns the groups on 3.3.0-6.1.0 and on 5.5.3-5.5.5 (released after 6.2.0 from branch_5_5, which never got LUCENE-7356) and throws OutOfMemoryError on the 89 releases 6.2.0-10.5.2; offset 1 with topN MAX throws NoSuchElementException on 3.3.0-3.6.2 and NullPointerException on the 130 releases 4.0.0-10.5.2; 6.1.0, 6.2.0, 9.12.3 and 10.5.2 also with -ea, same results. The candidate's JUnit fails 2 of 2 on 10.5.0 and 10.5.2 (-ea), on the branch_10_6 head 4ae946e5a9b (10.6.0 release candidate; -ea and -da) and on main a9779ef3c193 (-ea and -da; re-run at the registration check 2026-10-28: 2 of 2 fail with -ea and with -da, seed DEADBEEF); on 10.4.0 only its setUp fails to compile (FirstPassGroupingCollectorManager first shipped in 10.5.0), while the release probe there fails like every other 6.2.0+ release. [read] SearchGroup.java is byte-identical on main a9779ef3c193, the study base 7cecf795236 and upstream main (2026-10-28); branch_10_6 and branch_10x differ only by a cosmetic instanceof pattern; the last commits on the file are #16088 (author date 2026-05-21) and #15896 (2026-04-29), neither touching :281 or :294. Releases 8.9.0-8.11.4 are covered by execution only (not tagged in the history clone).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-958.html",
   "repro": "repro/LFV-958/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1002",
   "priority": "low",
   "priority_rank": 627,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / document suggester: TopSuggestDocs.merge (merging per-shard suggestion results)",
   "title": "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",
   "summary": "You collect suggestions from two index shards (for example SuggestIndexSearcher.suggest(query, 5, false) on each, giving 3 and 2 hits) and combine them with TopSuggestDocs.merge(Integer.MAX_VALUE, shards) to keep them all; its javadoc calls it 'Analogous to TopDocs#merge(int, TopDocs[])' and sets no bound on topN, so you expect the 5 hits that merge(10, ...) returns and that TopDocs.merge(Integer.MAX_VALUE, ...) returns for ordinary hits. Instead merge throws IllegalArgumentException 'maxSize must be >= 0 and < 2147483631; got: 2147483647', even for a single empty shard, because it creates its PriorityQueue with topN slots before it looks at any shard (TopSuggestDocs.java:116-117), while TopDocs.merge sizes its queue by the number of shards and its result by the hits it received. Below that limit, a large topN such as 10^8 makes merge allocate topN + 1 slots for a handful of hits.",
   "impact_class": "crash",
   "introduced_commit": "b7adb6ac7704a7e6364ee0d831bf77cf849f2090 (trunk, svn r1669698) and its branch_5x copy 40e94c39ad3b0f018ae9647b7d30bd0cfe341d86 (svn r1669715, the commit in 5.1.0): LUCENE-6339 'Near real time Document Suggester' (apache/lucene#7400; Areek Zillur; Subversion-era patch, no pull request), which added merge with new SuggestScoreDocPriorityQueue(topN). Michael McCandless proposed a TopSuggestDocs.merge method in that review; none of the 35 comments discusses its queue size [read]. 8e2c6aa1d58 (#14817, Simon Cooper, author date 2025-06-27, main only) replaced the queue class with PriorityQueue.usingComparator(topN, ...) and kept the size (git blame of main lines 116-117 points there). Not a regression.",
   "introduced_date": "2015-03-27 (b7adb6ac770, trunk); 2015-03-28 (40e94c39ad3, branch_5x)",
   "first_affected_version": "5.1.0 [exec] (tagged 2015-04-13; 5.0.0 has no TopSuggestDocs: the history probe does not compile there [exec])",
   "affected_versions": "Every release from 5.1.0 through 10.5.2, the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193. [exec] The follow-up's release-faithful main() probe fails on 5.1.0 (-ea and -da), 5.5.5, 6.6.6, 7.4.0, 7.5.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da): merge(Integer.MAX_VALUE) and merge(Integer.MAX_VALUE, {EMPTY}) throw, while the TopDocs.merge control returns 3 hits; the finder's JUnit fails 2 of 3 on main (-ea, -da), the 10.6 RC, 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 2 of 4 on main (-ea, -da), 10.5.2 and 9.12.3, and its main() variant fails on 8.11.4 and 8.0.0. Only the exception changed over time: NegativeArraySizeException -2147483648 in 5.1.0-7.4.0, IllegalArgumentException from 7.5.0 on (the PriorityQueue guard fix 4c646dab3fb, 2018, thanks rsaavedraf). The topN + 1 allocation is in every version (400,000,896 to 400,000,944 bytes for 3 hits at topN = 10^8, against about 1 KB for TopDocs.merge). [read] Not fixed: upstream main 645d4fe14a20 still sizes the queue by topN (line 117, checked 2026-10-29), and branch_10x and branch_10_6 still use new SuggestScoreDocPriorityQueue(topN) (#14817 was not backported; the file is unchanged there since 2021).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1002.html",
   "repro": "repro/LFV-1002/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-996",
   "priority": "low",
   "priority_rank": 628,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / spell checking (SpellChecker.suggestSimilar hit budget 10 * numSug and SuggestWordQueue size)",
   "title": "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",
   "summary": "You build an n-gram spell index with SpellChecker and call suggestSimilar(word, Integer.MAX_VALUE) to get all suggestions; you expect the same 9 suggestions that numSug 1000 returns on a 10-word dictionary. Instead SpellChecker multiplies numSug by 10 in int to size its search, the product wraps to -10, and the search throws IllegalArgumentException 'numHits must be > 0; please use TotalHitCountCollectorManager ...', naming a parameter the caller never passed; the same happens for half of all counts from 214,748,365 up, and in the blocks between (for example 429,496,730, whose product wraps to 4) the call silently returns fewer suggestions after allocating a queue of numSug slots. The fix is two lines: compute the budget in long and saturate it at Integer.MAX_VALUE, and size the queue by min(numSug, hits.length).",
   "impact_class": "wrong error",
   "introduced_commit": "57cd0765650 (the initial SpellChecker contribution 'prelim checking of spellchecker, v1.1', committed by David Spencer; the class's @author tag names Nicolas Maisonneuve; svn r151014, sandbox, no JIRA key and no pull request): the class as first written already had both halves of the defect, the int product as loop bound 'int stop=Math.min(hits.length(), 10*num_sug)' and the count-sized 'new SuggestWordQueue(num_sug)'. The current exception symptom dates from d7d9241ef7b (LUCENE-1856 'Remove Hits', migrated as #2931, Michael Busch, 2009-10-07, svn r822587), which made 'int maxHits = 10 * numSug' the searcher's top-N (line 361 on main blames to it); the 2.9 line got the same code through the LUCENE-2108 backport be65c5c2e26 (2009-12-06) [read]",
   "introduced_date": "2004-11-02 (author and commit date of 57cd0765650); current IllegalArgumentException symptom since 2009-10-07 (d7d9241ef7b, author and commit date)",
   "first_affected_version": "1.9 (tag 2006-02-27) [read]; oldest executed: 1.9.1 [exec]. The current IllegalArgumentException symptom starts at 3.0.0 (trunk) and 2.9.2 (2.9 line)",
   "affected_versions": "Every release that has SpellChecker: 1.9 to 10.5.2, 10.6.0 (released 2026-10-29; run as its RC, branch_10_6 4ae946e5a9b9) and main a9779ef3c193. Executed with -da on 22 releases plus the 10.6 RC and main, all failing [exec]: 1.9.1, 2.0.0, 2.4.1, 2.9.0, 2.9.1 (Integer.MAX_VALUE -> NegativeArraySizeException from the numSug + 1 queue; 214748365 -> silently [] instead of 9 suggestions), 2.9.2, 2.9.4, 3.0.0, 3.0.1, 3.0.3 ('nDocs must be > 0'), 3.1.0, 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0 ('numHits must be > 0; please use TotalHitCountCollector ...'), 9.12.3, 10.0.0, 10.5.2, the 10.6 RC and main ('... TotalHitCountCollectorManager ...'); also the finder's main() twin on 8.0.0 and its JUnit on 9.12.3 and 10.5.2 (-ea). The rest by reading: the product line has not changed since d7d9241ef7b, and before it the same product was the loop bound since 57cd0765650. The positive-wrap truncation leg was executed on main and 10.5.2 (-da, -Xmx4g) and applies to the other releases by reading. Not fixed upstream: upstream main 645d4fe14a20 still has lines 361, 364 and 366 (read 2026-10-29), and the newest commit on SpellChecker.java on upstream main is 378ca8d1bbf3 (2026-01-15, javadoc tags) (recheck 2026-10-29). Caveat: all runs used JDK 25.0.3 on Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-996.html",
   "repro": "repro/LFV-996/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-998",
   "priority": "low",
   "priority_rank": 629,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / analyzing: BlendedInfixSuggester lookup over-fetch (num * numFactor)",
   "title": "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",
   "summary": "You build a BlendedInfixSuggester with its defaults (numFactor 10) from 8 entries that match 'luc' and call lookup(\"luc\", false, Integer.MAX_VALUE) to get all suggestions; num is documented as the 'maximum number of results to return', so you expect the same 8 suggestions that num = 1000 returns. Instead the over-fetch count num * numFactor is computed in int (BlendedInfixSuggester.java:199) and wraps: a negative product throws IllegalArgumentException 'numHits must be > 0; please use TotalHitCountCollector ...' (num = Integer.MAX_VALUE or 214748365), a product below numFactor leaves room for 0 results and throws NoSuchElementException (num = 429496730), and a small positive product silently cuts the list (num = 429496731 returns only [lucas]; with numFactor 1000 already num = 4294969 does). So the number of suggestions can go down as num goes up.",
   "impact_class": "wrong error",
   "introduced_commit": "fb5fd910780d5862101cbd5f49f343b40eeca025 (trunk, svn r1556952) and 89a9302d5a743aca276621ba04196c1fc01d14a2 (branch_4x, r1556954): LUCENE-5354 'add new BlendedInfixSuggester' (#6418; Remi Melisson's patch, committed by Michael McCandless; Subversion era, no pull request). The class arrived with both halves of the defect: lookup overloads that pass num * numFactor down the chain as an int, and createResults' 'int actualNum = num / numFactor'. LUCENE-6050 (127eed36dd5 / 95ddd51108b, 2014-11-11, 5.0.0) and LUCENE-6464 (213cdf67930, 2015-05-15, 5.2.0) added overloads with their own multiplication; SOLR-7865 (602a1f50e72, author date 2015-12-18; in 5.3.2, 5.4.1, 5.5.0, 6.0.0) kept only the last multiplication, still in int, which is line 199 on main (blame 213cdf67930) [read]",
   "introduced_date": "2014-01-09",
   "first_affected_version": "4.7.0 [exec] (the class first shipped in 4.7.0; 4.6.1 has no BlendedInfixSuggester [exec])",
   "affected_versions": "Every release from 4.7.0 to 10.5.2, 10.6.0 (released 2026-10-29; run as its RC) and main [exec]; the int product and 'num / numFactor' are in all 110 local release tags from 4.7.0 on (8.9.0-8.11.3 are not tagged locally and are inferred) [read]. The wrap threshold changed with the number of multiplications on the path: num >= 21474837 in 4.7.0-4.10.4 (num * 100), num >= 2147484 in 5.0.0-5.3.1 and 5.4.0 (num * 1000), num >= 214748365 from 5.3.2, 5.4.1 and 5.5.0 on (num * 10, default factor) [exec]. In 4.7.x a negative product threw NegativeArraySizeException instead of the IllegalArgumentException [exec]. Not fixed: upstream main 645d4fe14a20 (2026-10-28) still has lines 199 and 227, and the newest commit on BlendedInfixSuggester.java is ce50d3a135d on main (author date 2025-02-24) and db775275305 on branch_10x and branch_10_6 (2025-02-12); no open PR changes these lines [read]. Caveat: all runs used JDK 25.0.3 on Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-998.html",
   "repro": "repro/LFV-998/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-577",
   "priority": "low",
   "priority_rank": 630,
   "novelty": "known",
   "withheld": false,
   "area": "queries / MoreLikeThis field-name resolution (setFieldNames(null) and the convenience method retrieveInterestingTerms(int))",
   "title": "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",
   "summary": "You create a MoreLikeThis, call setFieldNames(null), which its javadoc documents as 'the field names to be determined at runtime from the IndexReader provided in the constructor', and ask retrieveInterestingTerms(docNum) for the interesting words of an indexed document. You expect the words that like(docNum) would put into its query, taken from all indexed fields. Instead the call throws 'NullPointerException: Cannot read the array length because \"<local4>\" is null' at MoreLikeThis.retrieveTerms (MoreLikeThis.java:715), because only like(int) and like(Map) replace null with the reader's indexed fields, so it works only if one of them ran first on the same instance.",
   "impact_class": "crash",
   "introduced_commit": "1979d7560553b6c617e28468569e2d99c5a4f20d (svn r662413, lucene/java/trunk, 2008-06-02): LUCENE-1295 'Made method public and added retrieveInterestingTerms variation' (now apache/lucene#2372; a JIRA patch committed by gsingers, no pull request; CHANGES 2.4.0 New features 15) added public retrieveInterestingTerms(int docNum), which calls retrieveTerms(docNum) with no 'fieldNames == null' step, while like(int) already had that step; the null contract (setFieldNames and DEFAULT_FIELD_NAMES javadoc) and like(int)'s null resolution date from the class's first check-in 7952217cea6 (2005-01-17) [read]. Correction to the candidate: 175cf8a9fd8 (2005-05-10) added only retrieveInterestingTerms(Reader). Later edits to these lines added no null step (LUCENE-3308 4e198e8caf0, 2011, the for-each loop at :715; LUCENE-5795 173a44e67c7, 2014, the queue type at :890)",
   "introduced_date": "2008-06-02",
   "first_affected_version": "2.4.0 (released 2008-10-06) [exec]; last unaffected: 2.3.2 (method absent)",
   "affected_versions": "every release from 2.4.0 through 10.5.2 and main ea57360912ed; never fixed [exec] [read]; secondary entry point: retrieveTerms(int) was public from 2.4.0 to 4.9.1 and threw the same NPE [exec]; not affected: 1.9.x to 2.3.2 (method absent); upstream main a95c754ee003 (2026-10-26) has a byte-identical MoreLikeThis.java [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/2372",
    "https://github.com/apache/lucene/issues/4399",
    "https://github.com/apache/lucene/issues/940",
    "https://issues.apache.org/jira/browse/LUCENE-3326",
    "https://github.com/apache/lucene-solr/pull/369",
    "https://github.com/apache/lucene/issues/380"
   ],
   "doc": "",
   "repro": "repro/LFV-577/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-469",
   "priority": "low",
   "priority_rank": 631,
   "novelty": "new",
   "withheld": false,
   "area": "queries / intervals (Intervals.atLeast: MinimumShouldMatchIntervalsSource); queryparser / flexible StandardQueryParser fn:atLeast",
   "title": "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",
   "summary": "You build Intervals.atLeast(0, Intervals.term(\"a\"), Intervals.term(\"b\")), or parse 'fn:atLeast(0 a b)' with the flexible StandardQueryParser, and search an index that contains 'a b c'. You expect the 0 to be rejected with an IllegalArgumentException when the query is built (the same factory already handles a count equal to or larger than the number of sources), or else a search that runs. Instead the query is accepted and every search with it throws: NullPointerException in MinimumShouldMatchIntervalIterator.nextInterval, because top() of its empty, capacity-0 queue is null, or ArrayIndexOutOfBoundsException from an empty DisiPriorityQueue on a segment that holds none of the terms.",
   "impact_class": "wrong error",
   "introduced_commit": "e015afadaa698a0eb39574198dce31b9a7292a62 (master) and its branch_8x backport bfbe80472ef330f3ad264eda7a9ef48eb91b58cc (the released one, 8.0.0), both 'LUCENE-8622: Minimum-should-match interval function' by romseygeek; JIRA patch workflow, no GitHub PR (issue migrated as apache/lucene#9668) [read]. 077f8ccf708 (LUCENE-9744, apache/lucene-solr#2323, first released in 8.8.2) added the '== sources.length -> unordered' and '> sources.length -> no match' shortcuts and 'assert minShouldMatch < sources.length' but no lower bound (8.8.1 and 8.8.2 both fail [exec]); 8ef6a0da568 (LUCENE-9570) only re-wrapped the loop guard. The query-text path came with f725b27e12a (LUCENE-10223, apache/lucene#429 by dweiss, backport ff9ee28c603), whose AtLeast node passes the parsed number straight to Intervals.atLeast. Not a regression: wrong since the API was added; no commit-level bisection",
   "introduced_date": "2019-01-07 (LUCENE-8622); query-text exposure 2021-11-11 (LUCENE-10223)",
   "first_affected_version": "8.0.0 [exec] (direct Java API; intervals were then in the sandbox module, package org.apache.lucene.search.intervals; queries module from 8.2.0 [exec]); query text fn:atLeast(0 ...) through the flexible StandardQueryParser from 9.1.0 [exec] (9.0.0 has no interval functions in the parser and parses the text as an ordinary BooleanQuery [exec]); 7.6.0 and 7.7.3 have no atLeast API [exec]",
   "affected_versions": "every release from 8.0.0 through 10.6.0 and main ea57360912ed; not fixed upstream. [exec] follow-up history runs (seed DEADBEEF, -da; 8.0.0 and main also -ea): the direct API fails with NullPointerException 'PriorityQueue.top() is null' on 8.0.0, 8.1.1, 8.2.0, 8.8.1, 8.8.2, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main, with the atLeast(1, a, b) control passing before the failing call in every API run; query text fn:atLeast(0 a b) fails on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main; the independent reproduction's own JUnit fails 4 of 6 on main (-ea, -da), 10.5.2 and 9.12.3 and 3 of 5 on 8.11.4 (direct API only), and its probe shows the ArrayIndexOutOfBoundsException (no source term in the segment) and the late IllegalArgumentException for atLeast(-1, a, b) on main, 10.5.2, 9.12.3 and 8.11.4. [read] the releases in between: git blame shows the missing lower bound and the 'proximityQueue.size() == minShouldMatch && proximityQueue.top().start() == start' loop unchanged in logic since e015afadaa6; upstream main 49483e82b357 (re-checked 2026-10-26: no commit after it, and the last changes to Intervals.java and MinimumShouldMatchIntervalsSource.java predate ea57360912ed), branch_10x and branch_10_6 have the same code, and 10.6.0 (released 2026-10-29) is affected: the doc's one-method test fails on its release jars with -ea and -da [exec]. Caveats: all runs on JDK 25 (aarch64), so the old releases ran on a newer JDK than they were built for; the negative-value variant was not part of the history sweep",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-469.html",
   "repro": "repro/LFV-469/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-606",
   "priority": "low",
   "priority_rank": 632,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / matchhighlight: MatchRegionRetriever low-level API (highlightDocument with a custom FieldValueProvider) and the offset strategies OffsetsFromPositions, OffsetsFromTokens, OffsetsFromValues and the OffsetsFromMatchIterator fallback",
   "title": "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",
   "summary": "You call MatchRegionRetriever.highlightDocument with your own FieldValueProvider, for example one backed by a Map built from the document's stored fields, and for a field that is indexed but not stored it returns null, exactly as FieldValueProvider#getValues documents ('null if the field is not loaded or does not exist'). You expect no hit regions for that field, which is what the same provider gives when it returns an empty list and what the in-tree highlightDocuments path gives on the same index. Instead the default offset strategy uses the null list and the call throws NullPointerException (OffsetsFromPositions.java:70 for a positions-only field, OffsetsFromTokens.java:74 for a DOCS or DOCS_AND_FREQS field; the opt-in OffsetsFromValues fails at OffsetsFromValues.java:51).",
   "impact_class": "crash",
   "introduced_commit": "755de5aae331301acf4c1acd3af6d7329998ee48 (#12881 'Performance improvements to MatchHighlighter and MatchRegionRetriever', author dweiss, merged into main only and never backported to 9.x). It rewrote FieldValueProvider (List<String>, extends Iterable<String>) and added the javadoc '@return ... or {@code null} if the field is not loaded or does not exist for the field'; in the same commit the only in-tree provider (StoredFieldsVisitor.getValues) maps a missing field to List.of(), and none of the strategies got a null check [read]. The unguarded dereferences themselves date from LUCENE-9463 (150a8dacb59, lucene-solr#1750, 2020-08-14, first released in 9.0.0), when the 9.x interface had no null clause and its in-tree provider never returned null, so the defect is the contract change, not a code change at the crash sites",
   "introduced_date": "2023-12-07 (#12881 merged into main)",
   "first_affected_version": "10.0.0 [exec]. Not affected: the 9.x line, whose FieldValueProvider contract had no null clause (a 9.x-API variant of the scenario throws the same NullPointerException on 9.0.0, 9.9.0 and 9.12.3 [exec], but there null was outside the contract); 8.x and older have no matchhighlight package",
   "affected_versions": "every release from 10.0.0 through 10.6.0 and main a9779ef3c193 and 645d4fe14a20, never fixed. [exec] the finder's JUnit fails 2 of 3 on 10.0.0 (-ea and -da), 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1 (-ea), 10.5.2 (-ea and -da) and main (-ea and -da); the independent reproduction's JUnit fails on main (-ea and -da), 10.5.2 (-ea and -da) and 10.0.0 (-ea); the intended-behaviour check's JUnit fails on main (-ea and -da) and 10.5.2; the minimal test fails on the 10.6.0 release jars (4ae946e5a9b9) and on main 645d4fe14a20, -ea and -da (2026-10-30). [read] branch_10_6 (2763db11b0a) and the unreleased branch_10x (1309534296e), both 2026-10-24, have the same null clause and the same unguarded dereferences (the two branch heads were read, not executed). Caveat: on 10.x releases a positions-only field also throws for an EMPTY list (RuntimeException 'One of the offsets missing for position range'), which main removed in #15577 (548ae997d12, in no release), so on releases the null-specific failure is the DOCS / DOCS_AND_FREQS one (OffsetsFromTokens) and OffsetsFromValues. Releases were run on JDK 25 with SHA-1-verified Maven Central jars. No open upstream PR changes the handling of getValues (2026-10-26)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-606.html",
   "repro": "repro/LFV-606/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1009",
   "priority": "low",
   "priority_rank": 633,
   "novelty": "new",
   "withheld": false,
   "area": "facet / facet sets (FacetSetsField packing of custom FacetSet encodings)",
   "title": "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",
   "summary": "You write a FacetSet subclass that compresses its value (one length byte plus the value's significant bytes, so sizePackedBytes() is 2 for the value 7 and 7 for 2^40) with a matching FacetSetDecoder, and you expect FacetSetsField.create(\"f\", set(7), set(2^40)) to work just like the same call with the two sets swapped. Instead create allocates 4 + the first set's sizePackedBytes() times the number of sets (8 bytes) and then writes each set's own packed bytes (13 needed), so the second set's packValues throws ArrayIndexOutOfBoundsException 'Index 8 out of bounds for length 8'. With the larger set first the same two sets pack, index and count correctly.",
   "impact_class": "crash",
   "introduced_commit": "f6bb9d218c0e8315d86d2aa2ac1f5c7313925a7a (apache/lucene#841, LUCENE-10274 'Add FacetSets faceting capabilities', Marc D'Mello and Shai Erera; branch_9x backport 0e1502c12ba9, #981) [read]. Inside #841, PR commit 40e2992e25 (2022-06-15) sized the buffer as 4 + the sum of every set's sizePackedBytes(); PR commit ab0d4e1624 (2022-06-19, 'Finish FacetSets.adoc') replaced that with the first set's size times the count, with no review comment on the change. Not a regression: the line and the javadoc it breaks were added together.",
   "introduced_date": "2022-06-25",
   "first_affected_version": "9.3.0 [exec] (the first release with facet sets, LUCENE-10274 in its CHANGES.txt); 9.2.0 has no facetset package [exec]",
   "affected_versions": "every release from 9.3.0 to 10.5.2 and 10.6.0 (by reading) [read]; [exec] the finder's JUnit fails on 9.3.0 (-ea, -da), 9.4.0 (-da), 9.12.3 (-ea, -da), 10.0.0 (-da), 10.5.2 (-ea, -da) and main 645d4fe14a20 (-ea, -da), always ArrayIndexOutOfBoundsException from FacetSetsField.toPackedValues:74 with the larger-first control passing; the independent reproduction's own JUnit fails on main (-ea, -da), 10.5.2 and 9.12.3; branch_10_6 / 10.6.0 RC1 4ae946e5a9b and branch_10x 657014b3c57 [read]; not fixed upstream (upstream main head 645d4fe14a20, author date 2026-10-28; newest commit on the facetset package a7704f5242d6, 2025-06-18, unrelated; no open PR touches FacetSetsField.java or FacetSet.java). JDK 25.0.3 for all versions.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1009.html",
   "repro": "repro/LFV-1009/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-968",
   "priority": "low",
   "priority_rank": 634,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / flexible core (QueryParserHelper; inherited by StandardQueryParser and PrecedenceQueryParser)",
   "title": "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)",
   "summary": "You call setQueryNodeProcessor(null) on a StandardQueryParser, a PrecedenceQueryParser or any QueryParserHelper to switch off the optional query-processing phase, as the method's javadoc allows ('The argument can be null, which means that no processor will be used to process the query node tree'). You expect the parser to go on parsing without processing, as it does when the null processor is passed to the QueryParserHelper constructor. Instead the setter always throws NullPointerException, because it stores the argument and then calls setQueryConfigHandler on it without the null check that the constructor, setQueryConfigHandler and parse all have.",
   "impact_class": "crash",
   "introduced_commit": "343992fcbb4b31249f07354014723f18d0508d8a (Subversion lucene/java/trunk r800191, 'LUCENE-1567: New flexible QueryParser framework.', the commit that created QueryParserHelper; JIRA LUCENE-1567, migrated to GitHub as #2641; there is no pull request). The null-allowing javadoc and the unguarded dereference were written together in that commit, next to the null-guarded constructor, so the defect was born with the API and is not a regression [read]",
   "introduced_date": "2009-08-03 (author and commit date of 343992fcbb4)",
   "first_affected_version": "2.9.0 [exec] (the first release with the flexible query parser; 2.4.1 has no such API: compile_error [exec], and no lucene-queryparser artifact exists for it)",
   "affected_versions": "every final lucene-queryparser release from 2.9.0 to 10.5.2 (147 versions [read]: bytecode scan of SHA-1-verified Maven Central jars shows no null test before the call in setQueryNodeProcessor, with setQueryConfigHandler's null test as the positive control; 4.0.0-ALPHA/BETA not checked), plus 10.6.0 (branch_10_6 4ae946e5a9b) and main. Executed [exec]: 2.9.0, 3.6.2, 4.0.0, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main with a main() variant (-ea); 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main with the JUnit (-ea); 9.12.3, 10.5.2, branch_10_6 4ae946e5a9b and main with the JUnit (-da). Every run fails with the same NullPointerException in setQueryNodeProcessor, and the constructor control passes.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-968.html",
   "repro": "repro/LFV-968/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1188",
   "priority": "low",
   "priority_rank": 635,
   "novelty": "new",
   "withheld": false,
   "area": "core / index: IndexWriterConfig (setIndexWriterEventListener) and IndexWriter commit (merge-on-commit)",
   "title": "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)",
   "summary": "You pass null to IndexWriterConfig.setIndexWriterEventListener, for example because your code forwards an optional listener that is not set. You expect what IndexWriterConfig does with every other null it does not support (since LUCENE-4833 its setters throw IllegalArgumentException, and setInfoStream points to its no-op sentinel), or else a writer that simply has no listener. Instead the setter stores the null, IndexWriter keeps it, and a later commit() that runs a merge-on-commit merge, which is on by default, throws NullPointerException 'because \"this.eventListener\" is null', far from the call that caused it.",
   "impact_class": "minor",
   "introduced_commit": "6ba9fe5be35dea3ff66d89f63bc876286f186ea4: LUCENE-9406 'Add IndexWriterEventListener to track events in IndexWriter' (apache/lucene-solr#2342, issue apache/lucene#10446), by zacharymorn. It added the setter without a null check, the NO_OP_LISTENER default and the two unguarded listener calls in IndexWriter.prepareCommitInternal [read]. The default-config reach came with b5795db0cf5 (LUCENE-10078, apache/lucene#921, Adrien Grand, 2022-06-07; branch_9x 7d9de759f24), which turned merge-on-commit on by default (DEFAULT_MAX_FULL_FLUSH_MERGE_WAIT_MILLIS 0 to 500) [exec].",
   "introduced_date": "2021-03-02 (author date of 6ba9fe5be35, commit date the same day; first release 9.0.0); 2022-06-07 (b5795db0cf5, the default-config reach; first release 9.3.0)",
   "first_affected_version": "9.0.0 [exec]; with the default config 9.3.0 [exec]. 8.x is not affected [exec].",
   "affected_versions": "Every release from 9.0.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT): 9.0.0-9.2.0 only with merge-on-commit switched on explicitly, 9.3.0 and later with the default config. [exec] the one-test repro TestNullEventListenerDefaultConfigCommit fails on main with -ea and -da (the independent reproduction, adjudication, history step, re-run of 2026-11-03), on 10.6.0, 10.5.2 and 9.12.3 (the independent reproduction, -da), and on 10.6.0, 9.12.3 and 9.3.0 (history step, -da); it passes on 9.2.0 and 9.0.0 (-da), where the history step's opt-in probe fails with the same NullPointerException; the intended-behaviour check's own test fails on main (-ea, -da) and 10.6.0 (-da). [read] the setter, the cached field and the unguarded calls are unchanged in every release since 9.0.0. Not affected: 8.x and older (API absent; 8.11.4 executed). Not new in 10.6 (10.5.2 and 9.12.3 fail too). Not fixed upstream: upstream main 1c2072f0284 (2026-11-02) still stores the argument unchecked (IndexWriterConfig.java:573-577, contents API, 2026-11-03).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1188.html",
   "repro": "repro/LFV-1188/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-655",
   "priority": "low",
   "priority_rank": 636,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / TermVectorLeafReader (LeafReader over one document's term vectors; LeafMetaData invariant)",
   "title": "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",
   "summary": "You build a TermVectorLeafReader over one document's term vectors (new TermVectorLeafReader(field, terms), the public helper that 'wraps a Terms with a LeafReader') and use it like any other LeafReader, expecting getMetaData() to return metadata with no index sort, as MemoryIndex's in-memory reader does. Instead getMetaData() throws IllegalArgumentException('minVersion must be set when createdVersionMajor is >= 7') on every call, because it passes minVersion=null together with createdVersionMajor=Version.LATEST.major, a combination the LeafMetaData constructor rejects. So a field-sorted search (even with Sort.RELEVANCE), new ParallelLeafReader(reader) and addIndexes(SlowCodecReaderWrapper.wrap(reader)) all fail; a plain relevance search without a Sort works.",
   "impact_class": "crash",
   "introduced_commit": "23b002a0fdf2f6025f1eb026c0afca247fb21ed0 (LUCENE-7756 'Only record the major Lucene version that created the index, and record the minimum Lucene version that contributed to segments', migrated as apache/lucene#8807, by Adrien Grand; JIRA patch era, no PR): the same commit added the LeafMetaData constructor check and rewrote TermVectorLeafReader.getIndexSort() { return null; } as getMetaData() { return new LeafMetaData(Version.LATEST.major, null, null); }, while giving MemoryIndex the valid Version.LATEST [read]. The field-sorted-search trigger came with LUCENE-8059 'Fold early termination support into TopFieldCollector' (812711416d9 on master, e4e7d12f5d8 on branch_7x, first release 7.2.0), which made TopFieldCollector read getMetaData() for every leaf [exec]. 6677109ee60 (#12685, first release 10.0.0) only appended hasBlocks=false and kept the null",
   "introduced_date": "2017-03-30 (authored), 2017-04-04 (committed to master); sorted-search trigger 2017-11-29 (LUCENE-8059)",
   "first_affected_version": "7.0.0 [exec] (direct getMetaData(), ParallelLeafReader and addIndexes fail); field-sorted search fails from 7.2.0 [exec]. 6.x and older are not affected [exec]: getMetaData() did not exist and its predecessor getIndexSort() returned null",
   "affected_versions": "Every release from 7.0.0 to 10.6.0 (10.6.0 [exec]) and main a9779ef3c193; never fixed. [exec] follow-up version-independent main() probe: fails on 7.0.0, 7.1.0, 7.2.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da), passes on 6.5.0 and 6.6.6 and on main with the one-line fix shadowed; the finder's JUnit fails 2 of 2 on main (-ea and -da), 10.5.2 and 10.0.0, and its main() repro fails on 9.12.3, 9.4.2, 8.11.4, 7.7.3 and 7.0.0; the independent reproduction's JUnit fails 4 of 6 on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's probe fails 2 of 5 on main (-ea and -da) and 10.5.2; upstream main a95c754ee003, branch_10x and branch_10_6 still have the line (read through the GitHub contents API, not executed). JDK 25.0.3, aarch64; pure Java logic.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-655.html",
   "repro": "repro/LFV-655/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-692",
   "priority": "low",
   "priority_rank": 637,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-stempel / egothor stemmer trie reduction (Reduce.optimize, reached through Trie.reduce, MultiTrie.reduce and MultiTrie2.reduce)",
   "title": "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",
   "summary": "You reduce a stempel stemmer table with the base class of the egothor reductions, for example trie.reduce(new Reduce()), and expect what its javadoc promises: 'Optimize (remove holes in the rows) the given Trie and return the restructured Trie', a trie that still gives the same stems. Instead every call throws IndexOutOfBoundsException ('Index 0 out of bounds for length 0'), even for a one-word trie or the bundled Polish table. The cause is one wrong argument at Reduce.java:83: optimize passes its freshly created, empty list 'rows' to removeGaps as the list to read from, instead of 'orows' (the trie's own rows), which the sibling reductions Lift and Gener pass to the same helper.",
   "impact_class": "crash",
   "introduced_commit": "98c47c57e0a54ab4aab9d91dd60c33edef130893 (trunk, svn r940433, 'LUCENE-2298: Add stempel, an algorithmic stemmer with included Polish support', committed by rmuir; issue LUCENE-2298 'Polish Analyzer', now GitHub #3374; svn era, the code came as a JIRA patch, no PR) and its branch_3x backport 58328f0379049045b325d2082295836a7a50e9ce ('LUCENE-2298: backport', Reduce.java byte-identical). The wrong argument is in the imported code itself (import line Reduce.java:86 'rows = removeGaps(orig.root, rows, new ArrayList<Row>(), remap);'); the initial import of another contributor's fork of the original Egothor2 code (buda-base/stemmer 01b8840370b6) has it too, so it predates Lucene. The only later change to the line is dbaf97f5dcc (#14965, 2025-07-18, diamond only), which is why plain git blame names that commit; the form 'removeGaps(orig.root, orows' never appears on any branch [read]",
   "introduced_date": "2010-05-03 (trunk import 98c47c57e0a); 2010-05-06 (branch_3x backport 58328f03790)",
   "first_affected_version": "3.1.0 [exec] (2011-03-30; the first release with the stempel module, through the branch_3x backport; on the trunk lineage the first release is 4.0.0 [exec]). No release has the API without the bug: 3.0.3 has no stempel or org.egothor classes and no lucene-stempel artifact [exec].",
   "affected_versions": "Every release from 3.1.0 to 10.5.2, and main a9779ef3c193. Executed with the follow-up main() repro (3 base-Reduce cases fail, 2 Optimizer controls pass): 3.1.0 (-ea and -da), 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main [exec]; the finder's JUnit (2 of 2) and the independent reproduction's JUnit (3 of 4) also fail on 10.5.2 and 9.12.3 [exec]; the other releases by reading, because the line is unchanged since the import [read]. Not fixed: upstream main a95c754ee003 (2026-10-26) and branch_10x still have the line, and no open PR touches Reduce.java [read].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/6584",
    "https://issues.apache.org/jira/browse/LUCENE-5521",
    "https://github.com/apache/lucene/issues/6569",
    "https://issues.apache.org/jira/browse/LUCENE-5506",
    "https://github.com/apache/lucene/issues/3374",
    "https://issues.apache.org/jira/browse/LUCENE-2298"
   ],
   "doc": "",
   "repro": "repro/LFV-692/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-936",
   "priority": "low",
   "priority_rank": 638,
   "novelty": "new",
   "withheld": false,
   "area": "benchmark / search-quality package (QualityQuery, TREC topic readers)",
   "title": "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!'",
   "summary": "You read a TREC topics file with TrecTopicsReader or Trec1MQReader (as QueryDriver does) whose ids are mostly numbers but include a few sub-topic ids such as 1a or 10.1, or a few digit-only ids larger than Integer.MAX_VALUE, and expect the topics back sorted by id, as the readers' '// sort result array (by ID)' comment says. Instead QualityQuery.compareTo compares two int ids as numbers and every other pair as strings, which forms cycles (2 < 100 as numbers, 100 < 1a and 1a < 2 as strings), so Arrays.sort can throw IllegalArgumentException 'Comparison method violates its general contract!' (the repro: ids 1..111 plus 1a, 20a, 64a and 99a, each listed after its parent); when the sort does not detect the cycle, the topics come back in an order that depends on the file order. Separately, the int branch returns n - nOther, which overflows for extreme ids such as 2147483647 vs -1 (this needs a negative id).",
   "impact_class": "crash",
   "introduced_commit": "98fa2d898d18, LUCENE-836 'Add support for search quality benchmarking' (migrated as apache/lucene#1911; SVN era, no PR): added QualityQuery.compareTo (n - nOther when both ids parse as int, else String.compareTo) and TrecTopicsReader's Arrays.sort(qq) under '// sort result array (by ID)'. Trec1MQReader, with the same Arrays.sort(qq), came in 9e65cd554f2 (LUCENE-1116, apache/lucene#2193), before 2.3.0 was tagged. Later edits to compareTo are cosmetic: a0776e5cd0a (2009, compareTo(Object) to compareTo(QualityQuery)), e2f54df3ca7 (2012, @Override), 7f8b7ffbcad (2021, reformatting), 2971f311a2b and ba7f659b1d8 (2021, 2025, catch-variable form). [read]",
   "introduced_date": "2007-07-27 (LUCENE-836, author date); Trec1MQReader's sort site 2008-01-03 (LUCENE-1116, author date)",
   "first_affected_version": "2.3.0 [exec] (tagged 2008-01-24), the first release with the quality package; 2.2.0 has no org.apache.lucene.benchmark.quality package [exec]. The comparator breaks the Comparable contract in every version; whether readQueries throws depends on the JDK's sort: with the pre-JDK-7 merge sort (-Djava.util.Arrays.useLegacyMergeSort=true) the readers return every topic without an exception, in an order that is not sorted [exec], so the exception needs JDK 7 or later, which every Lucene release since 4.8.0 requires",
   "affected_versions": "Every release from 2.3.0 to 10.6.0 (latest 9.x: 9.12.3; 10.6.0 [exec] on its release jars by the bug doc's tests, -ea and -da), branch_10_6 4ae946e5a9b (the 10.6.0 release revision) [read] and main a9779ef3c193 [exec]. A version-neutral main() repro (public API, 6 checks plus a control, -da) fails identically on 17 targets: 2.3.0, 2.3.2, 2.4.1, 2.9.4, 3.0.3, 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (main also with -ea); the all-int control passes everywhere, and the fix sketch shadowed on main passes all 6 checks [exec]. The finder's JUnit fails 2 of 2 on main a9779ef3c193 and ea57360912ed, 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 5 of 6 on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's fails 2 of 5 on main, 10.5.2 and 9.12.3 [exec]. Not fixed upstream: the three files were last changed by dbf0d1426f13 (#16056, author date 2026-05-14, an unrelated toArray change) on upstream main 645d4fe14a20 (2026-10-28). All runs on Linux aarch64 with JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-936.html",
   "repro": "repro/LFV-936/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-404",
   "priority": "low",
   "priority_rank": 639,
   "novelty": "new",
   "withheld": false,
   "area": "misc / index: BpVectorReorderer merge-time reordering (BPReorderingMergePolicy) over core / index: SortingCodecReader vector views",
   "title": "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()",
   "summary": "You pass a SortingCodecReader, for example the reader that BPIndexReorderer.reorder returns or SortingCodecReader.wrap(reader, docMap, null), to IndexWriter#addIndexes on a writer whose merge policy is BPReorderingMergePolicy with a BpVectorReorderer, and expect the documents to be added and reordered, as they are for plain segment readers and as the same policy does with the postings BPIndexReorderer. Instead addIndexes throws UnsupportedOperationException and adds nothing: the policy reorders addIndexes as a forced merge, BpVectorReorderer's per-thread state calls copy() on the input's float vector values, and SortingCodecReader's vector views throw from copy() (with several such readers in one call the throw comes through SlowCompositeCodecReaderWrapper's merged copy()). Making copy() work is not enough on its own: BpVectorReorderer then treats the sorting view's ordinals as doc order, so the reordering is silently applied in the wrong doc space.",
   "impact_class": "crash",
   "introduced_commit": "02a09f6ab124e994fd1af42965617c8b5ec67bcc, apache/lucene#14097 'HNSW BP reordering' (by msokolov, merged to main 2025-01-07, milestone 11.0.0, never backported): it added BpVectorReorderer, whose PerThreadState constructor calls vectors.copy() (BpVectorReorderer.java:110, unchanged since), and let BPReorderingMergePolicy take any IndexReorderer [exec]. Precondition, not the failure by itself: SortingFloatVectorValues.copy() and SortingByteVectorValues.copy() throw UnsupportedOperationException since 6053e1e3137 (apache/lucene#13779, 2024-09-28, a deliberate partial implementation; first released in 10.0.0); the float16 view's throw came with bfe5c847d3c (#16383, 2026-07-27, main only).",
   "introduced_date": "2025-01-07 (the latent copy() throw: 2024-09-28)",
   "first_affected_version": "unreleased (main only, 11.0.0-SNAPSHOT; CHANGES.txt lists GITHUB#14097 under 11.0.0; BpVectorReorderer.java is absent from all 16 9.12.x and 10.x release tags, from branch_10x and from branch_10_6 [read]); the first affected release would be 11.0.0 if nothing changes",
   "affected_versions": "main from 02a09f6ab12 (2025-01-07) to ea57360912ed (2026-10-24) [exec]; upstream main cf398bfb142c (2026-10-26) still has both halves [read]. Not affected: 9.12.3, 10.0.0, 10.1.0, 10.2.0 and 10.5.2 [exec]. The latent half, the float and byte sorting views' copy() throw, is in every 10.x release [read], but no released in-tree caller copies those views [read], and the closest released composition, BPReorderingMergePolicy with the postings BPIndexReorderer on a SortingCodecReader input, passes on 10.0.0, 10.1.0, 10.5.2 and main [exec].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-404.html",
   "repro": "repro/LFV-404/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1023",
   "priority": "low",
   "priority_rank": 640,
   "novelty": "new",
   "withheld": false,
   "area": "misc / vector BP reordering (BpVectorReorderer command line: in-place rewrite through IndexWriter.addIndexes)",
   "title": "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",
   "summary": "You run BpVectorReorderer.main(path, field) on an index written by Lucene 10.x or 9.x, or on any index that has a soft-deletes field, and expect it to reorder the vectors in place: its javadoc takes 'a path containing an index to reorder', and on main indexes created with 9.x and 10.x 'remain fully supported (open and write)'. Instead reorderIndexDirectory opens a new IndexWriter with new IndexWriterConfig() and OpenMode.CREATE, which records created major 11 and no soft-deletes field, so the first addIndexes(SortingCodecReader.wrap(leaf, ...)) throws IllegalArgumentException 'Cannot merge a segment that has been created with major version 10 into this index which has been created by major version 11' (branch_11x; on main, 12.0.0-SNAPSHOT since #16942, the numbers are 11 and 12) (or 'soft-deletes field is not configured in IWC'). The javadoc of IndexWriterConfig.setIndexCreatedVersionMajor names exactly this addIndexes restriction and its remedy (use the source's created major), which the tool does not apply.",
   "impact_class": "minor",
   "introduced_commit": "02a09f6ab124 (apache/lucene#14097 'HNSW BP reordering', by Michael Sokolov, GitHub msokolov; main only, milestone 11.0.0): it created BpVectorReorderer with main() and reorderIndexDirectory(), which already rewrote the index through new IndexWriterConfig() + OpenMode.CREATE; git blame of reorderIndexDirectory gives 02a09f6ab12 for every line [read]; the repro fails at 02a09f6ab12 (-ea and -da) and at the next functional change b7c7fe064ce (#14117), and its parent 72d93de50c2 has no BpVectorReorderer (compile error) [exec]. 8476457b875 (#16741, 'Lower min supported major version to 9 in main', 2026-10-15) widened the reach to 9.x-created indexes, which main could not open before [read]. Not a regression elsewhere: the created-major guard (LUCENE-7756, 2017), the soft-deletes guard (LUCENE-8335, 2018) and the documented remedy setIndexCreatedVersionMajor (LUCENE-8508, 2018) all predate the tool [read]",
   "introduced_date": "2025-01-07 (02a09f6ab12 author date = commit date; #14097 opened 2025-01-02); 9.x-created indexes affected since 2026-10-15 (#16741)",
   "first_affected_version": "unreleased (main 12.0.0-SNAPSHOT and branch_11x 11.0.0-SNAPSHOT: BpVectorReorderer.java blob f2b987b3a51 identical on both [read]): no release contains BpVectorReorderer; the repro does not compile on 9.12.3, 10.1.0, 10.2.0 or 10.5.2 (class absent) [exec], and branch_10x and branch_10_6 (from which 10.6.0 was released on 2026-10-29) do not have the file [read]. Unless fixed first, 11.0.0 ships with it",
   "affected_versions": "main from 02a09f6ab12 (2025-01-07) through 645d4fe14a20, the upstream main head on 2026-10-29 [exec]; the only later commits to BpVectorReorderer.java (b7c7fe064ce #14117, 54283150a81 #16255) do not touch reorderIndexDirectory [read]. Not affected (API absent): 9.12.3, 10.1.0, 10.2.0, 10.5.2 [exec], every 9.x and 10.x lucene-misc jar, branch_10x 657014b3c579, branch_10_6 and branch_10_5 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1023.html",
   "repro": "repro/LFV-1023/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-695",
   "priority": "low",
   "priority_rank": 641,
   "novelty": "new",
   "withheld": false,
   "area": "misc / index tools (IndexRearranger.execute: writer configs of the rearrange pass and the apply-deletes pass)",
   "title": "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",
   "summary": "You rearrange an index with IndexRearranger and pass an IndexWriterConfig that sets, for example, a codec, an index sort, OpenMode.CREATE or a soft-deletes field, and expect the rearranged index to be written and opened with those settings, as it was from 8.9.0 through 9.12.3. Instead, since 10.0.0 execute() builds both of its writers with new IndexWriterConfig(config.getAnalyzer()) and sets only NoMergePolicy, so the output silently uses the default codec and has no index sort, a second run with OpenMode.CREATE appends and fails with IllegalStateException ('Document selector ... has matched more than 1 segments'), and an input with a soft-deletes or parent field fails with IllegalArgumentException ('soft-deletes field is not configured in IWC', 'this IndexWriter has no parent document field configured').",
   "impact_class": "minor",
   "introduced_commit": "369a70f28948e748ed157c0731f36c367c4a03fa ('Support deletions in rearrange', apache/lucene#11815, closes issue #11814; author @stefanvodita, reviewed by @zhaih and @mikemccand, merged by @zhaih; main only, never backported to branch_9x) [exec]",
   "introduced_date": "2022-11-22",
   "first_affected_version": "10.0.0 [exec]; the class itself dates from 8.9.0 (LUCENE-9694, e4cede0e8c5), and from 8.9.0 through 9.12.3 execute() opened its writer with the caller's config",
   "affected_versions": "every release from 10.0.0 through 10.5.2 and main a9779ef3c193 through 645d4fe14a2 (unreleased 11.0) [exec]; branch_10x 657014b3c57 and branch_10_6 4ae946e5a9b (10.6.0, released 2026-10-29) have the same IndexRearranger.java (:119-120) [read]; the bug doc's minimal test fails on the 10.6.0 release jars with -ea and -da [exec]; main 645d4fe14a2 re-run 2026-10-29: 4 of 4 fail with -ea and -da [exec]. Not affected [exec]: 8.9.0, 8.11.4 and all 21 releases 9.0.0 to 9.12.3 pass the 9.x-API variants with the same assertions (9.4.2 and 9.12.3 also -da); 8.8.2 and older have no IndexRearranger (compile error)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-695.html",
   "repro": "repro/LFV-695/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-618",
   "priority": "low",
   "priority_rank": 642,
   "novelty": "new",
   "withheld": false,
   "area": "misc / index tools (MultiPassIndexSplitter.split, output IndexWriterConfig); IndexWriter.addIndexes field-role checks",
   "title": "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",
   "summary": "You split an index with MultiPassIndexSplitter, for example one written with IndexWriterConfig#setSoftDeletesField(\"soft\") and a single softUpdateDocument call, or one written with IndexWriterConfig#setParentField(\"_parent\"), and expect it to split like any other index: the split() javadoc says the source 'can have deletions, can have multiple segments (or multiple readers)', and the only documented limitation is that document blocks may be broken up. Instead split() opens every part's IndexWriter with new IndexWriterConfig(null), which names no soft-deletes or parent field and cannot be replaced by the caller, so IndexWriter.addIndexes rejects the input's field infos with IllegalArgumentException ('this index has [soft] as soft-deletes already but soft-deletes field is not configured in IWC', or 'can't add field [_parent] as parent document field; this IndexWriter has no parent document field configured') and nothing is split.",
   "impact_class": "minor",
   "introduced_commit": "Two halves, each introduced by a core change that began checking a field role against the writer's config; neither touched lucene/misc, and the splitter's fixed output config was not adapted. (1) Soft deletes: LUCENE-8335 'Enforce soft-deletes field up-front' (apache/lucene#9382, 'Do not allow changing soft-deletes field'), e7a0a12926c399758a4021715a7419e22e59dab6 on master and 67b6593e7adbce76532e285cef42118e6cc3448f on branch_7x, both 2018-06-04 (a first landing a2d92766741 on 2018-06-02 was reverted the same day by 3dc4fa199c1) [exec]. (2) Parent field: apache/lucene#12829 'Add support for index sorting with document blocks', df6bd25ce44ead0b38cffca6ef9bc3a9ce63dbea on main and 0aa88910ca9a1032d288996d14203eac4953f2de on branch_9x, both 2024-01-11; it added IndexWriterConfig#setParentField and the rejection together [read]. The splitter's own config is older and unchanged: a default IndexWriterConfig since LUCENE-2294 (2010) and 'new IndexWriterConfig(null).setOpenMode(CREATE)' since LUCENE-5871 (2014), only reformatted since [read]",
   "introduced_date": "2018-06-04 (soft-deletes half, LUCENE-8335); 2024-01-11 (parent-field half, #12829)",
   "first_affected_version": "7.4.0 (tagged 2018-06-22) for soft deletes [exec]: it is the first release with soft deletes at all, so no released version ever split a soft-deletes index (the two-month window in which the split worked, executed at 6f6b7f57edd, was never released); 9.10.0 (tagged 2024-02-20) for the parent field [exec], the first release with IndexWriterConfig#setParentField. 7.3.1 and 9.9.2 lack the respective APIs (compile errors) [exec]",
   "affected_versions": "Soft-deletes half: every release from 7.4.0 to 10.5.2, plus main a9779ef3c193; parent-field half: 9.10.0 to 10.5.2, plus main; never fixed (MultiPassIndexSplitter.java last changed upstream on 2026-06-14 by #16255, a build-check change; upstream main a95c754ee003 checked read-only on 2026-10-26). [exec] by the follow-up's history runs, each with a passing plain-index control in the same JVM: 7.4.0 (-ea and -da), 7.7.3, 8.0.0, 8.11.4 and 9.9.2 (soft-deletes half), 9.10.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da; both halves); the independent reproduction's own JUnit also fails on 10.5.2 and 9.12.3, and the intended-behaviour check's probe on 10.5.2. [read] the releases in between share the code path (release membership from git tag --contains; 8.9.0-8.11.4 are not tagged in the history clone; 8.11.4 itself was executed). The rejection site moved without a change in behaviour: up to 9.3.x inside the addIndexes merge (FieldInfos$FieldNumbers.addOrGet), since LUCENE-10216 (9.4.0) up front in addIndexes (FieldNumbers.verifyFieldInfo); same message [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-618.html",
   "repro": "repro/LFV-618/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1071",
   "priority": "low",
   "priority_rank": 643,
   "novelty": "new",
   "withheld": false,
   "area": "classification / utils: DatasetSplitter (split, createNewDoc all-fields copy of a stored binary value)",
   "title": "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",
   "summary": "You split an index into training, test and cross-validation indexes with DatasetSplitter.split and leave fieldNames out, which the javadoc documents as 'all [fields] should be used', and a document of the source index has a stored binary field such as new StoredField(\"payload\", new byte[] {1, 2, 3}). You expect the split to succeed and keep the bytes; createNewDoc even has a branch written for binary values. Instead split() throws an IOException wrapping IllegalArgumentException 'cannot set a BytesRef value on a tokenized field', because every copied field gets the indexed, tokenized type TextField.TYPE_STORED and the core Field constructor refuses a BytesRef value on such a type, so no split of such an index is possible in that mode.",
   "impact_class": "minor",
   "introduced_commit": "3459b28334e2f3103336c0485b3f21da6dbaeeb9 (trunk, svn r1415060, 2012-11-29, '[LUCENE-4345] - added utility class for creating training / test / cv index from a single index'; no PR, it predates GitHub PRs; the issue is LUCENE-4345 = #5411, which never discusses binary stored fields). The very first DatasetSplitter already rebuilt every copied field with new FieldType(TextField.TYPE_STORED) (indexed, tokenized) and had the branch 'else if (storableField.binaryValue() != null) doc.add(new Field(storableField.name(), storableField.binaryValue(), ft))', and Field(String, BytesRef, FieldType) already threw 'Fields with BytesRef values cannot be indexed' for an indexed type, so the branch could never succeed. Released through the branch_4x backport 21e86983ed427f19cac6c38970f19d743980c735 (svn r1448105, 2013-02-20, 'LUCENE-4781 - backporting classification module to branch_4x', = #5846), which carries the same branch [read]. Not a regression. Later commits only reformatted, renamed or moved the branch: c83fac62889 (LUCENE-4345, 2012-12-10, reformat), 24c46305bd8 (LUCENE-6971, StorableField to IndexableField), 112078eaf90 (LUCENE-7196, moved into createNewDoc); 7f8b7ffbcad (LUCENE-9570) and 47f8c1baa2e (#11998, StoredFields) changed createNewDoc but not the branch lines. Two core changes moved the throw site and the message, not the outcome: LUCENE-5989 (trunk 249d0d25fec, branch_5x fd23211957a, first released in 5.2.0) dropped the constructor check, so IndexWriter.addDocument failed instead; #12053 (9ab324d2bed, 2023-01-12, main only, first released in 10.0.0) added the constructor check 'cannot set a BytesRef value on a tokenized field'.",
   "introduced_date": "2012-11-29 (trunk commit 3459b28334e); release line: backport 21e86983ed4 on 2013-02-20; first released in 4.2.0 (tagged 2013-03-11)",
   "first_affected_version": "4.2.0 [exec] (2013-03-11, the first release that ships the classification module and DatasetSplitter). There is no last unaffected release: 4.1.0 has no DatasetSplitter (no lucene/classification module in releases/lucene-solr/4.1.0 [read]; lucene-classification 4.1.0 does not exist on Maven Central, HTTP 404 [exec]).",
   "affected_versions": "Every release that has DatasetSplitter, 4.2.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b), and main 645d4fe14a20; not fixed. [exec] fails in all three eras of the failure, only the message and throw site differ: 4.2.0-5.1.0 'Fields with BytesRef values cannot be indexed' at the Field constructor (executed 4.2.0, 4.10.4, 5.0.0, 5.1.0); 5.2.0-9.12.3 'Field must have either TokenStream, String, Reader or Number value; got stored,indexed,tokenized<payload:[1 2 3]>' from Field.tokenStream during IndexWriter.addDocument (executed 5.2.0, 5.5.5, 6.0.0, 6.1.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3; the first lead also ran 9.4.2 and 9.5.0); 10.0.0 onwards 'cannot set a BytesRef value on a tokenized field' at Field.<init> from createNewDoc:199 (executed 10.0.0, 10.5.2, 10.6.0, main 645d4fe14a20). The one-test repro fails on main with -ea and -da, on 10.6.0 (-da; the independent reproduction's own test with -ea), 10.5.2 (-da) and 9.12.3 (-da); the history probe (a main() with the same scenario) covers the other releases with -ea. [read] all 120 release tags 4.2.0-10.6.0 in the history clone contain the binary branch with the TextField.TYPE_STORED copy type (8.8.2-8.11.x are not in the clone; 8.11.4 was executed); upstream main f815e679bf6 (2026-11-01) and branch_10_6 7e5aec4370e have a DatasetSplitter.java identical to 645d4fe14a20. Not new in 10.6. All runs on Linux aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1071.html",
   "repro": "repro/LFV-1071/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-223",
   "priority": "low",
   "priority_rank": 644,
   "novelty": "new",
   "withheld": false,
   "area": "join / ToParentBlockJoinSortField string sort (ToParentDocValues missing-child ordinals, since #15727)",
   "title": "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",
   "summary": "You sort parent documents by a string field of their children, descending, with new ToParentBlockJoinSortField(\"s\", STRING, reverse=true, null, SortField.STRING_LAST, parents, children) (or the 8-argument form with reverseChildren=true), and expect the search to return the parents with children that lack the field sorted as missing-last, because the javadoc lists STRING_LAST as a legal child missing value that 'participates in the min/max selection among siblings'. Instead, as soon as the search collects a parent that has one child with the field and another child without it, it throws IndexOutOfBoundsException from the doc-values terms dictionary (Lucene90DocValuesProducer$TermsDict.seekExact via ToParentDocValues$SortedDVs.lookupOrd), with -ea and -da. The cause is that the block-join wrapper reports 'a missing child, sorted last, won the max' as the ordinal Integer.MAX_VALUE, and the string comparator TermOrdValComparator treats every ordinal other than -1 as a real one and looks it up.",
   "impact_class": "crash",
   "introduced_commit": "167503f6d84d8e43db4ec6ae3baf17337290393f on main (apache/lucene#15727 'Fix incorrect handling of missing values in ToParentBlockJoinSortField (#15548)', by gmarouli, merged by romseygeek; closes issue #15548), with the 10.x backport 0915f9cac549 (reachable from releases 10.5.0, 10.5.1, 10.5.2 and 10.6.0; its three join files are blob-identical to 167503f6d84's) [read]; the childMissingValue constructors arrived in the same commit, so the defect was in the option's first version; ToParentDocValues.SortedDVs.lookupOrd, which passes the ordinal through, is unchanged since 706d2018153d (LUCENE-7871, 2017)",
   "introduced_date": "2026-03-03",
   "first_affected_version": "10.5.0 [exec]",
   "affected_versions": "10.5.0, 10.5.1 and 10.5.2 (the last release before 10.6.0), 10.6.0 (by reading, see the branch_10_6 check below) and main (11.0.0-SNAPSHOT) through ea57360912ed [exec]; branch_10x (unreleased) and branch_10_6 (the branch of 10.6.0, released 2026-10-29) carry the identical join files and TermOrdValComparator.copy on branch_10_6 still maps only -1 to missing [read]; not applicable: 10.4.0 and 9.12.3 [exec], and every older release [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-223.html",
   "repro": "repro/LFV-223/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-121",
   "priority": "low",
   "priority_rank": 645,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / HnswBitVectorsFormat x index / IndexingChain aborting-exception classification",
   "title": "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",
   "summary": "You use HnswBitVectorsFormat, which accepts only byte vectors, and by mistake add a document with a float vector field (KnnFloatVectorField) that is new to the index. You expect addDocument to reject that one document with IllegalArgumentException and the writer to stay open, as the format's own test TestHnswBitVectorsFormat#testFloatVectorFails expects the exception and as happens for the same codec's dimension limit and for a vector dimension mismatch. Instead the check sits in KnnVectorsWriter#addField, which IndexingChain calls after registering the field and treats as an aborting step, so the exception also becomes the writer's tragic exception: IndexWriter closes itself, the next call throws AlreadyClosedException, and the documents added since the last commit are gone (the repro ends with 1 committed document instead of 3).",
   "impact_class": "crash",
   "introduced_commit": "3d86ff2e6a72 (#13288 'Add BitVectors format and make flat vectors format easier to extend', by benwtrent; branch_9x backport d8a814762623, #13316), which added FlatBitVectorsWriter#addField with the BYTE-only IllegalArgumentException [read]; the other half of the root cause is older and was latent until then: ba4bc0427146 (#992, LUCENE-10592 'Build HNSW Graph on indexing', by mayya-sharipova; branch_9x a65a41855c7, #1043; first released in 9.4.0) put vectorValuesConsumer.addField after fieldInfos.add inside catch (Throwable) -> onAbortingException [read]",
   "introduced_date": "2024-04-17 (#13288 merged into main as 3d86ff2e6a72); 2024-04-22 (#13316, branch_9x); the aborting catch dates from 2022-07-22 (#992); 9.11.0 tagged 2024-06-06",
   "first_affected_version": "9.11.0 [exec]; on the main line 10.0.0 [exec]",
   "affected_versions": "all 18 releases that ship the format: 9.11.0, 9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2, and main ea57360912ed (unreleased 11.0.0) [exec]; the other 13 releases (9.12.0-9.12.2, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0, 10.5.1) [read]; branch_10x (1309534296e) and branch_10_6 (2763db11b0a) have the same code [read]; on main only, VectorEncoding.FLOAT16 (#16383) is a second trigger [exec]; 9.10.0 and older are not affected because the format does not exist (compile error on 9.10.0 [exec]); not fixed upstream as of main ea57360912ed [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-121.html",
   "repro": "repro/LFV-121/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-281",
   "priority": "low",
   "priority_rank": 646,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexingChain inversion with custom term frequencies (TermVectorsConsumerPerField, FreqProxTermsWriterPerField) x aborting-exception classification",
   "title": "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",
   "summary": "You index a document whose analysis chain sets a custom term frequency (TermFrequencyAttribute, for example DelimitedTermFrequencyTokenFilter with a token like 'red|2') on a field that also stores term-vector positions or offsets, indexes postings positions (a default TextField), or is DOCS-only and repeats the term. You expect addDocument to reject only that document with its usual IllegalArgumentException or IllegalStateException and the writer to stay open, as it does for the neighbouring offset checks and for the duplicate-term check that #15584 made non-aborting. Instead the four checks run inside termsHashPerField.add, which IndexingChain treats as aborting, so the rejection also becomes the writer's tragic exception: IndexWriter closes itself, the next call throws AlreadyClosedException, and everything since the last commit is lost (the repro ends with 1 committed document instead of 3).",
   "impact_class": "crash",
   "introduced_commit": "d276acfbbcb8ea6124fe486e35cea9eb928e4702, 'LUCENE-7854: enable indexing custom term frequencies' by mikemccand (JIRA-patch workflow, issue migrated to #8905; no GitHub PR), which created TermFrequencyAttribute together with all four rejection checks: TermVectorsConsumerPerField.getTermFreq (term-vector positions, term-vector offsets), FreqProxTermsWriterPerField.getTermFreq (postings positions) and the !hasFreq check in FreqProxTermsWriterPerField.addTerm (DOCS-only, repeated term) [read]. All four run inside termsHashPerField.add, which DefaultIndexingChain already wrapped as aborting in the parent commit (catch (Throwable th) { throw AbortingException.wrap(th); }), and LUCENE-5987 (5.0.0) had made aborting exceptions close the writer; LUCENE-8205 later replaced AbortingException.wrap with onAbortingException with identical behaviour [read]. The defect is the placement of the checks, present since the feature was created; isolation is by API absence (the probe cannot compile on 6.6.0 or 6.6.6, TermFrequencyAttribute being the only missing symbol)",
   "introduced_date": "2017-06-06 (d276acfbbcb committed; #8905 / LUCENE-7854 opened 2017-05-26, closed 2017-06-06); 7.0.0 tagged 2017-09-08",
   "first_affected_version": "7.0.0 [exec]; 6.6.6 and older lack the API [exec]",
   "affected_versions": "every release from 7.0.0 to 10.5.2 and main ea57360912ed (11.0.0-SNAPSHOT) [exec]; every release tag 7.0.0..10.5.2 in the history clone contains d276acfbbcb [read]; on 10.5.0 and later (#15584) also with the purpose-built IndexOptions.DOCS_AND_CUSTOM_FREQS plus term-vector offsets [exec]; branch_10x and branch_10_6 not checked; not affected: 6.6.6 and older (API absent) [exec]; not fixed upstream as of main ea57360912ed (no upstream commit to the four files after it, checked 2026-10-26) [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-281.html",
   "repro": "repro/LFV-281/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1189",
   "priority": "low",
   "priority_rank": 647,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexingChain inversion, term-doc (DOCS_AND_CUSTOM_FREQS) duplicate-term rejection (TermsHashPerField.add) x aborting-exception classification",
   "title": "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)",
   "summary": "You index binary terms into a field with IndexOptions.DOCS_AND_CUSTOM_FREQS, which allows each term only once per document, and one document repeats a term that is not valid UTF-8, for example new BytesRef(new byte[] {(byte) 0xC3}) added twice as an untokenized Field. You expect addDocument to reject only that document with the non-aborting IllegalArgumentException 'Document update skipped due to duplicate termdoc term' and the writer to stay open, as happens for an ASCII or valid UTF-8 term and as the upstream test TestCustomTermFreq.testRepeatedTerms asserts. Instead TermsHashPerField.add builds the rejection message with termBytes.utf8ToString(), which throws ArrayIndexOutOfBoundsException for these bytes; the indexing chain treats that as an aborting failure, so IndexWriter closes itself and every uncommitted document is lost.",
   "impact_class": "crash",
   "introduced_commit": "5158a52a082b842c29918c8b955323d2a0848eb5 on main, 'Added DOCS_AND_CUSTOM_FREQS whose 'length' is docFreq (#15584)' by msokolov (PR #15584, 'Compute 'length' of fields with custom term frequencies as docFreq', milestone 10.5.0), cherry-picked to branch_10x as 3a55cc9ac5e96e39a75e837e326085c5efdc894d; the same diff added IndexOptions.DOCS_AND_CUSTOM_FREQS, the DuplicateTermException throw in FreqProxTermsWriterPerField, the non-aborting DuplicateTermException catch in IndexingChain.invertTokenStream and the termBytes.utf8ToString() message decoration in TermsHashPerField.add, so the bug is as old as the feature [read]",
   "introduced_date": "2026-04-24 (author date 2026-04-24T13:07:17Z, merged the same minute; the branch_10x cherry-pick was committed 2026-04-24 09:34:18 -0400); first release 10.5.0",
   "first_affected_version": "10.5.0 [exec]; 10.4.0 and older, all 9.x included, lack the API [exec]",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2, 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT) [exec]; not affected: 10.4.0 and all 9.x, latest 9.12.3 (API absent) [exec]; TermsHashPerField.java lines 199-205 are byte-identical at 10.5.0, 10.6.0 and main, and only the throwing line in UnicodeUtil.UTF8toUTF16 moves (647 in 10.5.x, 650 in 10.6.0, 649 on main) [read]; not new in 10.6 (10.5.x fails); not fixed upstream as of main 1c2072f0284 (author date 2026-11-02), whose last commit on TermsHashPerField.java is still 5158a52a082 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1189.html",
   "repro": "repro/LFV-1189/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1170",
   "priority": "low",
   "priority_rank": 648,
   "novelty": "new",
   "withheld": false,
   "area": "document / stored values (Field.storedValue, StoredField)",
   "title": "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)",
   "summary": "You add a document holding new StoredField(\"f\", new StringBuilder(\"x\"), StoredField.TYPE) to an IndexWriter; you expect the value to be stored and read back as \"x\", since the public constructor takes a CharSequence and Lucene 7.7.0 to 9.5.x did exactly that. Instead addDocument throws IllegalStateException 'Cannot store value of type class java.lang.StringBuilder', because Field.storedValue(), added in 9.6.0 by #12116, has a text branch for String only and sends every other CharSequence to its error branch. The same happens for a Field with a stored type such as TextField.TYPE_STORED over a StringBuilder or CharsRef; only that document is rejected, and value.toString() works around it.",
   "impact_class": "minor",
   "introduced_commit": "96136b42821205e942f21a26c4992530c6909aca on main and its branch_9x cherry-pick 84dcaa850b1646ea50de8292e8993a3dd382cc2c: apache/lucene#12116 'Improve document API for stored fields.' (author @jpountz; CHANGES.txt credits Adrien Grand and Robert Muir). It added Field.storedValue() with arms for Integer, Long, Float, Double, BytesRef and exactly String, throwing IllegalStateException otherwise, and IndexingChain began storing storedValue() instead of letting the stored-fields writer take stringValue(), which converts any CharSequence [read] [exec]. Later commits kept the String-only branch: f12e44b6515 (#14213, added the StoredFieldDataInput arm) and 1518164afa3 (#15874, main only, rewrote the chain as a pattern switch, same arms). The CharSequence constructors themselves came from c651cbfd9a8 (SOLR-12885, first release 7.7.0), which stored such values through stringValue().",
   "introduced_date": "2023-02-06 (author date of 96136b42821 and of the branch_9x cherry-pick 84dcaa850b1, 2023-02-06T16:08:13Z; PR #12116 merged 2023-02-06T16:08:14Z)",
   "first_affected_version": "9.6.0 [exec] [read]",
   "affected_versions": "9.6.0 through 9.12.3, 10.0.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b), and main 5adff78bb168 (12.0.0-SNAPSHOT) [read] [exec]. Not affected [exec]: 9.5.0 (repro passes with -ea and -da), 8.11.4 and 7.7.0 (a main() probe of the same steps stores the value and reads it back); 7.6.0 and earlier have no CharSequence constructor (compile error). Not fixed upstream: main tip 1c2072f0284 (2026-11-02) still has only 'case String s' before the default branch at Field.java:620-622, and no open PR touches Field.java, StoredField.java or StoredValue.java. Not new in 10.6. All runs used JDK 25.0.3 on one aarch64 Linux host.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1170.html",
   "repro": "repro/LFV-1170/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1229",
   "priority": "low",
   "priority_rank": 649,
   "novelty": "new",
   "withheld": false,
   "area": "core / document column batch indexing: IndexWriter#addBatch, BinaryColumnAdapter invertable type (experimental column API)",
   "title": "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)",
   "summary": "You give an untokenized FieldType DOCS_AND_FREQS_AND_POSITIONS (or term vectors with positions) and index the value \"x\" through IndexWriter#addBatch with a BinaryColumn or DictionaryColumn, and expect what addDocument(new Field(\"f\", new BytesRef(\"x\"), type)) does with the same type: one token at position 0. Instead addBatch throws IllegalArgumentException 'Fields that are tokenized or index proximity data must produce a non-null TokenStream, but f did not' in its row pass, after ColumnValidation accepted the type. The internal BinaryColumnAdapter picks the single-term InvertableType.BINARY path from tokenized() alone and returns no TokenStream, and IndexingChain.invertTerm allows BINARY only without proximity data, whereas Field always wraps an untokenized value in a one-token stream.",
   "impact_class": "minor",
   "introduced_commit": "3d89568155799e2e1efe132f67967d9725f4bd60 'Add experimental columnar indexing api (#15990)' by Tim Brooks on main; release-line copy 3ec3bff01b157ea18e87dd73649abe71089704d9 ('Add experimental columnar indexing api (#15990) (#16066)', branch_10x, same day, identical ColumnFieldAdapter.java blob bf2610aeda6) [read]. The commit created the column API and wrote BinaryColumnAdapter.invertableType() as 'tokenized ? TOKEN_STREAM : BINARY' with a null tokenStream() for untokenized values; that code is unchanged since. The DictionaryColumn route through the same adapter came with #16101 (main e79c6780627, branch_10x 8a9e55f254d). The invertTerm guard that throws is older and correct on its own (cce33b07e4f, #12139, Adrien Grand, 2023-02-21, in 9.6.0 and later)",
   "introduced_date": "2026-05-14 (author date 2026-05-14T04:12:44-06:00 on main; branch_10x copy 2026-05-14T10:19:30-06:00; DictionaryColumn route 2026-05-26); first release 10.5.0",
   "first_affected_version": "10.5.0 [exec] (the first release with the column API; 10.4.0 and every earlier release have no IndexWriter#addBatch, so the repro does not compile there [exec])",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2, 10.6.0 (4ae946e5a9b) and main 5adff78bb168 (-ea and -da), executed with the finder's one-test repro [exec]; the independent reproduction's own test also fails on 10.6.0 and 10.5.2 [exec]; the same line is at the upstream heads of branch_11x and branch_10_6 [read]. Not affected: 10.4.0 and earlier, all 9.x (API absent; compile error on 10.4.0 and 9.12.3 [exec]). Not fixed upstream: upstream main 1c2072f0284 (author date 2026-11-02) still has 'return tokenized ? InvertableType.TOKEN_STREAM : InvertableType.BINARY;' at ColumnFieldAdapter.java:249 [read]. Not new in 10.6 (already in 10.5.0).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1229.html",
   "repro": "repro/LFV-1229/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1154",
   "priority": "low",
   "priority_rank": 650,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexingChain inversion (FieldInvertState.setAttributeSource attribute cache)",
   "title": "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",
   "summary": "You add a document whose field value is your own TokenStream ending in two removed stop words ('x the the' through StopFilter), then a document whose analysis fails because your analyzer's AttributeFactory throws when IndexWriter asks for TermFrequencyAttribute, then the plain-text document 'a b' through the same analyzer with the factory working again. You expect the failed document to be dropped and 'a b' to be indexed at positions 0 and 1, as it is without the failure. Instead 'a b' is accepted at positions 1 and 3 and PhraseQuery f:\"a b\" finds nothing, with no error, because FieldInvertState.setAttributeSource recorded the analyzer's reused stream as cached before it fetched that stream's attributes, so every later document of the field keeps reading the first stream's position increment (frozen at 2) until the next flush.",
   "impact_class": "minor",
   "introduced_commit": "e7b59c5a2115678ccf258d36f22d909144398834 'LUCENE-5611: move attribute juggling to a fieldinvertstate setter' (Robert Muir, GitHub rmuir; svn r1590747 on the lucene5611 feature branch; JIRA-patch era, no GitHub PR; the issue is migrated as apache/lucene#6673), merged to trunk in f5de5d01e810 and to branch_4x in eb045b5a8537 ('LUCENE-5611: simplify the default indexing chain', Michael McCandless). It moved the inline attribute cache of DefaultIndexingChain.invert, which stored the stream identity as its last statement (67ebc26fa97, kept by f0414ff3af7), into FieldInvertState.setAttributeSource and made the identity assignment the first statement, done as a review cleanup ('Can we factor this into FieldInvertState?', rmuir on #6673) with no discussion of exceptions [exec]. Later edits kept the order: d276acfbbcb (LUCENE-7854, #8905, 7.0.0) added the TermFrequencyAttribute lookup that the one-test repro fails, and cce33b07e4f (#12139, 2023) added the null branch.",
   "introduced_date": "2014-04-28 (author and commit date of e7b59c5a211, 18:55:37Z); merged to trunk 2014-04-29T17:18:41Z and branch_4x 2014-04-29T21:46:51Z; first release 4.9.0 (tag commit dated 2014-06-24)",
   "first_affected_version": "4.9.0 [exec]",
   "affected_versions": "Every release from 4.9.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT); never fixed. [exec] The one-test JUnit, unchanged, fails on 9.1.0, 9.12.3 and 10.6.0 and on main with -ea and -da (it needs the test framework of 9.1.0 and later); the independent reproduction's own test fails on main (-ea, -da), 10.6.0, 10.5.2 and 9.12.3; the follow-up's main() probe (same scenario in one API spelling per era) reproduces on 4.9.0 (-ea and -da), 4.10.4, 5.5.5, 6.6.6, 7.0.0, 7.7.3, 8.11.4, 9.12.3, 10.6.0 and main (-ea and -da) and does not on 4.8.1 or on the parent commit f0414ff3af7. The exact trigger of the repro (the factory fails the TermFrequencyAttribute request) exists from 7.0.0 (LUCENE-7854); on 4.9.0 to 6.6.6 the same root cause is reached through the PositionIncrementAttribute request with a tokenizer that does not add that attribute itself [exec]. Releases between executed ones: by reading, all 106 release tags from 4.9.0 to 10.6.0 in the history clone have the identity-first setter (the clone has no 8.x tags after 8.8.1; the executed 8.11.4 jar reproduces). Not new in 10.6 (10.5.2 and older fail). Not fixed upstream: upstream main 1c2072f02843 (2026-11-02) and branch_10_6 still assign the identity at FieldInvertState.java:98 before the addAttribute calls, and the file's last upstream commit is cce33b07e4f (#12139, author date 2023-02-21) [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1154.html",
   "repro": "repro/LFV-1154/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1135",
   "priority": "low",
   "priority_rank": 651,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexingChain inversion with custom term frequencies (TermFrequencyAttribute, FreqProxTermsWriterPerField)",
   "title": "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",
   "summary": "You index a document through a TokenStream whose TermFrequencyAttribute is your own implementation (plugged in with AttributeSource.addAttributeImpl or an AttributeFactory) and that reports a frequency of 0 for a token, on a field indexed with DOCS_AND_FREQS. You expect IndexWriter to reject that document with an IllegalArgumentException, as it does for a negative position increment, backwards offsets or too many tokens, or at least never to write an index that its own CheckIndex calls broken. Instead the 0 goes into the postings unchecked: with assertions off addDocument and commit succeed and CheckIndex then reports 'term [66 6f 6f]: doc 0: freq 0 is out of bounds' and 1 broken segment, and if the term's only document has frequency 0, the commit instead throws 'cannot write negative vLong (got: -1)', which closes the writer and loses every uncommitted document.",
   "impact_class": "minor",
   "introduced_commit": "d276acfbbcb8ea6124fe486e35cea9eb928e4702 'LUCENE-7854: enable indexing custom term frequencies' by mikemccand (JIRA-patch workflow, issue migrated as #8905; no GitHub PR) [read]. It added TermFrequencyAttribute (its javadoc states no range), put the only lower-bound check into the two stock setters (TermFrequencyAttributeImpl and PackedTokenAttributeImpl: 'Term frequency must be 1 or greater') and made FreqProxTermsWriterPerField store whatever getTermFrequency() returns as the posting frequency; the indexing chain only adds the value to the field length (upper bound only; the follow-up 6c3ece2b9f9, 2017-06-07, turned the overflow into 'too many tokens'). Before it every occurrence counted 1, so a frequency of 0 could not occur. Not a regression: the -ea-only assert at FreqProxTermsWriterPerField:143 (c40b0375603b, rmuir, 2012) predates the feature, and #12139 (cce33b07e4f, 9.6.0, null guard) and #15584 (5158a52a082, 10.5.0, DOCS_AND_CUSTOM_FREQS length branch) changed the code nearby without adding a lower bound.",
   "introduced_date": "2017-06-06 (author and committer date of d276acfbbcb); first release 7.0.0 (tag 2017-09-08)",
   "first_affected_version": "7.0.0 [exec]; 6.6.6 and older lack the API [exec]",
   "affected_versions": "Every release from 7.0.0 (2017) through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT); never fixed. [exec] a core-only main() variant (same two documents, commit, CheckIndex) fails on 7.0.0 (-da and -ea), 7.7.3, 8.11.4 and 9.0.0 (-da), because releases before 9.1.0 lack today's test framework; the one-test JUnit unchanged fails on 9.1.0, 9.12.3 and 10.0.0 (-da) and on 10.6.0 and main (-ea and -da); the independent reproduction's own test fails on main, 10.6.0, 10.5.2 and 9.12.3 (-ea and -da); the intended-behaviour check's own test fails on main (-ea and -da) and 10.6.0 (-da); re-run on main 2026-11-02 fails with -ea and -da. Not new in 10.6 (10.5.2 and every earlier executed release fail). Not fixed upstream: upstream main 1c2072f02843 (2026-11-02) has no commit since 2026-10-25 on FreqProxTermsWriterPerField.java or TermFrequencyAttribute.java and only a9779ef3c19 (#16734, columnar vectors) on IndexingChain.java [read]. DOCS_AND_CUSTOM_FREQS (10.5.0 and later) uses the same getTermFreq() path [read], not executed.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1135.html",
   "repro": "repro/LFV-1135/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1218",
   "priority": "low",
   "priority_rank": 652,
   "novelty": "new",
   "withheld": false,
   "area": "core / index: SlowCompositeCodecReaderWrapper (merged CodecReader view handed to OneMerge#reorder), term vectors",
   "title": "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)",
   "summary": "You write a merge policy whose OneMerge#reorder clones the term-vectors reader of the merged view it receives, and merge (or addIndexes) a segment with term vectors together with one in which no document has a term-vector field, expecting a reader that returns the first segment's term vectors, as the uncloned reader does. Instead clone() throws NullPointerException at SlowCompositeCodecReaderWrapper.java:233: the view stores a null sub-reader for the segment without term vectors (:206-213), and clone() maps TermVectorsReader::clone over that array (:230-235) without the null check that get, prefetch and checkIntegrity have and that close gets from IOUtils.close. On the merge path the exception closes the IndexWriter as a tragic event, and it fails the same way after a reopen.",
   "impact_class": "minor",
   "introduced_commit": "f7cab1645017d863331b42900581b67d3591e2da (main; squash-merge of apache/lucene#12622 'Add a merge policy wrapper that performs recursive graph bisection on merge.' by Adrien Grand (jpountz), parent 76fe6bdbc16); the same change is on branch_9x as 6b1538b33136a4737ad0d22b3633e62f3d7f362b (same author and author date), which 9.9.0 contains. That one change creates SlowCompositeCodecReaderWrapper with the unguarded clone() next to the null-checked get() and checkIntegrity() and the null-skipping close(), and adds OneMerge#reorder [read]. Not a regression: the trigger API arrived with the defect. Later commits on the file (24 on main, e.g. #13758 adding a null-guarded prefetch, #13289 adding the Executor parameter to reorder) never touched clone().",
   "introduced_date": "2023-11-23 (author date = commit date 2023-11-23T13:25:00+01:00 on main; the branch_9x commit 6b1538b3313 was committed 23 s later)",
   "first_affected_version": "9.9.0 [exec] (tag 2023-12-04; fails with -ea and -da, run with a copy of the test that differs only in the two-argument reorder(CodecReader, Directory) signature that 9.9.0-9.11.x have); 9.8.0 has no SlowCompositeCodecReaderWrapper and no OneMerge#reorder [exec]",
   "affected_versions": "9.9.0 through 10.6.0 (4ae946e5a9b) and unreleased main 5adff78bb168 (12.0.0-SNAPSHOT): 9.9.0-9.9.2, 9.10.0, 9.11.0-9.11.1, 9.12.0-9.12.3, 10.0.0-10.6.0 [read]. [exec] fail: main 5adff78bb168 with -ea and -da, 10.6.0 (-ea and -da), 10.5.2, 10.0.0, 9.12.3, 9.12.0, 9.11.1 and 9.9.0 (-ea and -da; 9.9.0 and 9.11.1 with the two-argument reorder copy). Not run: 9.9.1, 9.9.2, 9.10.0, 9.11.0, 9.12.1, 9.12.2 and 10.1.0-10.5.1 (identical line by reading each tag). Not fixed upstream: the line is unchanged on upstream main 1c2072f0284 (2026-11-02), branch_11x, branch_10_6 and branch_9_12. Not new in 10.6 (9.9.0 and 10.5.2 fail). All runs used JDK 25.0.3 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1218.html",
   "repro": "repro/LFV-1218/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-375",
   "priority": "low",
   "priority_rank": 653,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / hunspell (Stemmer affix removal)",
   "title": "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)",
   "summary": "You load a hunspell dictionary that sets COMPLEXPREFIXES (twofold prefix stripping, meant for morphologically complex right-to-left languages) and chains prefixes through continuation classes, and expect at most two prefixes per word, as hunspell(5), C Hunspell and Lucene up to 9.4.2 do. Instead, after removing the second prefix the Stemmer goes on removing prefixes: with prefixes a, b, c chained on root x, the three-prefix word cbax is accepted by spell() and stemmed to x, and with a zero-length prefix that only passes on a flag (PFX A 0 0/B), the same prefix is removed again and again without shortening the word, so spell(\"bbx\"), getRoots(\"bx\") and HunspellStemFilter throw StackOverflowError. Inside IndexWriter.addDocument that Error closes the writer, and every later addDocument throws AlreadyClosedException.",
   "impact_class": "crash",
   "introduced_commit": "d537013e70872015364c745e5f320727efc034b7 (apache/lucene#975, LUCENE-10626 'Hunspell: add tools to aid dictionary editing', a feature PR by donnerpeter with one approving review; it reached branch_9x as the backport 3b763af12f576b8b8120e98ae38b7a67461a99e8) [read]",
   "introduced_date": "2022-07-05 (merged to main); 2023-01-13 (branch_9x backport, author date kept as 2022-07-05)",
   "first_affected_version": "9.5.0 [exec] (10.0.0 on the 10.x line); 9.3.0 and 9.4.0-9.4.2 were released after the main commit but before the backport and are not affected [exec]",
   "affected_versions": "9.5.0 - 9.12.3, 10.0.0 - 10.5.2, 10.6.0 (by reading) and main ea57360912ed [exec]; not affected: 8.9.0, 8.11.4 and 9.0.0-9.4.2 [exec]; 8.8.2 and older: no Hunspell spell API, and by code the second-prefix step recursed with doPrefix = false from LUCENE-5483 (4.8.0) on [read]; [read] upstream main, branch_10x and branch_10_6 still set doPrefix = true (2026-10-26)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-375.html",
   "repro": "repro/LFV-375/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-282",
   "priority": "low",
   "priority_rank": 654,
   "novelty": "new",
   "withheld": false,
   "area": "spatial3d / Geo3DPoint polygon and shape queries (Geo3DUtil.fromPolygon, PointInGeo3DShapeQuery, PointInShapeIntersectVisitor)",
   "title": "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",
   "summary": "You build Geo3DPoint.newPolygonQuery from an org.apache.lucene.geo.Polygon that Polygon accepts but whose vertices all lie on one great circle, for example lat {0,0,0,0} and lon {0,1,2,0}, and expect a query that matches nothing: Geo3DUtil.fromPolygon recognizes the polygon as degenerate ('// Polygon is degenerate') and deliberately replaces it with an empty GeoCompositePolygon. Instead every search with the query throws NullPointerException ('Cannot invoke Double.doubleValue() because the return value of XYZBounds.getMinimumX() is null'), because the empty shape adds nothing to its XYZBounds and the PointInShapeIntersectVisitor constructor unboxes the null bounds. Geo3DPoint.newShapeQuery with an empty GeoCompositePolygon fails the same way, while LatLonPoint.newPolygonQuery returns 0 hits for the same Polygon and newLargePolygonQuery rejects it with IllegalArgumentException when the query is built.",
   "impact_class": "crash",
   "introduced_commit": "75cdcbab1094ce25a9a340f84f2101c5718635c0 (master, 2016-04-19, 'LUCENE-7192: Revamp how coplanar points are detected and filtered, for OpenStreetMap compatibility.', by Karl Wright (GitHub DaddyWri); LUCENE-7192 is apache/lucene#8247; committed from the JIRA issue, no pull request): GeoPolygonFactory.makeGeoPolygon and filterPoints return null instead of throwing IllegalArgumentException for degenerate input, and Geo3DPoint.newPolygonQuery maps a null polygon to an empty GeoCompositePolygon; the same-day follow-up 02f1dacc3d84a42f9359aedb0cc98ca4a6161d57 ('LUCENE-7192: Catch the case where we have two points in the same poly that are not adjacent but identical.') lets the three-collinear-vertex input through as well; 6.1.0 shipped the branch_6x backports 01a7ee4eebbc and e4012c6b32ef (identical patch-ids). The unboxing that throws is older: 1d76b2c49ba9c924b539f7d8a0f58c3e609656f1 (LUCENE-7221, #8276, 2016-04-14, backport 0b0e442010a6) made PointInShapeIntersectVisitor compare against the shape's XYZBounds; LUCENE-7430 (08ca33f57e5, 6.3.0) moved the unboxing into the visitor constructor and LUCENE-9150 (a6e80d004d8, 8.5.0) reworded it; it has never had a null check. [exec]",
   "introduced_date": "2016-04-19 (LUCENE-7192 and its follow-up; the unboxing site, LUCENE-7221, dates from 2016-04-14)",
   "first_affected_version": "6.1.0 [exec] (the first release with Geo3DPoint.newPolygonQuery, org.apache.lucene.geo.Polygon and the LUCENE-7192 commits; fails with -ea and -da); 6.0.0 and 6.0.1 have no newPolygonQuery, but there the newShapeQuery(empty GeoCompositePolygon) variant already fails at search time, with IndexOutOfBoundsException in GeoCompositeMembershipShape.getEdgePoints instead of the NPE [exec]",
   "affected_versions": "6.1.0 to 10.5.2 (the last release before 10.6.0) and main ea57360912ed. [exec] a version-neutral public-API main() (four API-era variants that differ only in marked API lines) fails with the same NPE for every degenerate input and for the empty-composite shape on 6.1.0 (-ea and -da), 6.2.0, 6.2.1, 6.3.0, 6.6.6, 7.0.0, 7.0.1, 7.1.0, 7.7.3, 8.0.0, 8.4.1, 8.5.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da), with the circle, box and box-plus-degenerate-component controls passing; the finder's JUnit fails on main (-ea, -da, 20 of 20 iterations), 10.5.2 and 9.12.3, and the independent reproduction's JUnit on main, 10.5.2, 9.12.3 and 8.11.4. [read] releases between the tested points are inferred: every executed release fails, including the releases on both sides of the two later changes to the unboxing (LUCENE-7430, LUCENE-9150). Not fixed upstream as of 2026-10-26.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-282.html",
   "repro": "repro/LFV-282/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-352",
   "priority": "low",
   "priority_rank": 655,
   "novelty": "new",
   "withheld": false,
   "area": "spatial3d / Geo3DDocValuesField outside-distance sort fields (Geo3DPointOutsideSortField equality)",
   "title": "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",
   "summary": "You build the same outside-distance sort twice, for example Geo3DDocValuesField.newOutsideDistanceSort(\"loc\", 10, 20, 1000, PlanetModel.WGS84), and compare the two with equals, with Sort.equals, or by looking one up in a HashMap keyed by Sort, and expect true (or false for two different shapes), which is what the inside-distance sort gives. Instead equals throws ClassCastException ('Geo3DPointOutsideSortField cannot be cast to class Geo3DPointSortField'): the method was copied from the sibling class Geo3DPointSortField and still casts to that class right after checking that both objects are Geo3DPointOutsideSortField, so the cast can never succeed. Searching and sorting with these sort fields work; only comparing two of them fails.",
   "impact_class": "crash",
   "introduced_commit": "cc263413457c826914c3f3c1c26f885330a931aa (main, 'LUCENE-7212: Add outside distance classes and methods.', by Karl Wright (GitHub DaddyWri); first released in 7.0.0) and its branch_6x twin aa339a2f0756a487293c271a673e60e12722d661 (same change and author date, the commit that shipped first, in 6.1.0); committed under JIRA LUCENE-7212 (migrated as apache/lucene#8267, still open), no pull request. The wrong line was copied from Geo3DPointSortField.equals, added the day before in 07af00d8e7bc ('LUCENE-7212: Add Geo3D sorted document fields'), where the same cast is correct because it names its own class. [read]. Not a regression: the cast has never changed",
   "introduced_date": "2016-05-18",
   "first_affected_version": "6.1.0 [exec] (the first release with Geo3DDocValuesField and the outside-distance sort factories; fails with -ea and -da); 6.0.1 has no such API (the probe does not compile)",
   "affected_versions": "6.1.0 to 10.6.0 (10.6.0 by reading) and main ea57360912ed; not fixed upstream. [exec] a public-API main() probe (two variants, before and after the PlanetModel argument that LUCENE-9150 added in 8.5.0) hits the ClassCastException in 5 of 5 checks (one per factory, one of them through Sort.equals) on 6.1.0 (-ea and -da), 6.6.6, 7.0.0, 7.7.3, 8.4.1, 8.5.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main, and passes 5 of 5 on main with the one-line fix; the finder's JUnit fails 3 of 4 (the control passes) on main (-ea, -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 5 of 9 (the 4 controls pass) on main (-ea, -da), 10.5.2 (-ea, -da) and 9.12.3. [read] all 81 release tags from 6.1.0 to 10.5.2 in the history clone contain the cast (8.8.2 and 8.9.0-8.11.3 are not in the clone and are inferred from 8.8.1 and the executed 8.11.4); upstream main e1c4184cb98, branch_10x, branch_10_6 and branch_9_12 still contain it (read-only check 2026-10-26). All runs on aarch64 with JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-352.html",
   "repro": "repro/LFV-352/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1055",
   "priority": "low",
   "priority_rank": 656,
   "novelty": "new",
   "withheld": false,
   "area": "core / HNSW merge-time graph reuse (util/hnsw InitializedHnswGraphBuilder.rebalanceGraph, codecs/lucene99 Lucene99HnswVectorsFormat)",
   "title": "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",
   "summary": "You index vectors with an HNSW format configured with maxConn = 1, a value the format accepts (1 to 512), delete or update one document and call forceMerge(1) (or let a natural merge run), and you expect the merge to finish, as it does in about a second with maxConn = 2 or 16. Instead the merge reuses the old graph, repairs it and calls rebalanceGraph, whose level loop stops only when size * (1/M)^level drops to 0: for M = 1 that target stays at the full size on every level and every node is promoted, so each pass adds one more complete graph level, without end. forceMerge never returns and the heap grows until OutOfMemoryError, which closes the IndexWriter (10.5.x has no abort check in the loop; main and 10.6.0 poll it, so rollback() can stop it).",
   "impact_class": "hang",
   "introduced_commit": "ef10476d98ab37b92fe48a1f71a1a06dad009ae3 (apache/lucene#15003 'Avoid reconstructing HNSW graphs during segment merging.', author Pulkitg64; branch_10x backport 3e024479d358, first released in 10.4.0) [read]",
   "introduced_date": "2025-12-01 (author date 2025-12-02T03:44:21+05:30 = 2025-12-01T22:14:21Z, merged to main the same minute; branch_10x backport 2025-12-01T22:49:47Z)",
   "first_affected_version": "10.4.0 (through a codec whose knnVectorsFormat() returns the HNSW format directly); with the default per-field codec 10.5.1, because 10.4.0 and 10.5.0 did not reuse graphs under per-field formats (#16400, fixed by #16403 in 10.5.1); 10.3.2 and earlier have no rebalanceGraph",
   "affected_versions": "[exec] main 645d4fe14a20 (-ea and -da; re-run at the registration check 2026-10-30: 1 of 1 fails each, seed DEADBEEF, abort raised from rebalanceGraph:468), 10.6.0 (4ae946e5a9b9, -ea and -da: 'forceMerge(1) still running after 100000 abort checks'; a production-codec probe without the test framework is still merging after 20 s), 10.5.2 and 10.5.1 (-da, -Xmx512m: OutOfMemoryError in rebalanceGraph after 25-42 s, then 'this writer hit an unrecoverable error; cannot complete forceMerge'), 10.5.0 and 10.4.0 pass with the default per-field codec (no graph reuse under per-field formats before #16403) but fail with OutOfMemoryError in rebalanceGraph through a codec that returns the HNSW format directly; 10.3.2 and 9.12.3 pass (no rebalanceGraph; grep count 0 from 9.12.3 to 10.3.2). [read] the loop lines are identical in 10.4.0, 10.5.x, 10.6.0 and main; not fixed upstream: main head 716d6f216f5 (2026-10-29) is unchanged at the fix site (the last commit to InitializedHnswGraphBuilder.java is d8468fd9375, #16627, 2026-10-08) and no open PR changes the loop [read]. Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1055.html",
   "repro": "repro/LFV-1055/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1056",
   "priority": "low",
   "priority_rank": 657,
   "novelty": "new",
   "withheld": false,
   "area": "core / HNSW graph construction (util/hnsw HnswGraphBuilder constructor; codecs/lucene99 Lucene99HnswVectorsFormat beamWidth range)",
   "title": "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)",
   "summary": "You configure a vector field with an HNSW format and beamWidth = 1, the smallest value the format and the graph builder accept ('beamWidth must be positive'), index vectors and merge, and you expect it to work as it did up to 10.1.0, only with a poorer graph. Instead every HnswGraphBuilder constructor sizes its level-0 merge candidate queue as Math.min(beamWidth / 2, M * 3), which integer division makes 0, and the heap rejects capacity 0 ('initialCapacity must be > 0 ... got: 0'), so no HNSW graph can be built at all. Small segments still flush without a graph, then the first merge that needs one throws and closes the IndexWriter, and the vector document that would push a segment past the graph threshold is rejected.",
   "impact_class": "crash",
   "introduced_commit": "3752dba9c51d817363c76e9a388cd68dcba5c4a0 (main) and its branch_10x backport aa1e9f34b373882025726a01982b768e4948ccf4 (#14380), first shipped in 10.2.0: apache/lucene#14331 'Speedup merging of HNSW graphs' (author mayya-sharipova, merged 2025-03-20). The 'beamWidth / 2' sizing entered the PR branch in 09735cf80a1 ('Adjust beamCandidates0', 2025-03-18), replacing Math.min(beamWidth, M * 2), which is at least 1 for every accepted value [read]",
   "introduced_date": "2025-03-20 (author date 2025-03-20T10:02:50-04:00 = 14:02:50Z, squash-merged to main the same minute; branch_10x backport merged 2025-03-20T18:43:08Z)",
   "first_affected_version": "10.2.0 [exec]",
   "affected_versions": "every release from 10.2.0 through 10.6.0 (10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2, 10.6.0) and main [exec]. The failure point moves with the version: in 10.2.x-10.3.x the flush writer builds the graph eagerly, so the first vector addDocument throws ('maxSize must be > 0' from LongHeap at HnswGraphBuilder.<init>:165); from 10.4.0 (#14963, tiny segments skip the graph) small segments flush and the failure moves to the first segment or merge that needs a graph ('initialCapacity must be > 0' from TernaryLongHeap; 10.4.0 at <init>:190, 10.5.2 at :215, 10.6.0 at :216, main at :195). Not affected: 10.1.0, 10.0.0 and 9.12.3 [exec] and all 9.x (no beamCandidates0) [read]. Not fixed upstream: main head 716d6f216f5 (2026-10-29) still has the line at HnswGraphBuilder.java:195 and branch_10_6 at :216, and no open PR changes it [read]. Lucene104HnswScalarQuantizedVectorsFormat and HnswBitVectorsFormat reach the same builder [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1056.html",
   "repro": "repro/LFV-1056/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-589",
   "priority": "low",
   "priority_rank": 658,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / HNSW vectors formats (constructor parameter validation; concurrent HNSW merge)",
   "title": "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)",
   "summary": "You build a codec with, for example, new Lucene99HnswVectorsFormat(16, 100, 0, executor), that is zero merge workers plus a merge executor. The constructor already rejects maxConn or beamWidth <= 0 and one worker with an executor, so you expect it to reject 0 as well (or to merge serially, as it does without an executor). Instead it accepts the value, indexing works, and the first merge that builds an HNSW graph throws ArrayIndexOutOfBoundsException (NegativeArraySizeException for -1) inside HnswConcurrentMergeBuilder, whose worker array is sized by that count, and the IndexWriter closes itself with that exception.",
   "impact_class": "crash",
   "introduced_commit": "a8c52e2e19c4ca9bdf71cf476d69d36d3ca9ae52 (main) and its 9.x backport 5fe48424a25dc5e3084beb02593484120adeabdf (shipped in 9.9.0): apache/lucene#12660 'Concurrent HNSW Merge' (author zhaih, merged 2023-10-28). It added the numMergeWorkers / mergeExec constructor parameters with only the (> 1, null) and (== 1, executor) checks, the worker array 'new ConcurrentMergeWorker[numWorker]' and the writer's mergeExec != null branch to ConcurrentHnswMerger [read]. Later changes moved the exposure without adding a lower bound: #13190 (75e1ebc4501, 9.11.0: intra-merge executor, so 0 without an executor fails too), #14331 (3752dba9c51, branch_10x aa1e9f34b37, 10.2.0: '> 1' guard on the intra-merge path, so (0, null) works again), #14963 (9b957e807aa, 10.4.0: tiny segments skip graph building), #15169 (07033dcd84c, 10.4.0: Lucene104HnswScalarQuantizedVectorsFormat copies the partial check), #16794 (c50bc9523db, main only: the zero-worker exception moves from finish() to runInBatches()).",
   "introduced_date": "2023-10-28",
   "first_affected_version": "9.9.0 [exec]",
   "affected_versions": "every release from 9.9.0 through 10.6.0 (10.6.0 [exec]) and main a9779ef3c193 and 645d4fe14a2 (re-run 2026-10-29, -ea and -da), also the previous hunt main ea57360912ed [exec]. On 9.11.0-10.1.0 the no-executor control (0, null) fails too, through the intra-merge executor path [exec]; on 9.9.x-9.10.0 and 10.2.0+ it passes [exec]. From 10.4.0 a merge must exceed the tiny-segment threshold to reach the bug: with the default 4-argument constructor a 40-vector merge passes and a 2000-vector merge fails on 10.5.2 and main [exec]. Lucene104HnswScalarQuantizedVectorsFormat (10.4.0+) executed on 10.4.0-10.5.2 and main; HnswBitVectorsFormat (lucene/codecs) has the same check [read]; the sandbox DedupHnswVectorsFormat and DedupHnswScalarQuantizedVectorsFormat (new in 10.6.0: #15979/#16506, backported as #16493/#16594) have the same check and fail the same way [exec]; the backward-codecs Lucene99HnswScalarQuantizedVectorsFormat and Lucene102HnswBinaryQuantizedVectorsFormat share the omission but are read-only formats [read]. branch_10_6 RC1 4ae946e5a9b fails the same [exec]; branch_10x 657014b3c57 has identical code [read]. Not fixed on upstream main 645d4fe14a2 (2026-10-29), branch_10x or branch_10_6, and no open PR adds a lower bound [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-589.html",
   "repro": "repro/LFV-589/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-166",
   "priority": "low",
   "priority_rank": 659,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / UniformSplit postings formats (BlockWriter last-block split; UniformSplit and SharedTermsUniformSplit)",
   "title": "UniformSplit postings formats fail to flush or merge a field when deltaNumLines > targetNumBlockLines/3, a setting validateSettings accepts",
   "summary": "You build a UniformSplit (or SharedTermsUniformSplit) postings format with targetNumBlockLines=4 and deltaNumLines=2, which the constructor accepts because its documented rule is only 0 <= delta < target, and commit a field with 3 terms. You expect the commit to succeed and the blocks to hold target +- delta lines. Instead the flush throws (AssertionError 'blockLines size: 3' with assertions on, IndexOutOfBoundsException 'Index -1 out of bounds for length 3' with them off) and the IndexWriter closes, because the code that splits a field's last block assumes its look-back window of 2*delta lines starts at line 1 or later, which is false whenever 3*delta > target and the last block has between target-delta+1 and 2*delta lines.",
   "impact_class": "crash",
   "introduced_commit": "b963b7c3dbe (b963b7c3dbecda86c2917ad341caee63b93815ac, LUCENE-8753 'New UniformSplit and SharedTermsUniformSplit PostingsFormats', committed by dsmiley; PR apache/lucene-solr#828 by bruno-roustant, following #633 and absorbing #676; the JIRA issue is now apache/lucene#9798; branch_8x cherry-pick b8a1857b0bd) [read] [exec]",
   "introduced_date": "2019-09-06",
   "first_affected_version": "8.3.0 [exec] (the first release with UniformSplit; 8.2.0 lacks the package, so the repro does not compile there [exec]); main line 9.0.0 [exec]",
   "affected_versions": "every release that ships the UniformSplit and SharedTermsUniformSplit formats: 8.3.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2 and main ea57360912ed [exec] [read]; not a regression; not fixed upstream (BlockWriter.java last changed 2021-01-03 on main and branch_10x, reformatting only; no CHANGES entry; no open PR touches BlockWriter or validateSettings) [read]; executed on aarch64 with JDK 25 only",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-166.html",
   "repro": "repro/LFV-166/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-226",
   "priority": "low",
   "priority_rank": 660,
   "novelty": "known",
   "withheld": false,
   "area": "misc / store DirectIODirectory (direct-I/O merge buffers)",
   "title": "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)",
   "summary": "You create DirectIODirectory(FSDirectory, mergeBufferSize, minBytesDirect) with a mergeBufferSize that is not a multiple of the file system block size (for example 100000, or 4 * 4096 + 100, on a 4 KiB-block file system) and expect merges to read and write through direct I/O as usual, because the constructor documents the value only as 'Size of buffer to use for merging' and accepts any int. Instead every fresh top-level DirectIOIndexInput fails on its first read with IllegalArgumentException 'Negative position' or IOException 'Channel position ... is not a multiple of the block size', so a merge that reads through direct I/O fails while opening its segment readers and IndexWriter closes on a tragic exception (the index on disk stays intact, but the error sometimes surfaces as CorruptIndexException); with a size below the block size, some fresh outputs throw BufferOverflowException on the first writeByte and writeBytes on such an output loops without progress. The cause is that the direct buffers are aligned slices whose capacity is always a block multiple (and can be 0), while DirectIOIndexInput starts its file position at -mergeBufferSize and then advances it by the buffer's capacity, so the first read lands at -(mergeBufferSize mod blockSize) or at blockSize - (mergeBufferSize mod blockSize).",
   "impact_class": "crash",
   "introduced_commit": "a7747b63b4ac649837469ee189b8aef10e4ce867 (LUCENE-8982, apache/lucene-solr#2052 'Make NativeUnixDirectory pure java with FileChannel direct IO flag, and rename to DirectIODirectory', author zacharymorn, merged by uschindler into master, the 9.0 line) [read]. It created DirectIODirectory with aligned-slice buffers (capacity a block multiple, :233 and :372-376) while the top-level input kept starting at filePos = -bufferSize (:342) and fill() advances by buffer.capacity() (:497), and it deleted the predecessor NativeUnixDirectory's constructor check 'mergeBufferSize must be 0 mod ' + ALIGN (added by 005fec5a58e, LUCENE-2795, 2012; that check tested a single bit). None of the 15 later commits to the file changes the start position or the capacity step, or validates the size; the defect was in the class's first version",
   "introduced_date": "2021-01-17",
   "first_affected_version": "9.0.0 [exec]",
   "affected_versions": "every release from 9.0.0 to 10.5.2 (33 releases), 10.6.0 (run at the RC1 revision, see below) and main (11.0.0-SNAPSHOT) through 645d4fe14a2 (re-run 2026-10-29, -ea and -da) [exec]; not applicable: 8.x and earlier [exec]; the 8.x predecessor NativeUnixDirectory is a different class whose constructor rejected some unaligned sizes (executed on 8.7.0 and 8.11.4: 100000 and 1000 rejected, 4097 and 16484 accepted); not fixed upstream (the draft PR #14928, which would fix it, is unmerged); unreleased branch_10x 657014b3c57 and 10.6.0 (released 2026-10-29; branch_10_6 4ae946e5a9b, RC1) [exec]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/14928",
    "https://github.com/apache/lucene/issues/12185",
    "https://issues.apache.org/jira/browse/LUCENE-8982",
    "https://github.com/apache/lucene/issues/10827"
   ],
   "doc": "",
   "repro": "repro/LFV-226/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1175",
   "priority": "low",
   "priority_rank": 661,
   "novelty": "new",
   "withheld": false,
   "area": "core / codecs: compressing term vectors format (Lucene90CompressingTermVectorsFormat blockSize validation; FieldsIndexWriter, DirectMonotonicWriter)",
   "title": "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)",
   "summary": "You build a custom codec whose term vectors format is new Lucene90CompressingTermVectorsFormat(..., blockSize) and, as its javadoc says ('the number of chunks to store in an index block'), pass a chunk count such as 1024; the constructor accepts it, since it rejects only values below 1. You expect a format that writes and reads term vectors, or an IllegalArgumentException from the constructor, as the stored-fields twin Lucene90CompressingStoredFieldsFormat gives for the same argument. Instead the value goes unchanged to the writer, which uses it as a DirectMonotonicWriter block shift, so addDocument succeeds and the first flush with term vectors (here DirectoryReader.open(writer) or commit) throws 'blockShift must be in [2-22], got 1024' and closes the IndexWriter; blockSize 1, the constructor's own minimum, fails the same way.",
   "impact_class": "minor",
   "introduced_commit": "136dcbdbbced7c2d32b4d244ca99ace2c59baee8 on the main line (first release 9.0.0) and its branch_8x cherry-pick 597141df6b6a017fced16ec27b8fd180e9a6fcc2 (first release 8.5.0), the same change: LUCENE-9147 'Move the stored fields index off-heap' by Adrien Grand (apache/lucene-solr PR #1179, migrated issue #10187). It turned the term vectors writer's index-block argument from a chunk count into a DirectMonotonic block shift (CompressingTermVectorsWriter: blockSize -> blockShift; Lucene50TermVectorsFormat: 1024 -> 10) and gave the stored-fields twin the [2, 22] check and the 'log in base 2' javadoc, but did not touch CompressingTermVectorsFormat.java, which kept '@param blockSize the number of chunks' and 'blockSize < 1' [read]. LUCENE-9705 (f8be421ae1f, 2021) copied the stale javadoc and check into Lucene90CompressingTermVectorsFormat; the API itself dates from LUCENE-4599 (4.2.0).",
   "introduced_date": "2020-02-05 (author date 2020-02-05T18:35:08+01:00; PR merged 2020-02-05T17:35:09Z); first release 8.5.0",
   "first_affected_version": "8.5.0 [exec]; 8.4.1 is not affected [exec]",
   "affected_versions": "Every release from 8.5.0 (2020) through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT); never fixed. [exec] the independent reproduction's one-test repro (blockSize 1024) fails on main with -ea and -da (the independent reproduction, the adjudication and a separate re-run of 2026-11-03) and on the 10.6.0, 10.5.2 and 9.12.3 jars (-ea, the independent reproduction); the finder's equivalent test fails on main (-ea, -da), 10.6.0 and 9.12.3; the intended-behaviour check's blockSize-1 test fails on main (-ea, -da) and 10.6.0; core-only main() equivalents fail on 8.5.0, 8.11.4 and 9.0.0, and 8.4.1 passes. [read] the 8.5.1 to 8.8.1, 9.0.0, 9.12.3, 10.0.0 and 10.6.0 sources all have 'blockSize < 1' with a shift-taking writer; 8.8.2 to 8.11.3 fall between executed failing releases. Not new in 10.6 (10.5.2 fails too). Not fixed upstream: main 1c2072f0284 (2026-11-02) still has the count javadoc and the >= 1 check (contents API, 2026-11-03), and the newest upstream commit on the file is be94a667f20 (2021-04-06).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1175.html",
   "repro": "repro/LFV-1175/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1183",
   "priority": "low",
   "priority_rank": 662,
   "novelty": "new",
   "withheld": false,
   "area": "core / search: filtered kNN accept docs (AcceptDocs.createBitSet behind KnnFloatVectorQuery/KnnByteVectorQuery filters, read by Lucene99HnswVectorsReader and HnswGraphSearcher)",
   "title": "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)",
   "summary": "You run a KnnFloatVectorQuery with a custom filter whose scorer iterates a BitSetIterator over a FixedBitSet sized to its own matches (10 bits for docs 0..9) on a 100-document segment with no deletions, where every document has a vector. You expect the top k vectors among the filter's matches (here doc 9, with k = 1), as with the same filter backed by a maxDoc-sized set. Instead AcceptDocs.createBitSet hands the filter's 10-bit set unchanged to the HNSW reader as the accept bits (its other branches build maxDoc bits, and its fromLiveDocs entry point rejects bits whose length is not maxDoc), the reader tests it for every vector ordinal, and the search throws ArrayIndexOutOfBoundsException (AssertionError 'index=10, numBits=10' with -ea) from FixedBitSet.get.",
   "impact_class": "minor",
   "introduced_commit": "03846b468e52126582c09816f7e85e98aee9a405 on main and its branch_9x cherry-pick e055e95d3ef404368c1accea95d88f1cf5b48c80 (the commit in the 9.3.0 release): #951 (LUCENE-10606, 'For KnnVectorQuery, optimize case where filter is backed by BitSetIterator', by kaivalnp), which replaced the per-segment collector (always a new FixedBitSet(maxDoc)) by reusing the filter scorer's own BitSetIterator set when the segment has no deletions, without checking the set's length [read]. Later commits only moved the code (72968d30ba1, #12004, into AbstractKnnVectorQuery, 9.5.0; 310ef63d827, #15011, into AcceptDocs, 10.3.0, which added the length == maxDoc check to the fromLiveDocs path only) or changed where the bits are read (0614fe9ebd7, #14160, 10.2.0: small filtered counts take the exhaustive loop, which reads the accept bits for every ordinal).",
   "introduced_date": "2022-06-27 (author date of 03846b468e5, 12:22:52 +0530; merged 2022-06-27T06:52:53Z); first release 9.3.0",
   "first_affected_version": "9.3.0 [exec]. The independent reproduction's 200-document variant of the repro first fails on 9.9.0 [exec]. 9.0.0 has no kNN filter [read].",
   "affected_versions": "Every release from 9.3.0 (2022) through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT); never fixed. [exec] the independent reproduction's 200-document variant of the repro fails on main with -ea (AssertionError 'index=10, numBits=10') and -da (ArrayIndexOutOfBoundsException 'Index 1 out of bounds for length 1'), both at FixedBitSet.get <- Lucene99HnswVectorsReader.search:389 (the independent reproduction, the intended-behaviour check, the adjudication, the history step and the re-run of 2026-11-03); on 10.6.0, 10.5.2 (-ea and -da), 10.3.0 and 10.2.2 in the exhaustive loop, and on 10.0.0, 9.12.3 (-ea and -da), 9.10.0 and 9.9.0 in the graph walk (HnswGraphSearcher.searchLevel), all -da unless stated; it passes on 9.2.0, 9.3.0, 9.7.0 and 9.8.0. The finder's test fails on 10.2.0 to 10.6.0 and main and passes on 10.0.0 and 10.1.0; the finder's HNSW-path probe (2000 random 4-d vectors, a 1000-bit filter set) fails on 9.3.0 (-ea, -da), 9.8.0, 9.12.3, 10.0.0 and 10.1.0 (-ea, -da) and passes on 9.1.0 and 9.2.0. [read] every release tag from 9.3.0 to 10.6.0 has the unguarded shortcut. Not new in 10.6 (10.5.2 fails). Not fixed upstream: main 1c2072f0284 (2026-11-02) still has the unguarded shortcut at AcceptDocs.java:95-97; the last commit on AcceptDocs.java is #16588 (1a65ceae18e, author date 2026-09-10), which 5adff78 contains.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1183.html",
   "repro": "repro/LFV-1183/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1176",
   "priority": "low",
   "priority_rank": 663,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / Lucene104 scalar-quantized vectors (flat format search on a field with no vectors: Lucene104ScalarQuantizedVectorsReader.search)",
   "title": "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)",
   "summary": "You index float vectors with the flat Lucene104ScalarQuantizedVectorsFormat, delete every document that has a vector while other documents remain, and merge, so the merged segment still lists the vector field but holds no vectors (the same index Lucene's own test testDeleteAllVectorDocs builds). You expect a FloatVectorSimilarityQuery on that index to return no hits, as it does with the HNSW formats and as KnnFloatVectorQuery does on the same index. Instead IndexSearcher.search throws NullPointerException ('quantizer' is null), because the reader's search() returns early only when k is 0 and then builds a scorer over the empty vector values, whose quantizer is null.",
   "impact_class": "crash",
   "introduced_commit": "594eeb7e637c94d1018cdb938a5596de9034c0bc on main, cherry-picked to branch_10x as 07033dcd84ccbbcf13bc3a81a6430445d2e4d3fa (the same change): #15169 'Add a new codec to implement OSQ for 4 and 8 bit quantized vectors' by @mccullocht (co-author @benwtrent; merged 2025-09-17, milestone 10.4.0) [read]. The FLOAT16 overload search(String, short[], ...) with the same guard came with 50c1e6acb7f (#16473, author 2026-08-26, main only, unreleased).",
   "introduced_date": "2025-09-17 (author date 2025-09-17T15:37:18-07:00 of both the main and the branch_10x commit; first release 10.4.0)",
   "first_affected_version": "10.4.0 [exec]; 10.3.2 and 9.12.3 are not affected because the format does not exist there [exec]",
   "affected_versions": "10.4.0, 10.5.0, 10.5.1, 10.5.2, 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT); not fixed anywhere (upstream main 1c2072f02843, 2026-11-02, still returns early only for k() == 0 in both search overloads). [exec] fail: main -ea and -da (finder, the independent reproduction, the intended-behaviour check, adjudication, follow-up), 10.6.0 -ea (finder, the independent reproduction, the intended-behaviour check, follow-up), 10.5.2 -ea (finder, follow-up) and with -ea and -da (the independent reproduction), 10.4.0 -ea with the adapted constructor (finder probe, the independent reproduction, follow-up); 10.5.0 and 10.5.1 -da with the adapted constructor (the doc's fact check, which also re-ran 10.4.0, 10.5.2 and 10.6.0: all fail). Not affected: 10.3.2 and 9.12.3 (format absent) [exec]. The FLOAT16 path (KnnFloat16VectorField with Float16VectorSimilarityQuery) throws the same NullPointerException on main [exec], main only. Not new in 10.6 (10.4.0 and 10.5.2 fail).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1176.html",
   "repro": "repro/LFV-1176/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1185",
   "priority": "low",
   "priority_rank": 664,
   "novelty": "new",
   "withheld": false,
   "area": "search / kNN vector queries (SeededKnnVectorQuery seed-to-ordinal mapping: MappedDISI and the entry-point count)",
   "title": "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)",
   "summary": "You index 2,000 documents with a float vector on the even ones only, build a seed Weight with IndexSearcher.createWeight for a term query that matches doc 1997 (no vector) and doc 1998 (the last vector doc), and search new SeededKnnVectorQuery(new KnnFloatVectorQuery(\"v\", q, 2), seed, seedWeight) for 2 hits. You expect 2 hits, which SeededKnnVectorQuery.fromFloatQuery returns for the same seed, and the class javadoc only says the format may ignore a seed. Instead search throws IllegalArgumentException 'The number of entry points provided is less than the number of entry points requested': the caller's Weight skips the FieldExistsQuery filter that the internal path adds, MappedDISI maps doc 1997 to vector doc 1998 and then calls advance(1998) on an iterator already at 1998 (undefined for a DocIdSetIterator), which runs it off the end, while the entry-point count still counts both seeds.",
   "impact_class": "minor",
   "introduced_commit": "2b47cd3cd69b83c9798bfa109ba05b2666947b8e on main (branch_10x 52597fa4cac): apache/lucene#14838 'Make it possible to extend Patience/Seeded knn queries' (Tommaso Teofili, approved by Benjamin Trent), which made the Weight-taking constructors SeededKnnVectorQuery(KnnFloatVectorQuery|KnnByteVectorQuery, Query, Weight) public with no javadoc; that is the first point where public API can hand MappedDISI a seed Weight whose hits lack a vector [exec]. The defective code is older: the unguarded indexedDISI.advance(newTarget) in MappedDISI and the entry-point count seedTopDocs.scoreDocs.length come from 34f0453283a45acac366539d08d47a5e8939204a (#14084 'Add two new \"Seeded\" Knn queries for seeded vector search', Benjamin Trent; branch_10x bf7c98a0a1b), moved unchanged into SeededKnnVectorQuery by e4321619bba (#14170) [read]",
   "introduced_date": "2025-06-25 (author date = commit date of 2b47cd3cd69, #14838; branch_10x commit 2025-06-25); root code 2025-01-15 (author date of 34f0453283a, #14084)",
   "first_affected_version": "10.3.0 [exec] [read]",
   "affected_versions": "10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2, 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT); not fixed anywhere (upstream main 1c2072f0284, 2026-11-02, has no commit to SeededKnnVectorQuery.java since 310ef63d827, 2025-08-24, and MappedDISI.advance is still unguarded). Executed, fail [exec]: main with -ea and -da (finder, the independent reproduction, the intended-behaviour check, adjudication, a separate re-run), 10.6.0 (-ea and -da), 10.5.2 (-ea and -da), 10.4.0 (-da), 10.3.0 (-ea, and -da through the out-of-package copy). 10.3.1, 10.3.2, 10.5.0 and 10.5.1 by reading (every release tag from 10.3.0 to 10.6.0 has both public constructors and the two unguarded advance calls). Not affected through public API [exec]: 10.2.0 to 10.2.2 hold the same code behind a package-private constructor (a same-package copy of the test fails on 10.2.0 and 10.2.2: latent, not claimed); 10.1.0 and 9.12.3 have no SeededKnnVectorQuery (compile error). Not new in 10.6. All runs on Linux aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1185.html",
   "repro": "repro/LFV-1185/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1184",
   "priority": "low",
   "priority_rank": 665,
   "novelty": "new",
   "withheld": false,
   "area": "core / codecs: MultiLevelSkipListWriter (multi-level skip lists for postings; @lucene.experimental)",
   "title": "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)",
   "summary": "You write a postings format whose skip writer extends MultiLevelSkipListWriter with maxSkipLevels = 1 (a single-level skip list) and call bufferSkip every skipInterval documents. You expect every entry to go to level 0, because the writer reports numberOfSkipLevels = 1 and allocates one level buffer, and 9.8.0 does exactly that. Instead, at the first df that is a multiple of skipInterval * skipMultiplier, a shortcut added in 9.9.0 (#12653) raises the level count to 2 without checking that cap, and bufferSkip throws ArrayIndexOutOfBoundsException 'Index 1 out of bounds for length 1'; Lucene's own postings formats use 4 or 10 levels and are not affected.",
   "impact_class": "minor",
   "introduced_commit": "de8ae1de7cc022998f8700ae3d9b59c7bff3cf63 on main and its branch_9x twin 3292aca1f453d6e6b2a2a6ace172f2128e3b397f: apache/lucene#12653 'Optimize computing number of levels in MultiLevelSkipListWriter#bufferSkip' (by shubhamvishu, merged by mikemccand). It replaced the level loop 'df /= skipInterval; while ((df % skipMultiplier) == 0 && numLevels < numberOfSkipLevels)', where every increment was capped, with a 'df % windowLength == 0' fast path whose first increment is not capped [read]. The capped loop dated from the class's creation (LUCENE-866, 87ba4a12584, 2007).",
   "introduced_date": "2023-10-21 (author date 2023-10-21T11:52:28Z for both de8ae1de7cc and 3292aca1f45; PR merged 2023-10-21T11:52:28Z); first release 9.9.0",
   "first_affected_version": "9.9.0 [exec]",
   "affected_versions": "Every release from 9.9.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT); never fixed. [exec] the finder's test fails on main (-ea, -da), 10.6.0 and 9.9.0 (-da) and passes on 9.8.0 (-da); the history step ran it on 9.8.0 (-ea, -da: pass) and on 9.9.0 (-ea, -da), 9.12.3, 10.0.0, 10.6.0 (-da) and main (-ea, -da): fail; the independent reproduction's test fails on main (-ea, -da), 10.6.0, 10.5.2 and 9.12.3 (-da) and passes on 9.8.0 (-da); the intended-behaviour check's write-then-read test fails on main (-ea, -da) and 10.6.0 (-da) and passes on 9.8.0 (-da). Not new in 10.6 (10.5.2 fails). Not fixed upstream: main 1c2072f0284 (2026-11-02) still has the uncapped 'if (df % windowLength == 0)' at line 134 (contents API, 2026-11-03), so do branch_11x and branch_10_6 (follow-up check), and the newest upstream commit on the file is still de8ae1de7cc.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1184.html",
   "repro": "repro/LFV-1184/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1238",
   "priority": "low",
   "priority_rank": 666,
   "novelty": "new",
   "withheld": false,
   "area": "core / util/hnsw: HnswGraphSearcher (bulk-scoring scratch of the unfiltered searcher)",
   "title": "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)",
   "summary": "You implement HnswGraph for a graph whose M you do not know, so maxConn() returns the public constant HnswGraph.UNKNOWN_MAX_CONN (-1), and search it with HnswGraphSearcher.search, whose dispatch handles that value on purpose by skipping only the filtered searcher ('We can only use filtered search if we know the maxConn'). You expect the nearest neighbours, as the same graph gives when it reports a known maxConn and as 10.2.x gives. Instead every search throws java.lang.NegativeArraySizeException: -2 from HnswGraphSearcher.prepareScratchState, because since 10.3.0 the unfiltered searcher allocates its bulk-scoring scratch as new int[graph.maxConn() * 2] (in searchLevel, and since 10.4.0 also in findBestEntryPoint for graphs with more than one level).",
   "impact_class": "minor",
   "introduced_commit": "71d4ad6780e58a0768cb33e5f17320977bbc015d (apache/lucene#14978 'Add a bulk scoring interface to RandomVectorScorer', by mccullocht; released through the branch_10x cherry-pick cac1a31b6a32d09c57f06d41d7d9d5802274828e, contained in releases/lucene/10.3.0 and not in 10.2.2): it added bulkNodes = new int[graph.maxConn() * 2] (and bulkScores) to HnswGraphSearcher.searchLevel, which is new int[-2] for UNKNOWN_MAX_CONN. #15500 (8c1461e536d, by benwtrent, 10.4.0; branch_10x 3c2a0f41a51) later moved the sizing into prepareScratchState(size, graph.maxConn() * 2) and added the same call to findBestEntryPoint, so git blame on main's current lines points to #15500, but 10.3.0 already fails. The constant and the dispatch guard that sends such graphs to the plain searcher came first, with #14160 (0614fe9ebd7, by benwtrent, 10.2.0), when that searcher never read maxConn() [read]",
   "introduced_date": "2025-07-31 (#14978: author date 2025-07-31T04:01:34-07:00, merged 2025-07-31T11:01:34Z; branch_10x commit 2025-08-06); the findBestEntryPoint call of #15500 dates from 2025-12-15 (author date 2025-12-15T11:22:48-05:00); #14160, which added the constant and the fallback, from 2025-02-13",
   "first_affected_version": "10.3.0 [exec]; HnswGraph.maxConn() and UNKNOWN_MAX_CONN first exist in 10.2.0 (#14160), so 10.1.x, 10.0.x and 9.x cannot express the trigger (the test does not compile on 10.1.0 or 9.12.3)",
   "affected_versions": "10.3.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT); never fixed. [exec] main (-ea and -da: finder, the independent reproduction, the intended-lens review's re-check, the intended-behaviour check, adjudication, registration check), 10.6.0 (-da: finder, the independent reproduction, the intended-behaviour check, history step), 10.5.2 (-da: the independent reproduction), 10.4.0 (-da: history step) and 10.3.0 (-da: finder, the independent reproduction, the cross-model reviews, the intended-behaviour check, history step) all fail with NegativeArraySizeException: -2 (at prepareScratchState :371 <- searchLevel :284 on main, :377 <- :290 on 10.4.0 to 10.6.0, searchLevel :283 on 10.3.0); 10.2.0 and 10.2.2 pass (finder, the independent reproduction, the cross-model reviews, the intended-behaviour check, history step); on 10.1.0 and 9.12.3 the test does not compile because HnswGraph has no maxConn() or UNKNOWN_MAX_CONN there (history step). [read] the sizing 'maxConn() * 2' is absent from HnswGraphSearcher.java at releases/lucene/10.2.0, 10.2.1 and 10.2.2 and present at every tag from 10.3.0 to 10.6.0 (10.3.0-10.3.2 inline in searchLevel; 10.4.0-10.6.0 in prepareScratchState calls at :229 and :290). Not new in 10.6 (10.5.2 and older releases fail). Not fixed upstream: upstream main head still has prepareScratchState(size, graph.maxConn() * 2) at HnswGraphSearcher.java:223 and :284 and new int[bulkScoreSize] at :371; the newest commit on the file is #16806 (2e21f30ef68, author date 2026-11-02), which 5adff78bb168 contains [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1238.html",
   "repro": "repro/LFV-1238/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1234",
   "priority": "low",
   "priority_rank": 667,
   "novelty": "new",
   "withheld": false,
   "area": "core / util/hnsw: OnHeapHnswGraph (upper-level node cache of getNodesOnLevel and getSortedNodes)",
   "title": "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)",
   "summary": "You build an HNSW graph with HnswGraphBuilder.create(...).build(0) over an empty vector set and list the nodes of every level the returned OnHeapHnswGraph reports (numLevels() is 2), the same loop Lucene's own vectors writer runs over a graph. You expect level 1 to list no nodes, as level 0 of the same graph does and as HnswGraph.EMPTY does for every level. Instead getNodesOnLevel(1) (and getSortedNodes(1)) throws NullPointerException 'Cannot load from object array because \"this.levelToNodes\" is null', because the upper-level node cache is rebuilt only when size() differs from the size at its last build, both are 0 on a new graph, so the cache is never created.",
   "impact_class": "minor",
   "introduced_commit": "a8c52e2e19c4ca9bdf71cf476d69d36d3ca9ae52 (apache/lucene#12660 'Concurrent HNSW Merge', by zhaih; branch_9x cherry-pick 5fe48424a25dc5e3084beb02593484120adeabdf): it replaced the empty graph's 'numLevels = 1' with the placeholder entry node EntryNode(-1, 1), so an empty graph reports numLevels() == 2. That exposed the size-keyed upper-level cache (levelToNodes, null, and lastFreezeSize, 0, on a new graph) that #12651 ('Optimize OnHeapHnswGraph's data structure', a1cf22e6a94 on main, ba26abcaee9 on branch_9x, same author) had added 12 days earlier, when level 1 of an empty graph was still out of range [read]",
   "introduced_date": "2023-10-28 (#12660: author date 2023-10-28T11:03:22-07:00, merged 2023-10-28T18:03:23Z; branch_9x commit 2023-10-28T11:11:40-07:00); the size-keyed cache of #12651 dates from 2023-10-16 (merged 2023-10-16T20:13:37Z)",
   "first_affected_version": "9.9.0 [exec]; #12651 and #12660 both first shipped in 9.9.0, so no release has only one of them",
   "affected_versions": "9.9.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT); never fixed. [exec] main (-ea and -da: finder, the independent reproduction, the cross-model reviews, the intended-behaviour check, adjudication, registration check), 10.6.0 (-da: finder, the independent reproduction, the intended-behaviour check, history step; -ea: the intended-lens review's re-check), 10.5.2 (-da, the independent reproduction), 10.0.0 (-da, history step), 9.12.3 (-da, with a 9.x vector-API copy of the test, the independent reproduction and history step) and 9.9.0 (-da, history step; the independent reproduction through a same-package range check) all fail with the same NullPointerException (at OnHeapHnswGraph.java:276 on main, :269 on 10.6.0, :247 on 10.0.0, :270 on 9.12.3, :245 on 9.9.0); 9.8.0 passes. [read] every release tag from 9.9.0 to 10.6.0 contains both 'new EntryNode(-1, 1)' and 'lastFreezeSize == size()' in OnHeapHnswGraph.java, and git log -L shows no later change to the entry node, numLevels() or the cache key. Not new in 10.6 (10.5.2 and older releases fail). Not fixed upstream: upstream main 1c2072f0284 (:77, :281) and branch_10_6 (:77, :274) still have both lines; the newest commit on the file is #15590 (3b8a0cdbcc6 on main, author date 2026-02-26) [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1234.html",
   "repro": "repro/LFV-1234/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1197",
   "priority": "low",
   "priority_rank": 668,
   "novelty": "new",
   "withheld": false,
   "area": "core / util/hnsw: InitializedHnswGraphBuilder (fromGraph, addGraphNode; @lucene.experimental)",
   "title": "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)",
   "summary": "You copy an existing HNSW graph into a new builder with InitializedHnswGraphBuilder.fromGraph, passing null for initializedNodes, which its javadoc allows ('can be null if not tracking'), and then add a new vector with addGraphNode. You expect the vector to be inserted (with a bit set marking the copied nodes, the graph grows from 2 to 3 nodes). Instead addGraphNode throws NullPointerException ('Cannot invoke BitSet.get(int) because this.initializedNodes is null'), because it checks the bit set for nodes to skip without first checking that there is one.",
   "impact_class": "minor",
   "introduced_commit": "ef10476d98ab37b92fe48a1f71a1a06dad009ae3 (apache/lucene#15003 'Avoid reconstructing HNSW graphs during segment merging', by Pulkitg64; branch_10x cherry-pick 3e024479d358e77ba7d802308b70ccb25ccf08c4) [read]. The unguarded read itself is older: 'if (initializedNodes.get(node))' dates from #12657 (ea272d0eda1 on main, 18bb826564b on branch_9x, by benwtrent, 2023-10-17, first released in 9.9.0) [read], but through 10.3.2 the @param required a bit set and no in-tree code passed null, so a null there was caller misuse.",
   "introduced_date": "2025-12-01 (#15003 merged 2025-12-01T22:14:21Z; author date 2025-12-02T03:44:21+05:30; branch_10x cherry-pick committed 2025-12-01T17:49:47-05:00)",
   "first_affected_version": "10.4.0 [exec]; 10.3.2, the last release before, is not affected as a contract bug [read]",
   "affected_versions": "10.4.0, 10.5.0, 10.5.1, 10.5.2 and 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT); never fixed. [exec] finder: main (-ea, -da), 10.6.0 and 10.4.0 (-ea) fail with NullPointerException at InitializedHnswGraphBuilder.addGraphNode (:489 on main, :488 on 10.6.0, :448 on 10.4.0); history step: 10.4.0, 10.6.0 and main (-ea) fail; the independent reproduction's own test: main (-ea, -da), 10.6.0, 10.5.2 (:464) and 10.4.0 (-ea) fail; the intended-behaviour check's own test: main (-ea, -da) and 10.6.0 (-da) fail; judge and re-runs on main (-ea, -da) fail. [read] 10.5.0 and 10.5.1 contain 3e024479d35 with the same @param and the same unguarded read. Before 10.4.0 (9.9.0 to 10.3.2) the same NullPointerException follows a null argument [exec], but the javadoc did not allow null there, so those releases are not counted. 9.8.0 and earlier have no such class. Not new in 10.6 (10.4.0 and 10.5.2 fail). Not fixed upstream: upstream main 1c2072f0284 (author date 2026-11-02), branch_11x and branch_10_6 still have the '(can be null if not tracking)' @param and the unguarded read (:489, :489, :488); the newest commit on the file is d8468fd9375 (#16627, author date 2026-10-08).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1197.html",
   "repro": "repro/LFV-1197/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-125",
   "priority": "low",
   "priority_rank": 669,
   "novelty": "new",
   "withheld": false,
   "area": "search / kNN query layer (PatienceKnnVectorQuery over SeededKnnVectorQuery)",
   "title": "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",
   "summary": "You build PatienceKnnVectorQuery.fromSeededQuery(SeededKnnVectorQuery.fromFloatQuery(knnQuery, seedQuery)) and search it with IndexSearcher. You expect the query object to be unchanged by the search (Weight javadoc: 'searching does not modify a Query, so that a Query instance can be reused'), so it can be compared, cached and reused, including by several threads on different readers. Instead rewrite stores a new SeededKnnVectorQuery holding a seed Weight built for the current searcher in the query's own delegate field: after one search the query's hashCode has changed and it no longer equals an identical unsearched query, and when two searches of the same object on different readers overlap, the first one runs the other searcher's seed Weight on its later segments and fails with 'AssertionError: The top-reader used to create Weight is not the same as the current reader's top-reader' (-ea) or 'ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1' at TermStates.get (-da).",
   "impact_class": "crash",
   "introduced_commit": "f16e2f35902 (f16e2f35902d37e9de071cefc61e763d8cbe4249) on main, 10.x cherry-pick e569483131c, apache/lucene#14688 'Fix patience knn queries to work with seeded knn queries' (tteofili; one review, APPROVED 'LGTM' by ChrisHegarty; no general or inline comments): it changed 'final AbstractKnnVectorQuery delegate' to a mutable private field and added the rewrite override that assigns delegate = new SeededKnnVectorQuery(..., createSeedWeight(indexSearcher), ...) [read]",
   "introduced_date": "2025-05-20 (#14688 merged to main 2025-05-20T15:21:37Z)",
   "first_affected_version": "10.3.0 (release tag 2025-09-13) [exec]",
   "affected_versions": "10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main through ea57360912ed [exec]; upstream main, branch_10x, branch_10_6 (10.6.0, released 2026-10-29) and branch_10_5 still declare the mutable field and assign it in rewrite on 2026-10-26 [read], so 10.6.0 (released 2026-10-29) has it, and 11.0.0 ships it unless fixed; not affected: 10.2.0, 10.2.1, 10.2.2 [exec]; the API does not exist in 10.1.0 and older or in any 9.x release [exec]; executed variants: float vectors (finder, the independent reproduction, the cross-model review, the intended-behaviour check, adjudication) and byte vectors",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-125.html",
   "repro": "repro/LFV-125/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-567",
   "priority": "low",
   "priority_rank": 670,
   "novelty": "known",
   "withheld": false,
   "area": "queries / function queries (ValueSource context map under concurrent search)",
   "title": "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",
   "summary": "You search with a FunctionQuery (or FunctionRangeQuery, or a sort by ValueSource.getSortField) whose function uses scale() together with about twenty context-storing sources such as query(), on an IndexSearcher built with an executor, and expect the same hits and scores as on a searcher without one, because IndexSearcher is documented as completely thread safe. Instead all slices share the Weight's one IdentityHashMap context (documented 'non-threadsafe'), ScaleFloatFunction.getValues puts its min/max entry into it from the slice threads, and when that put resizes the map other slices miss entries such as \"searcher\". The search then throws NullPointerException, or, on a searcher with a non-default Similarity, QueryValueSource silently rebuilds its weight with the default Similarity and the scores and top hits change.",
   "impact_class": "silent wrong results",
   "introduced_commit": "a993ae9032337ca8d5b2c7a4d58bf41a6f5053f5 (2011-06-28, svn r1140906, LUCENE-3249 = #4322 'Moved FunctionQuery impls to new Queries Module': brings ScaleFloatFunction with its lazy getValues-time put, QueryValueSource and MaxDocValueSource into Lucene's queries module) with its companion b3f0ae9b7a0d9e58b1e38d9b48fe6cb3cfbd4e5a (2011-06-27, r1140379, LUCENE-3240 = #4313: FunctionQuery with one context per FunctionWeight, and ValueSource.newContext, an IdentityHashMap documented 'non-threadsafe') [read]. Code origin, all first released in 4.0.0-ALPHA: the search-time put comes from Solr's ScaleFloatFunction in 8b241d9230380b75157ad396c74ca1498f287666 (2011-01-08, LUCENE-2831 = #3905), the shared-Weight executor search from 87274d00ac17cbee79da2b162f8f169abdd61cd7 (2011-01-05, LUCENE-2837 = #3911), the context map from 1eb4697977563fa26562e5973cc9c06796ba3aa3 (2009-09-17, SOLR-1432, Solr code); the context key changed later (SOLR-5524, 4.7.0) without changing the lazy put. Pre-GitHub (svn), no PR.",
   "introduced_date": "2011-06-28 (move into Lucene; companion 2011-06-27; the search-time put itself dates from 2011-01-08 in Solr code)",
   "first_affected_version": "4.0.0-ALPHA [exec]; FunctionRangeQuery from 5.4.0, where the class first appears [exec]; not affected: 3.6.2 and earlier, where the API does not exist [exec]",
   "affected_versions": "Every release from 4.0.0-ALPHA through 10.5.2 (the last release before 10.6.0), plus main ea57360912ed. [exec] fail: 4.0.0-ALPHA, 4.0.0, 4.10.4, 5.4.0, 5.5.5, 6.6.6, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (history probe, public API, 300 searches per case; 26 of 26 stock JVM runs failed, every control without scale() passed; -da also on 4.0.0-ALPHA, 4.0.0, 8.11.4, 9.12.3, 10.5.2 and main); the finder's JUnit fails on main (-ea, -da), 10.5.2, 9.12.3 and 8.11.4; the independent reproduction's JUnit on main (-ea, -da), 10.5.2 and 9.12.3; separate runs on main (-ea, -da), 10.5.2 and 9.12.3. [read] the other release tags have the same code (code-identity check over 123 of 123 tags 4.0.0-alpha..10.5.2 in the history clone; the 8.9.0-8.11.x tags are not in the clone, 8.11.4 was executed). Not fixed upstream: no commit and no open PR changes this code (follow-up prior-report record, 2026-10-26).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15574",
    "https://github.com/apache/lucene/issues/6399",
    "https://issues.apache.org/jira/browse/LUCENE-5335",
    "https://github.com/apache/lucene/issues/7294",
    "https://issues.apache.org/jira/browse/LUCENE-6232",
    "https://github.com/apache/lucene/issues/14775"
   ],
   "doc": "",
   "repro": "repro/LFV-567/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-863",
   "priority": "low",
   "priority_rank": 671,
   "novelty": "known",
   "withheld": false,
   "area": "search / BooleanWeight.explain (span and payload-span queries under non-scoring clauses; FunctionScoreQuery; Monitor ExplainingMatch)",
   "title": "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",
   "summary": "You search with a BooleanQuery such as '+body:quick -(spanNear([body:brown, body:fox], 0, true) body:dog)', which ComplexPhraseQueryParser builds from 'quick AND NOT (\"brown fox\" OR dog)', and call IndexSearcher.explain to see why a document matched or not; you expect an Explanation. Instead explain throws NullPointerException (AssertionError with -ea): Lucene builds the weight of a FILTER or MUST_NOT clause, or of the query inside a FunctionScoreQuery whose source does not read scores, without scores, but BooleanWeight.explain still asks that weight's scorers for score(), and a span scorer built without scores has no similarity scorer. Search results are correct and only explain fails, but Monitor's ExplainingMatch reports such a query as an error and loses its match.",
   "impact_class": "crash",
   "introduced_commit": "d27ddcb409ddf5d388734db2428ac60edc22180a (d27ddcb409d, 'LUCENE-8008: Reduce leniency in CheckHits.', the JIRA patch of LUCENE-8008 / apache/lucene#9056, committed directly to lucene-solr master, no GitHub PR, no CHANGES entry): BooleanWeight.explain stopped returning the summed clause values and started pulling scorer(context), advancing it to doc and returning scorer.score(), without checking the weight's ScoreMode [exec]. Later commits that change where it shows: bdeca925f4a (LUCENE-9524 / #10564, 8.7.0) fixed the earlier SpanWeight.explain NPE that masked this site on no-cache searchers; 26387b4b00e (#14187, author date 2025-04-02, main only) disabled the default query cache, which exposes the nested FILTER/MUST_NOT shapes with default settings",
   "introduced_date": "2017-11-29 (author and commit date of d27ddcb409d)",
   "first_affected_version": "8.0.0 [exec] (FunctionScoreQuery shape with the default searcher; all 14 7.x releases pass [exec]; branch_7x never got d27ddcb409d, so 7.2.0-7.7.3, released after the commit date, still sum the clause values). Nested FILTER/MUST_NOT shapes on a searcher without a query cache: 8.0.0-8.6.3 throw earlier in SpanWeight.explain (LUCENE-9524, a separate bug fixed in 8.7.0), from 8.7.0 at this site [exec]; with the default IndexSearcher: main only (unreleased 11.0) [exec]",
   "affected_versions": "Every release from 8.0.0 to 10.5.2 (60 releases executed with the FunctionScoreQuery shape and the default searcher: 8.0.0-8.11.4 27, 9.0.0-9.12.3 21, 10.0.0-10.5.2 12, all fail at BooleanWeight.explain's score() line), the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193 [exec]; 7.0.0-7.7.3 pass [exec]. Reach by version: FunctionScoreQuery(BooleanQuery with a span clause, a source that does not need scores) fails with the default IndexSearcher everywhere from 8.0.0; nested FILTER/MUST_NOT shapes fail with the default IndexSearcher only on main (no default query cache since #14187), and on 8.7.0-10.5.2 and the branch_10_6 head only on searchers without a query cache (setQueryCache(null), MemoryIndex.createSearcher()) [exec], because the default LRUQueryCache's CachingWrapperWeight extends ConstantScoreWeight and its explain does not call the wrapped weight; Monitor ExplainingMatch with production defaults: main fails, 10.5.2 passes [exec]. Not fixed: BooleanWeight.java:121-129 unchanged on upstream main c5ab3e57b9b (2026-10-28) and branch_10_6 [read]. All runs JDK 25.0.3 on aarch64",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9652",
    "https://issues.apache.org/jira/browse/LUCENE-8606",
    "https://github.com/apache/lucene/issues/10564",
    "https://issues.apache.org/jira/browse/LUCENE-9524",
    "https://github.com/apache/lucene/issues/12991",
    "https://github.com/apache/lucene/issues/12383"
   ],
   "doc": "",
   "repro": "repro/LFV-863/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-167",
   "priority": "low",
   "priority_rank": 672,
   "novelty": "new",
   "withheld": false,
   "area": "join / block join (ParentsChildrenBlockJoinQuery: ParentsChildrenBlockJoinWeight#scorerSupplier intra-segment guard)",
   "title": "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",
   "summary": "You search with a BooleanQuery that combines a ParentsChildrenBlockJoinQuery with another clause and call IndexSearcher.explain on a hit, and you expect an explanation, because the Weight#scorer and Weight#scorerSupplier javadoc say a scorer (supplier) for the same LeafReaderContext may be requested multiple times as part of a single search call. Instead explain throws IllegalStateException 'ParentsChildrenBlockJoinQuery does not support intraSegment concurrency. Context ... was already seen.': the join query's Weight records every leaf it has built a scorer supplier for and refuses a second request, and BooleanWeight#explain makes exactly that second request (the join clause's own explain pulls a scorer, then BooleanWeight pulls its scorer for the same leaf to compute the score). The search itself returns the right hits; explain fails for every document that the BooleanQuery matches, including documents matched only by the other clause.",
   "impact_class": "crash",
   "introduced_commit": "1584c05b27ac31fbccb0ab328bf9f8eb6a7de414 (main, squash merge of PR #14728 '[BlockJoin] Add ParentsChildrenBlockJoinQuery', issue #14565, by Jinny-Wang, merged by msfroh; the guard came from the PR-branch commit b86181a44fde 'Do not support IntraSegment Concurrency in ParentsChildrenBlockJoinQuery', 2025-06-09) and its branch_10x backport 61b32ff6d3772906b12b9e7f855b8607e9261371; the class and the guard landed together [read]; it collides with older code: BooleanWeight#explain has pulled a second scorer since d27ddcb409dd (LUCENE-8008, 2017-11-29) and the Weight javadoc 'may be requested multiple times' dates from fafd6af004e0 (#13542, 2024-09-10, in 10.0.0)",
   "introduced_date": "2025-06-13 (main squash merge; guard first written in the PR branch 2025-06-09); branch_10x backport 2025-09-04",
   "first_affected_version": "10.4.0 [exec] (the first release with the class; 10.3.2 and 9.12.3 do not have it and the repros do not compile there [exec])",
   "affected_versions": "10.4.0, 10.5.0, 10.5.1, 10.5.2 (the last release before 10.6.0) and main ea57360912ed [exec]; the guard is unchanged since the class was added (the only other commit to the file on main, bc601411a31 / #16519, changes only the cost() and setTopLevelScoringClause() signatures) [read]; not fixed upstream: upstream main, branch_10x and branch_10_6 (so 10.6.0, by reading) still carry the guard and no open PR touches the file [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-167.html",
   "repro": "repro/LFV-167/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-864",
   "priority": "low",
   "priority_rank": 673,
   "novelty": "known",
   "withheld": false,
   "area": "core / search: vector-similarity queries (AbstractVectorSimilarityQuery Weight.explain vs scorerSupplier), with consequences in BooleanWeight.explain and FunctionScoreQuery.explain",
   "title": "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",
   "summary": "You run a FloatVectorSimilarityQuery.Adaptive (or the Byte or Float16 variant) with the default decay and call IndexSearcher.explain for a document, and you expect explain to agree with the hits, as the kNN queries do: a document the query does not return is explained as a non-match. Instead explain applies the exact threshold test, so a document above the threshold that the approximate graph search did not collect is explained as '... = Score above threshold' although it is not a hit, and Weight.matches() of the same Weight returns null for it. Wrapped in a BooleanQuery, explain of such a non-hit returns a match with the next hit's score (-da), fails 'assert advanced == doc' (-ea) or throws NullPointerException when the segment has no vector hits, FunctionScoreQuery's explain throws the same NullPointerException, and the hits of a hybrid 'term OR vector' query can be explained with a vector contribution that is not in their score.",
   "impact_class": "crash",
   "introduced_commit": "cd195980ecbcb45e19ce9465854fed0b6be79ea7 ('Add support for similarity-based vector searches (#12679)', author @kaivalnp, author date 2023-12-12 00:48 +0530, committed to main 2023-12-11; branch_9x backport 8089b8c9d33) [read]. The NullPointerException form came with 5b5815a26d14201f32ba60a0a133a092ac666032 ('Fix NPE when LeafReader return null VectorValues (#13162)', author date 2024-03-11; backport 7782be42fb7), which made the weight return a null scorer for a segment where the graph search collects nothing [exec]. The wrappers' explain code is older and unchanged: BooleanWeight.explain d27ddcb409d (LUCENE-8008, 2017-11-29), FunctionScoreQuery.explain a8a63464e7d (LUCENE-7996, 2017-12-06). Not a regression: present since the API was added.",
   "introduced_date": "2023-12-11 (cd195980ecb; author date 2023-12-12 +0530); the NullPointerException form 2024-03-11 (5b5815a26d1)",
   "first_affected_version": "9.10.0 [exec] (tagged 2024-02-20, the first release with vector-similarity queries; 9.9.2 fails to compile on the missing class); the NullPointerException form first in 9.11.0 [exec]",
   "affected_versions": "Every release that has the API, each executed with -da: 9.10.0, 9.11.0, 9.11.1, 9.12.0, 9.12.1, 9.12.2, 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 (also -ea on 9.10.0, 9.11.0, 9.12.3, 10.4.0, 10.5.0 and 10.5.2), the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193 (-ea and -da) [exec]. ByteVectorSimilarityQuery shares the explain [exec]; Float16VectorSimilarityQuery (main only, #16735) inherits it [exec]. DECAY_MAX_QUALITY (exact search) is not affected [read]. Not fixed: the last upstream commit to AbstractVectorSimilarityQuery on main and branch_10_6 is #16104 (author date 2026-05-28), and no upstream commit after a9779ef3c193 (to c5ab3e57b9b, 2026-10-28) touches AbstractVectorSimilarityQuery, BooleanWeight or FunctionScoreQuery [read].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15802",
    "https://github.com/apache/lucene/issues/15784",
    "https://github.com/apache/lucene/issues/16104",
    "https://github.com/apache/lucene/issues/10526",
    "https://issues.apache.org/jira/browse/LUCENE-9487",
    "https://github.com/apache/lucene/issues/16271"
   ],
   "doc": "",
   "repro": "repro/LFV-864/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-875",
   "priority": "low",
   "priority_rank": 674,
   "novelty": "new",
   "withheld": false,
   "area": "search / IndriAndQuery (IndriAndWeight.explain)",
   "title": "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)",
   "summary": "You search with an IndriAndQuery of SHOULD clauses, for example IndriAndQuery(SHOULD f:a), and call IndexSearcher.explain for a document that contains none of the clause terms and is not a hit. You expect a no-match explanation (isMatch false), as TermQuery and a BooleanQuery over the same clauses give. Instead IndriAndWeight.explain advances its scorer to the document, checks the result only with 'assert advanced == doc', and returns Explanation.match(scorer.score(), ...) for wherever the scorer landed: a match carrying the next hit's score, or, past the last match, an EOFException or IndexOutOfBoundsException from a norms read (AssertionError with -ea).",
   "impact_class": "crash",
   "introduced_commit": "9cc5c9b7983cf181280e18819f8516dc16ccf1ef (LUCENE-9537 'Add initial Indri search engine functionality to Lucene', issue now apache/lucene#10577; PR apache/lucene-solr#2097 by GitHub cammiemw, reviewed and merged by mikemccand), released through its branch_8x backport a6125fb938553fe2cd8cd035b8ffb329a7a1a288; the unchecked advance and the assert are already in the PR's first commit 087d9d2a07 (2020-11-24), and the review follow-up 88c9c35090 ('IndriAndWeight explain NullPointer fix') added only the 'scorer != null' guard [read]; not a regression: the defect was born with the class",
   "introduced_date": "2021-01-29 (author date of 9cc5c9b7983 and of the backport a6125fb9385; first PR commit 2020-11-24)",
   "first_affected_version": "8.9.0 [exec] (the first release with the Indri classes; 8.8.2 has no IndriAndQuery, so the check does not compile there [exec]; on the main line: 9.0.0)",
   "affected_versions": "8.9.0 to 8.11.4 and every 9.x and 10.x release (9.0.0 to 10.6.0; 10.6.0 run as the branch_10_6 head 4ae946e5a9b9) and main [exec] [read]; not fixed anywhere: upstream main c5ab3e57b9ba, branch_10x and branch_10_6 still have the unchecked advance (last commit to IndriAndWeight.java d0d2aa274fb5, 2024-06-06) [read]. Not affected: 8.8.2 and earlier (no class). All runs with JDK 25 on aarch64 Linux.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-875.html",
   "repro": "repro/LFV-875/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-833",
   "priority": "low",
   "priority_rank": 675,
   "novelty": "new",
   "withheld": false,
   "area": "queries / payloads (SpanPayloadCheckQuery.toString, reached from SpanWeight.explain)",
   "title": "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)",
   "summary": "You build a SpanPayloadCheckQuery over the span 'a b' with payloadToMatch = [null, 'p'], meaning that 'a' must have no payload and 'b' the payload 'p'; the matcher supports exactly this (a null entry matches a position without a payload, a non-null entry never does), and the search finds the document. You expect toString() to print the query and IndexSearcher.explain() to explain the hit. Both throw NullPointerException ('Cannot read field \"bytes\" because \"termText\" is null'), because toString() hands every entry, null included, to Term.toString(BytesRef), and explain builds its description from the query string.",
   "impact_class": "crash",
   "introduced_commit": "e135605e718644c661aaaf015723fcf08073a4b3 on branch_5x (svn r1702892, 'LUCENE-6716: Change SpanPayloadCheckQuery to take List<BytesRef>', author Alan Woodward (GitHub romseygeek); issue LUCENE-6716 = #7774, '+1 LGTM' from dsmiley; no pull request, JIRA/SVN era). It merges the trunk commits 22cc3a1560e2 (adds the matcher branch 'payloadToMatch.get(upto) == null -> matches = payload == null'; its toString used bytes.utf8ToString(), which also throws on null) and 13a64196d0db ('LUCENE-6716: Better toString() for SpanPayloadCheckQuery', the Term.toString(bytes) line still on main) [exec]. Older ingredient: toString() has thrown on a null element since the class was added (LUCENE-2692, 3.1, ToStringUtils.byteArray), but before LUCENE-6716 the matcher gave a null element no meaning [exec]",
   "introduced_date": "2015-09-14 (author dates: 22cc3a1560e 08:52:38Z, 13a64196d0d 09:10:26Z, e135605e718 09:57:24Z)",
   "first_affected_version": "5.4.0 [exec] (tagged 2015-12-10, the first release containing e135605e718; on the trunk line 6.0.0); last unaffected in this form 5.3.2 and 5.3.1 [exec]: there a null element never matches, so the query finds nothing, although toString() already throws on it. The NPE itself is older: 3.1-5.3.2 throw from toString() on a null element, and on 5.2.1 explain() of a matching single-term query with [null] throws too, but there the list is not consulted at payload-less positions ([null] and ['x'] both match) [exec]",
   "affected_versions": "5.4.0, 5.5.5, 6.0.0, 7.7.3, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0 and 10.5.2 [exec]; main a9779ef3c193 [exec]; all 91 release tags from 5.4.0 to 10.5.2 [read]; upstream main 20ced71c1e6 (same file blob as a9779ef3c193), branch_10x, branch_10_6 and branch_9_12 [read], so the released 10.6.0 has it too. Not affected in this form: 3.1-5.3.2 (a null element has no matching meaning; toString() still throws on it) [exec]. Not fixed upstream.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-833.html",
   "repro": "repro/LFV-833/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1190",
   "priority": "low",
   "priority_rank": 676,
   "novelty": "new",
   "withheld": false,
   "area": "index / merged multi-segment postings (MultiPostingsEnum.toString, MultiTermsEnum.postings)",
   "title": "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)",
   "summary": "You index two documents into two segments, with the term 'a' only in the first, and ask MultiTerms.getTermPostingsEnum for the merged postings of 'a'; iterating them correctly gives doc 0 and then NO_MORE_DOCS. You expect toString() to describe the enum, as it does when the term is in every segment. Instead it throws NullPointerException 'Cannot invoke \"org.apache.lucene.index.ReaderSlice.toString()\" because \"this.slice\" is null': the enum keeps one slot per segment but fills only the slots of the segments that hold the term, and toString prints every slot, including the unfilled ones whose slice is null.",
   "impact_class": "minor",
   "introduced_commit": "489b8e82a8c65af7d69d8a3e0ad12fa13c26f0b3 (branch_4x, svn r1607055, the commit that shipped in 4.10.0) and its trunk twin 04ef241474d616d196b10ea9798592559dcc71c2 (svn r1607049), both 'LUCENE-5798: Optimize MultiDocsEnum reuse' by Robert Muir (GitHub rmuir); issue LUCENE-5798 'minor optimizations to MultiDocs(AndPositions)Enum.reset()' = #6860 (JIRA era, no pull request; its discussion does not mention toString) [exec]. It pre-allocated the enum's own slots with null slices and made reset() copy only numSubs of them. Older ingredient: both toString methods date from 24092aab4cd ('add toString for debugging', 2012-07-21); they printed every slot before too, but every slot then carried a slice",
   "introduced_date": "2014-07-01 (author and commit date of both commits); first release 4.10.0 (release tag commit 2014-09-02)",
   "first_affected_version": "4.10.0 [exec] (4.9.0 and 4.9.1 pass [exec]: their reset() copied every slot from MultiTermsEnum, each with a slice, so toString printed unused slots without throwing)",
   "affected_versions": "Every release from 4.10.0 through 10.6.0 (4ae946e5a9b) and main. Executed and reproduced: 4.10.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.12.3, 10.5.2, 10.6.0 and main 5adff78bb168 (-ea and -da) [exec]; the remaining releases contain the change [read]. Not affected: 4.0.0-alpha to 4.9.1 (4.9.0 and 4.9.1 executed, pass); before 4.0 the class did not exist. Not fixed upstream: upstream main 1c2072f0284 (author date 2026-11-02) still prints Arrays.toString(getSubs()) [read]. Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1190.html",
   "repro": "repro/LFV-1190/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-963",
   "priority": "low",
   "priority_rank": 677,
   "novelty": "known",
   "withheld": false,
   "area": "core / search (MultiPhraseQuery.Builder input validation and MultiPhraseQuery.toString)",
   "title": "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",
   "summary": "You build a phrase with MultiPhraseQuery.Builder and pass an empty Term[] for one position, for example the terms of a prefix expansion that found nothing (the class javadoc's 'microsoft app*' recipe); add(Term[]) documents the array as a disjunction, so you expect an empty position to match nothing, or the Builder to reject it with IllegalArgumentException. At the first position Builder.add throws ArrayIndexOutOfBoundsException (it reads terms[0].field(), MultiPhraseQuery.java:127), while at any later position the array is accepted and search correctly returns 0 hits, but toString() throws ArrayIndexOutOfBoundsException (terms[0].text(), :345). So logging the query fails, IndexSearcher.explain throws for a BooleanQuery or IndriAndQuery that holds it (BooleanWeight.java:99 and :103, IndriAndWeight.java:88), and on a field indexed without positions the documented IllegalStateException becomes that exception, because its message prints the query (:255-262).",
   "impact_class": "crash",
   "introduced_commit": "59f20d1ada41ae3b97f60ab283aadad457d8ad33 (SVN r150582, 2004-10-10, 'Deprecate PhrasePrefixQuery and copy it to MultiPhraseQuery; also fix toString() in MultiPhraseQuery'; pre-JIRA, no issue or review), which created MultiPhraseQuery as a copy of PhrasePrefixQuery with both defect lines verbatim: add's 'if (termArrays.size() == 0) field = terms[0].field();' and toString's 'buffer.append(terms[0].text())' [read]. Inherited from PhrasePrefixQuery (15bbd8def83, 2002-07-18, first released in 1.3, same defect [exec]). The Builder API named in the title arrived with LUCENE-7064 (#8120, 40aab73a4c9, 2016-03-03, 6.0.0), which moved the unchanged add body into Builder.add. Not a regression.",
   "introduced_date": "2004-10-10 (MultiPhraseQuery created; predecessor PhrasePrefixQuery 2002-07-18; Builder API 2016-03-03)",
   "first_affected_version": "1.9 (the first release with MultiPhraseQuery; executed on 1.9.1, because 1.9.0 is not on Maven Central) [exec]; the MultiPhraseQuery.Builder API: 6.0.0 [exec]; the predecessor PhrasePrefixQuery had the same defect from 1.3 [exec]",
   "affected_versions": "every release that has MultiPhraseQuery, 1.9.1 through 10.6.0 (branch_10_6 4ae946e5a9b9) and main a9779ef3c193; not fixed upstream (main 645d4fe14a2 of 2026-10-28 has the same lines) [exec]. How it surfaces changed over time: up to 5.1.0 search on the accepted query threw as well; since 5.2.0 (LUCENE-6421) search returns 0 hits and only toString and the paths that print the query fail: explain of a non-matching required BooleanQuery clause since 5.2.0 [exec], the positionless-field IllegalStateException message since 5.1.0 [read]; since 10.5.0 (#16229) explain of a BooleanQuery with it as a SHOULD clause throws for every hit (that leg passes on 9.12.3, 10.0.0 and 10.4.0) [exec]. Caveat: 1.9.1 to 8.11.4 ran the follow-up's main() probes and 9.12.3 and later the finder's JUnit; the independent reproduction and the intended-behaviour check independently re-ran only main, 10.5.2 and 9.12.3.",
   "security": "none",
   "upstream_links": [
    "https://lists.apache.org/thread/ozho4o1m123fdrzmq85444yr56js63r1",
    "https://github.com/apache/lucene/issues/16851",
    "https://github.com/apache/lucene/issues/14716",
    "https://github.com/apache/lucene/issues/3600",
    "https://issues.apache.org/jira/browse/LUCENE-2526",
    "https://github.com/apache/lucene/issues/3654"
   ],
   "doc": "",
   "repro": "repro/LFV-963/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1177",
   "priority": "low",
   "priority_rank": 678,
   "novelty": "new",
   "withheld": false,
   "area": "core / search: conjunction iterators (ConjunctionUtils.createConjunction, ConjunctionDISI.ConjunctionTwoPhaseIterator)",
   "title": "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)",
   "summary": "You combine two TwoPhaseIterators with the public ConjunctionUtils.createConjunction(List.of(a.approximation(), b.approximation()), List.of(a, b)), where a has matchCost 100 and b has matchCost 1. You expect a conjunction iterator over their common documents, which is what you get when the same list happens to be in ascending cost order: the javadoc describes both arguments only as lists 'to combine', and the method copies its first list before sorting it. Instead it throws UnsupportedOperationException, because the private ConjunctionTwoPhaseIterator constructor sorts the caller's second list in place by matchCost (CollectionUtil.timSort) before copying it; a LinkedList makes the same call throw IllegalArgumentException 'CollectionUtil can only sort random access lists in-place.' in any order, and a mutable ArrayList comes back reordered.",
   "impact_class": "minor",
   "introduced_commit": "5e0e7a5479bca798ccfe385629a0ca2ba5870bc0: apache/lucene#148 (LUCENE-9204, migrated issue #10244) 'Make ConjunctionDISI package-private and add ConjunctionUtils factory class' by @romseygeek (Alan Woodward), main line only (not cherry-picked to branch_8x). It added the public final ConjunctionUtils, whose createConjunction(List<DocIdSetIterator>, List<TwoPhaseIterator>) hands the caller's lists to ConjunctionDISI unchanged; before it, the list-taking ConjunctionDISI.createConjunction was private and only fresh internal ArrayLists reached the sort [read]. The in-place sort itself is older: LUCENE-6276 (0ed54b3105c on trunk, 9576c06156a on branch_5x, Adrien Grand, 2015-11-13, first release 5.4.0) made the two-phase conjunction constructor CollectionUtil.timSort its List<TwoPhaseIterator> argument, which was safe while every caller was internal.",
   "introduced_date": "2021-05-25 (author date 2021-05-25T12:07:20+01:00, commit date identical; PR #148 merged 2021-05-25T11:07:20Z); first release 9.0.0",
   "first_affected_version": "9.0.0 [exec]; 8.x is not affected [exec]",
   "affected_versions": "Every 9.x and 10.x release, 9.0.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b), and main 5adff78bb168 (12.0.0-SNAPSHOT); never fixed. [exec] the finder's one-test JUnit fails on main with -ea and -da (finder, the intended-behaviour check, history step and the re-run of 2026-11-03) and on the 10.6.0 (finder, the intended-behaviour check, history step), 10.0.0, 9.12.3 and 9.1.0 jars (-ea); the independent reproduction's own public-API test fails on main (-ea, -da; also the adjudication's re-run), 10.6.0 (-ea), 10.5.2 (-ea) and 9.12.3 (-ea, -da); a core-only main() fails on 9.0.0 (-ea, -da). [read] all 34 9.x/10.x release tags contain 5e0e7a5479b, and each still passes the two-phase list uncopied into the in-place sort. Not affected: 8.x and older (API absent; 8.11.4 executed). Not new in 10.6 (10.5.2 fails too). Not fixed upstream: main 1c2072f0284 (2026-11-02) still calls CollectionUtil.timSort(twoPhaseIterators, ...) at ConjunctionDISI.java:354 before toArray at :357 (contents API, 2026-11-03).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1177.html",
   "repro": "repro/LFV-1177/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-154",
   "priority": "low",
   "priority_rank": 679,
   "novelty": "new",
   "withheld": false,
   "area": "search / CachingCollector replay (CachingCollector, CachingCollectorManager)",
   "title": "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",
   "summary": "You run a query once through a CachingCollector (or CachingCollectorManager) and then replay the cached hits into a second-pass collector, expecting the same result as running that collector through IndexSearcher. When the second-pass collector stops a segment early by throwing CollectionTerminatedException, which is how LeafCollector#collect documents early termination and what a stock TopFieldCollector sorted by the index sort does once a segment has more than 1000 hits, IndexSearcher simply moves on to the next segment, but replay lets the exception escape to the caller, without a stack trace. Catching it around replay is no workaround: the later segments are never replayed, so in the repro the top 10 come back as [1000..1009] instead of [0..9].",
   "impact_class": "crash",
   "introduced_commit": "65b70503ab16 (branch_4x, svn r1459408, merged from trunk 986444de446b, r1459400; LUCENE-4862 'Ability to terminate queries on a per-segment basis', GitHub mirror #5927, by jpountz, reviewed on the issue by shaie; pre-GitHub, no PR): it added CollectionTerminatedException and a catch around scoring in IndexSearcher only, and left CachingCollector.replay (since 3.2, LUCENE-3102) without a handler [read]; the getLeafCollector path (then setNextReader) followed with a5c3b88fe7ae (branch_4x r1466057, trunk e2e3e2bfdafd; LUCENE-4858, #5923, by shaie with jpountz, 2013-04-09, also 4.3.0); carried forward unchanged in substance by 85642f59ddf0 (LUCENE-5527, 2014, replay rewritten to its current per-leaf shape) and 8811f31b9ca6 (#12380, 2023, added finish() to the no-score replay but no handler); the CachingCollectorManager entry point 3afffeef5a8d (#16247, by gaobinlong, merged 2026-07-08, first released in 10.6.0) inherits it [read]; no commit on any branch ever added or removed a handler in replay [read]",
   "introduced_date": "2013-03-21 (LUCENE-4862, collect path); 2013-04-09 (LUCENE-4858, getLeafCollector path); 2026-07-08 (#16247, CachingCollectorManager entry point, first released in 10.6.0)",
   "first_affected_version": "4.3.0 [exec] for CachingCollector.replay (4.2.1 is the last release without the bug: CollectionTerminatedException does not exist there [exec]); CachingCollectorManager.replay: 10.6.0 (released 2026-10-29; listed under 10.6.0 in CHANGES.txt)",
   "affected_versions": "every release from 4.3.0 to 10.6.0 (10.6.0 by reading) and main ea57360912ed. [exec] the follow-up's history probes (public-API main() programs, 4 cases: collect and getLeafCollector paths x cacheScores false and true) fail 4 of 4 on 4.3.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea, and -da on 9.12.3, 10.5.2 and main) and pass 4 of 4 with the fix shadowed on main; the finder's legacy JUnit fails 2 of 2 on 9.12.3, 10.5.2 and main; the independent reproduction's JUnit fails 7 of 7 on 10.5.2 and 9.12.3; the intended-behaviour check's index-sort probe (stock TopFieldCollectorManager trigger) fails 2 of 2 on 9.12.3, 10.5.2 and main; the CachingCollectorManager JUnit fails 2 of 2 on main and does not compile on 10.5.2 (class absent). [read] the other releases from 4.3.0 to 10.5.2 by tag containment and the absence of any handler commit; branch_10x, branch_10_6 and branch_9_12 still have no handler (follow-up prior-report record, read, not executed). The stock-collector trigger was executed only on 9.12.3, 10.5.2 and main; older releases ran the minimal custom-collector probe. The 4.x-7.x runs used JDK 25, not the JDK those releases supported. Not executed: x86, a concurrent first pass with intra-segment partitions.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-154.html",
   "repro": "repro/LFV-154/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1068",
   "priority": "low",
   "priority_rank": 680,
   "novelty": "known",
   "withheld": false,
   "area": "grouping / GroupingSearch second-pass cache (score-less CachingCollector / CachingCollectorManager replay into the TopGroups second pass)",
   "title": "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",
   "summary": "You turn on GroupingSearch's documented second-pass cache without cached scores, new GroupingSearch(\"g\").setCaching(10, false), and run an ordinary grouped search over two documents in groups A and B; you expect the same groups as without the cache, because the javadoc presents the cache as an optimisation that the second pass replays. Instead search() throws NullPointerException ('Cannot invoke Scorable.score() because this.scorer is null'): GroupingSearch builds the cache with the caller's cacheScores flag but replays it into a second pass that it builds itself from its defaults (within-group sort Sort.RELEVANCE, includeMaxScore=true), and both need scores, while a score-less replay never sets a Scorer. Whether a search fails depends on the hit count: when the hits overflow the cache, the cache is dropped, the query is re-run and the search succeeds.",
   "impact_class": "minor",
   "introduced_commit": "89b55566d8392657be86e1441a329373e9132257 (LUCENE-3778 'Added a grouping utility class that makes it easier to use result grouping for pure Lucene apps', SVN trunk r1303871, author martijnvg, author date = commit date 2012-03-22T16:15:42Z; pre-GitHub patch, migrated issue apache/lucene#4851) [read] [exec]. Born with the API, not a regression. Changes that kept it: LUCENE-6900 0442747f05d (default within-group sort null -> Sort.RELEVANCE, 5.5.0), LUCENE-7701 caf329717ef (GroupSelector refactor, 7.0.0) and #16247 3afffeef5a8 (CachingCollectorManager, author gaobinlong, author and merge date 2026-07-08; backport d60e550b47f, first released in 10.6.0), after which the same NullPointerException comes through CachingCollectorManager.replay",
   "introduced_date": "2012-03-22",
   "first_affected_version": "4.0.0-alpha [exec]; first GA release 4.0.0 [exec]; 3.6.2 and earlier have no GroupingSearch [exec]",
   "affected_versions": "every release that has GroupingSearch, 4.0.0-alpha through 10.6.0 (released 2026-10-29, 4ae946e5a9b), and main 645d4fe14a20; never fixed (upstream main f815e679bf6c and branch_10_6 unchanged at the fix site, checked 2026-11-01). [exec] the JUnit repro (seed DEADBEEF) fails 1 of 1 on main (-ea and -da) and on 10.6.0 and 10.5.2 (-da); a version-agnostic main() fails with -da on all 15 releases executed (4.0.0, 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2, 10.6.0) and on 4.0.0-alpha; the independent reproduction's own JUnit fails on main (-ea and -da), 10.6.0, 10.5.2 and 9.12.3; the intended-behaviour check re-ran the repro on 10.6.0 (fails). All runs on one aarch64 Linux host with JDK 25.0.3, release jars from Maven Central, SHA-1-checked. Not new in 10.6 (10.5.2 fails the same way).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16247",
    "https://github.com/apache/lucene/issues/4175",
    "https://issues.apache.org/jira/browse/LUCENE-3102",
    "https://github.com/apache/lucene/issues/4851",
    "https://issues.apache.org/jira/browse/LUCENE-3778",
    "https://github.com/apache/lucene/issues/5438"
   ],
   "doc": "",
   "repro": "repro/LFV-1068/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-116",
   "priority": "low",
   "priority_rank": 681,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexingChain per-field schema validation (FieldSchema)",
   "title": "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",
   "summary": "You index a document in which field f carries a skip-indexed doc-values field (for example SortedDocValuesField.indexedField, new in 10.0), IndexWriter correctly rejects it with IllegalArgumentException because f is already indexed without doc values (or because another field of that document is invalid), and you keep adding documents that have f without doc values. You expect only the bad document to be rejected, as for any non-aborting exception, and the next valid documents to be accepted, as they are when the rejected document used doc values without a skip index. Instead every later document with f and no doc values in the same in-memory segment is rejected (\"doc values skip index type: expected 'NONE', but it has 'RANGE'\", or \"field 'f' cannot have docValuesSkipIndexType=RANGE with doc values type NONE\") until the next flush, because IndexingChain.FieldSchema.reset() clears the per-document doc-values type but not the skip index type, so the rejected document's RANGE is left behind.",
   "impact_class": "crash",
   "introduced_commit": "048770205cb (#13449 'Sparse index: optional skip list on top of doc values', by iverase, co-authored by jpountz; milestone 10.0.0), which added the docValuesSkipIndex member to IndexingChain.FieldSchema together with its write in setDocValues and its comparison in assertSameSchema, but no line in reset(); carried forward by b59a357e586 (#13784 'Change docValuesSkipIndex from a boolean to an enum', which left reset() unchanged) [read]; the commit's parent has no doc-values skip index API, so no earlier commit can be affected",
   "introduced_date": "2024-06-13 (#13449 merged into main as 048770205cb); 2024-09-17 (#13784, b59a357e586); 10.0.0 tagged 2024-10-14",
   "first_affected_version": "10.0.0 [exec]",
   "affected_versions": "all 12 releases from 10.0.0 through 10.5.2 (10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2) and main ea57360912ed (unreleased 11.0.0) [exec]; the unreleased introducing commit 048770205cb fails too [exec]; 9.x and older are not affected: they have no doc-values skip index API (the repro does not compile on 9.11.0 and 9.12.3 [exec]; no DocValuesSkipper in 9.11.1, 9.12.0 and 9.12.3 [read]); branch_10x (1309534296e3) and branch_10_6 (2763db11b0a7) still lack the reset line [read], so 10.6.0 (released 2026-10-29) is affected too; not fixed upstream as of main ea57360912ed [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-116.html",
   "repro": "repro/LFV-116/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-127",
   "priority": "low",
   "priority_rank": 682,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexingChain per-field schema validation (frozen-FieldType cache) x columnar addBatch",
   "title": "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)",
   "summary": "You add a document whose 8-dimensional KnnFloatVectorField (built from one shared frozen FieldType) does not match the field's 4 dimensions, and Lucene correctly rejects it; you then index an IndexWriter#addBatch with a 4-dimensional vector column for the same field and add the same kind of 8-dimensional document again. You expect the same IllegalArgumentException, because Lucene requires a field to keep the same data structures in every document and checks each document against them. Instead the batch marks the rejected document's FieldType as already validated, so until the next flush every document with that FieldType instance skips the check: the 8-dimensional vector is accepted and stored as its first 4 values (CheckIndex clean), and a SORTED value for a NUMERIC doc-values field fails with ClassCastException instead of the schema error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "3d895681557 (#15990 'Add experimental columnar indexing api', by Tim-Brooks, merged 2026-05-14; 10.x backport #16066, 3ec3bff01b1): its processBatch calls PerField.trySetValidatedFrozenFieldType although it never sets candidateFieldType, so it promotes a candidate that an earlier rejected document left behind [exec]. The reported same-segment form first fails at 1a6f4040dc6 (#16219 'Allow multiple addBatch columns per field name', by Tim-Brooks, 2026-06-14; 10.x ae74896dd37), which made processBatch reset the field schema and validate through initAndValidateFields, on top of 3ca085e1c77 (#16171 'Address frozen FieldType cache never recovering after type switch', by neoremind, 2026-06-13; 10.x eccb3394382), which made PerField.reset record a candidate for every document and promote it after every successful check [exec]. The cache itself is 9e1c6a37c6e (#15886, 2026-04-07) and is not affected without addBatch [read].",
   "introduced_date": "2026-05-14 (root cause, #15990); 2026-06-14 (reported same-segment form, #16219, after #16171 on 2026-06-13); 10.5.0 is the first release and contains all four commits",
   "first_affected_version": "10.5.0 [exec]",
   "affected_versions": "10.5.0, 10.5.1 and 10.5.2 (latest 10.5.x release) [exec]; main from 3d895681557 (narrow form) or 1a6f4040dc6 (reported form) through ea57360912ed, the upstream main head on 2026-10-26 [exec]; the unreleased branch_10x and branch_10_5, and branch_10_6 (10.6.0, released 2026-10-29), carry the same code [read], so 10.6.0 has it; not applicable: every release before 10.5.0, including 10.4.0 and 9.12.3, where addBatch does not exist (compile error) [exec]; not fixed upstream as of 2026-10-26 (the last IndexingChain.java change on main is #16708, 2026-09-28, which does not touch the cache) [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-127.html",
   "repro": "repro/LFV-127/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-379",
   "priority": "low",
   "priority_rank": 683,
   "novelty": "new",
   "withheld": false,
   "area": "core / document: LatLonPoint distance feature query (dynamic pruning through setMinCompetitiveScore)",
   "title": "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",
   "summary": "You index points with LatLonPoint plus LatLonDocValuesField and run searcher.search(LatLonPoint.newDistanceFeatureQuery(\"loc\", 1, 0, 0, 1000), 1), expecting the closest document, because Scorable#setMinCompetitiveScore lets a scorer skip only documents that score below the threshold and Lucene's own TestLatLonPointDistanceFeatureQuery asserts that pruned (TOP_SCORES) and unpruned (COMPLETE) top-k agree for this query. Instead, once a document 999.999 m due north (score 0.50000024) fills the queue, a document 999.803 m due north (score 0.5000492) is never visited and the farther one is returned. The scorer turns the threshold into a radius with a binary search that stops when the interval is 1 m wide and keeps the lower end (999.729 m, although every distance up to 999.999 m still competes), and the box it then searches adds only 7 cm to that radius, so competitive documents just beyond the box edge are dropped.",
   "impact_class": "silent wrong results",
   "introduced_commit": "10060a6237ccd2785f6cbe248ca7254028f8eb04 'LUCENE-8482: Added feature query in LatLonPoint to boost results by distance' by GitHub iverase (author and committer; a JIRA patch reviewed in the issue thread, migrated to GitHub issue #9528, no pull request) [read]. computeMaxDistance was adapted from LongDistanceFeatureQuery (LUCENE-8340, a9acdfdb544, 2018-09-04), where the same loop is exact on longs; the 7 cm pad in Rectangle.fromPointDistance is older (045659533cd, LUCENE-7147, 2016-03-29, with a 'LUCENE-7143' comment). Not a regression",
   "introduced_date": "2018-09-19",
   "first_affected_version": "8.0.0 [exec] (2019-03-13, the first release with LatLonPoint#newDistanceFeatureQuery; every 7.x release lacks the API [exec])",
   "affected_versions": "Every release from 8.0.0 to 10.6.0 (10.6.0 by reading) and main ea57360912ed; not fixed upstream. [exec] the finder's JUnit fails 5 of 6 (control passes) on main (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and 9.12.3 (-ea and -da); its 8.x port (top-level path only) fails 1 of 1 on 8.0.0, 8.11.4 and 9.0.0 (-ea; 8.0.0 and 8.11.4 also -da) and passes on 8.0.0 with the one-line fix shadowed; the independent reproduction's independent JUnit fails 4 of 6 (both controls pass) on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's scorer-level contract test fails on main (-ea and -da) and 10.5.2 (follow-up). [read] the computeMaxDistance text is identical (whitespace-normalised) in all 51 release tags of the history clone from 8.0.0 to 10.5.2, 'return min' (dload 4; dreturn) is in the 8.0.0, 8.11.4, 9.12.3, 10.5.2 and main jars, and 8.8.2-8.11.3 were not checked one by one; upstream main cf398bfb142c (2026-10-26) has the file byte-identical, branch_10x and branch_10_6 differ only by 'final' modifiers (10.6.0, released 2026-10-29, is affected by reading, not executed). All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-379.html",
   "repro": "repro/LFV-379/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-203",
   "priority": "low",
   "priority_rank": 684,
   "novelty": "new",
   "withheld": false,
   "area": "queries / FunctionScoreQuery block-max pruning (#16431)",
   "title": "FunctionScoreQuery scores negative values as 0, but its block-max bound stays negative, so top-k search skips competitive documents",
   "summary": "You index a numeric doc-values field with a skip index (NumericDocValuesField.indexedField(\"delta\", v)) and search BooleanQuery(SHOULD FunctionScoreQuery(MatchAllDocsQuery, DoubleValuesSource.fromLongField(\"delta\")), SHOULD TermQuery(body:b)) for the top hit, expecting the same hit as an exhaustive search, because FunctionScoreQuery documents that a negative value simply scores 0 (MIGRATE.md, LUCENE-7996). Instead, with 5,000 documents where doc 0 has delta 1, all others have -1000, and only doc 4999 matches body:b, TOP_SCORES and the plain IndexSearcher.search(q, 1) return doc 0 (score 1.0) instead of doc 4999. The cause is that the scorer's getMaxScore returns innerMaxScore * valueMaxScore * boost without the clamp at 0 that score() applies, so a block of negative values reports a bound of -1000 for documents that all score 0, and MaxScoreBulkScorer skips windows that hold competitive documents.",
   "impact_class": "silent wrong results",
   "introduced_commit": "0d4f93a9ff93ccc396c1323f26416b57d8dc08d9 on main (apache/lucene#16431 'Enable Block-Max WAND dynamic pruning for FunctionScoreQuery via DocValuesSkipper (+422% QPS)', by rajat315315 with uschindler as co-author, resolves #16429, merged 2026-08-22) [exec]; it replaced the scorer's +Infinity bound with innerMaxScore * valueMaxScore * boost and added the skipper-based DoubleValuesSource bound, without the 0 clamp that score() has applied since LUCENE-7996 (a8a63464e7d, 2017); the silent wrong top hit became reachable end to end with #16697 (d150ba27d11, by easyice, 2026-10-09), which fixed a separate advanceShallow defect that made the tested queries throw first [exec]",
   "introduced_date": "2026-08-22 (0d4f93a9ff9 on main); silent wrong top hit reachable end to end from 2026-10-09 (d150ba27d11, #16697)",
   "first_affected_version": "unreleased (main only; 11.0.0 would be the first release with it) [exec]",
   "affected_versions": "main (11.0.0-SNAPSHOT) from 0d4f93a9ff9 (2026-08-22) through ea57360912ed (upstream main HEAD on 2026-10-26) [exec]; not affected: 10.0.0 and 10.5.2 [exec] and the parent commit a1fcd50799f [exec]; not applicable: 9.x [exec]; unreleased branch_10x and branch_10_6 (last fetched 2026-10-24) and branch_10_5 do not contain #16431 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-203.html",
   "repro": "repro/LFV-203/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-406",
   "priority": "low",
   "priority_rank": 685,
   "novelty": "new",
   "withheld": false,
   "area": "queries / function queries (ValueSourceScorer behind FunctionRangeQuery, LUCENE-7996 non-negative score rule; the hit loss surfaces in core WANDScorer)",
   "title": "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",
   "summary": "You index a document with DoubleDocValuesField(\"d\", -5.0) and search new FunctionRangeQuery(new DoubleFieldSource(\"d\"), -10.0, 10.0, true, true), expecting a non-negative score, because since LUCENE-7996 (8.0) scorers must not produce negative scores and FunctionQuery over the same source scores that document 0. Instead it scores -5.0 (-Infinity and NaN become -Float.MAX_VALUE), because ValueSourceScorer.score() returns the raw value and LUCENE-7996 clamped FunctionQuery, BoostedQuery and FunctionScoreQuery but not this scorer. Since 10.1.0 this also loses hits: with minimumNumberShouldMatch = 2 over SHOULD clauses FunctionRangeQuery(d, open range), body:a and body:b (sparse term clauses; also dense ones since 10.5.0), a matching document whose value is -Infinity is missing from search(q, 10), whose totalHits says '3 hits' while count(q) is 4, because WANDScorer rejects a candidate whose scaled score is below the initial minimum competitive score of 0.",
   "impact_class": "silent wrong results",
   "introduced_commit": "a8a63464e7da63b3dbc884634fd0e00b3f0c140b (LUCENE-7996 'Queries are now required to produce positive scores.', a JIRA patch, now GitHub issue #9044, no pull request): it made non-negative scores a rule for every Scorer and replaced FunctionQuery's identical NaN/-Infinity -> -Float.MAX_VALUE mapping with a 0 clamp, but did not touch ValueSourceScorer or FunctionRangeQuery (neither is among its 22 files) [read]; ValueSourceScorer.score() itself is unchanged since LUCENE-6720 (13f8ab93a97 trunk / 88d137632d3 branch_5x, 2015-08-06), the raw floatVal score dates from SOLR-2429 (e219ad401cf, 2011) [read]; the hit loss comes from WANDScorer's per-candidate score check added by #14021 'Make WANDScorer compute scores on the fly' (d9aa525c9ea main / 3f620dcd34f release line, first released in 10.1.0) [read]; #16176 'Restore WANDScorer for TOP_SCORES + minShouldMatch > 1' (135b348b370 main / 4f720f944b8 release line, first released in 10.5.0) widened it to dense top-level queries, which 10.1.0 to 10.4.0 ran with BooleanScorer [exec]",
   "introduced_date": "2017-12-06 (a8a63464e7d); hit loss from 2024-11-26 (#14021, first released in 10.1.0), widened to dense top-level queries on 2026-06-03 (#16176, first released in 10.5.0)",
   "first_affected_version": "8.0.0 [exec] for the negative score (first release with a8a63464e7d; 5.4.0 to 7.7.x score the same way but before the rule, identical to FunctionQuery; 7.7.3 executed); 10.1.0 [exec] for the hit loss (sparse top-level and nested minimumShouldMatch >= 2 queries); 10.5.0 [exec] for dense top-level ones",
   "affected_versions": "every release from 8.0.0 through 10.6.0 (10.6.0 by reading) and main ea57360912ed [exec]; hit loss [exec]: sparse top-level shape (4 target documents plus 96 fillers that match one clause) fails on 10.1.0, 10.4.0, 10.5.2 and main and passes on 9.12.3 and 10.0.0; nested shape (MUST (minimumShouldMatch=2 query) + MUST body:x) fails on 10.1.0, 10.4.0, 10.5.2 and main and passes on 9.12.3 and 10.0.0; dense 4-document top-level shape fails on 10.5.0, 10.5.2 and main and passes on 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.2.2, 10.3.0 and 10.4.0; with -ea all three shapes throw AssertionError at WANDScorer.scaleMaxScore (WANDScorer.java:92) on main; the follow-up security probe also shows it on main and 10.5.2 (20,000 documents, 361 -Infinity documents missing); not affected: 5.4.0 to 7.7.x (no rule yet), and FunctionRangeQuery does not exist before 5.4.0; branch_10x (unreleased) and branch_10_6 (10.6.0, released 2026-10-29) have the same ValueSourceScorer.score() [read]; not fixed upstream",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-406.html",
   "repro": "repro/LFV-406/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-189",
   "priority": "low",
   "priority_rank": 686,
   "novelty": "new",
   "withheld": false,
   "area": "search / function scoring (DoubleValuesSource skip-index score bounds for FunctionScoreQuery block-max pruning)",
   "title": "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",
   "summary": "You index doubles as raw IEEE bits in a NUMERIC doc-values field with a skip index (NumericDocValuesField.indexedField('rating', Double.doubleToRawLongBits(v))) and search BooleanQuery(SHOULD FunctionScoreQuery(MatchAllDocsQuery, DoubleValuesSource.fromDoubleField('rating')), SHOULD TermQuery) for the top hit, expecting the same top hit as an exhaustive search (a NaN value simply scores 0, as upstream TestFunctionScoreQuery#testNaN expects). Instead, with 5,000 docs valued 0.5, one NaN at doc 4500 and 50.0 at doc 4999, TOP_SCORES returns doc 1 (score 4.19) instead of doc 4999 (score 50). The cause is that fromDoubleField declares Double::longBitsToDouble INCREASING, so a block's maximum is read as the decoded largest raw long: NaN's raw bits are above every number's, giving a NaN bound, and negative values are in reverse raw order, so a block holding {-1.0, -2.0} reports getMaxScore -2.0 and getMinScore -1.0.",
   "impact_class": "silent wrong results",
   "introduced_commit": "0d4f93a9ff9 on main (apache/lucene#16431 'Enable Block-Max WAND dynamic pruning for FunctionScoreQuery via DocValuesSkipper (+422% QPS)', by rajat315315 with uschindler as co-author, resolves #16429, merged 2026-08-22) [exec]; it attached Monotonicity.INCREASING to the raw-bits decoders Double::longBitsToDouble and Float.intBitsToFloat((int) v), which fromDoubleField/fromFloatField have used since LUCENE-5325 (3f24fd81c83, 2016), and added the skipper-based getMaxScore/getMinScore that decode skipper.maxValue/minValue through them; the end-to-end wrong top hit became reachable with #16697 (d150ba27d11, by easyice, 2026-10-09), which fixed a separate advanceShallow defect that made the tested queries throw first [exec]",
   "introduced_date": "2026-08-22 (0d4f93a9ff9 on main); wrong top hit reachable end to end from 2026-10-09 (d150ba27d11, #16697)",
   "first_affected_version": "unreleased (main only; 11.0.0 would be the first release with it) [exec]",
   "affected_versions": "main (11.0.0-SNAPSHOT) from 0d4f93a9ff9 (2026-08-22) through ea57360912ed (upstream main HEAD on 2026-10-26) [exec]; not affected: 10.0.0 and 10.5.2 [exec] and the parent commit a1fcd50799f [exec]; not applicable: 9.x [exec]; unreleased branch_10x (1309534296e) and branch_10_6 (2763db11b0a) do not contain #16431 and have no Monotonicity [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-189.html",
   "repro": "repro/LFV-189/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-214",
   "priority": "low",
   "priority_rank": 687,
   "novelty": "new",
   "withheld": false,
   "area": "search / function scoring (DoubleValues.withDefault score bound for FunctionScoreQuery block-max pruning, #16431)",
   "title": "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",
   "summary": "You write a DoubleValuesSource that returns DoubleValues.withDefault(DoubleValuesSource.fromLongField(\"price\").getValues(ctx, scores), 100) over a price field indexed with a skip index (NumericDocValuesField.indexedField), and search BooleanQuery(SHOULD FunctionScoreQuery(MatchAllDocsQuery, thatSource), SHOULD TermQuery(tag:t)) for the top hit, expecting the document without a price (which scores the default 100) to win, as it does in an exhaustive search. Instead, with 12,288 documents (prices i % 10, doc 0 = 50, doc 9000 without a price), the plain IndexSearcher.search(q, 1) returns doc 0 (score 50.0018) instead of doc 9000 (score 100). The cause is that withDefault.getMaxScore returns the wrapped source's bound, the skip-index block maximum, which counts only documents that have a value (9 in doc 9000's block), although withDefault itself produces missingValue (100) for documents without one, so pruning skips the block that holds the true top hit.",
   "impact_class": "silent wrong results",
   "introduced_commit": "0d4f93a9ff93ccc396c1323f26416b57d8dc08d9 on main (apache/lucene#16431 'Enable Block-Max WAND dynamic pruning for FunctionScoreQuery via DocValuesSkipper (+422% QPS)', by rajat315315 with uschindler as co-author, related issue #16429, merged 2026-08-22) [exec]; it added the DoubleValues bound API and, in the same diff, the withDefault getMaxScore override that forwards in.getMaxScore(upTo), plus the skipper-based field-source bound that makes the forwarded bound finite; withDefault itself dates from LUCENE-7737 (2f2e00ffe23, 2017, first released in 7.0.0) and had no bound to get wrong before; the end-to-end wrong top hit became reachable for the tested query shape with #16697 (d150ba27d11, by easyice, 2026-10-09), which fixed a separate advanceShallow defect that made the tested query throw in the skipper first [exec]",
   "introduced_date": "2026-08-22 (0d4f93a9ff9 on main); silent wrong top hit reachable end to end from 2026-10-09 (d150ba27d11, #16697) for the executed query shape",
   "first_affected_version": "unreleased (main only; 11.0.0 would be the first release with it) [exec]",
   "affected_versions": "main (11.0.0-SNAPSHOT) from 0d4f93a9ff9 (2026-08-22) through ea57360912ed (upstream main HEAD, checked 2026-10-26) [exec]; not affected: 10.0.0 [exec] and 10.5.2 [exec] (the end-to-end test passes 4/4; the bound API does not exist there, so the unit repro is a compile error) and the parent commit a1fcd50799f [exec]; not applicable: 9.12.3 [exec]; unreleased branch_10x, branch_10_6 and branch_10_5 do not contain #16431 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-214.html",
   "repro": "repro/LFV-214/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-221",
   "priority": "low",
   "priority_rank": 688,
   "novelty": "new",
   "withheld": false,
   "area": "search / function scoring (DoubleValuesSource skip-index score bounds for FunctionScoreQuery block-max pruning)",
   "title": "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",
   "summary": "You index a long counter with the doc-values skip index (NumericDocValuesField.indexedField('count', v)) and search BooleanQuery(SHOULD BoostQuery(FunctionScoreQuery(MatchAllDocsQuery, DoubleValuesSource.fromLongField('count')), 1.5f), SHOULD TermQuery(body:b)), expecting the same top hit as an exhaustive search. Instead, with 5,000 docs where doc 0 holds 2^24 and doc 4999 holds 2^24 + 1, the pruned search (TOP_SCORES, which plain IndexSearcher.search(q, 1) also uses) returns doc 0 (score 25165824) instead of doc 4999 (score 25165826). The cause is that the block bound is the decoded block maximum cast to the nearest float (2^24 + 1 becomes 2^24) and FunctionScoreQuery multiplies that rounded float by the boost, so the block's bound (25165824) is one float step below the score it must cover and the block is skipped; ordinary doubles do the same (0.065 with boost 1.1 scores 0.0715 under a bound of 0.071499996).",
   "impact_class": "silent wrong results",
   "introduced_commit": "0d4f93a9ff93ccc396c1323f26416b57d8dc08d9 on main (apache/lucene#16431 'Enable Block-Max WAND dynamic pruning for FunctionScoreQuery via DocValuesSkipper (+422% QPS)', by rajat315315 with uschindler as co-author, related issue #16429, merged 2026-08-22) [exec]; it added both halves of the mismatch, the nearest-float cast of the decoded skipper bound and the float product innerMaxScore * valueMaxScore * boost, while score() has returned (float) (value * boost) from the exact double since LUCENE-7996 (a8a63464e7d, 2017), which was harmless while the bound was +Infinity; the silent wrong top hit of the tested query became reachable end to end with #16697 (d150ba27d11, by easyice, 2026-10-09), which fixed a separate advanceShallow defect that made that query throw first and kept the cast [exec]",
   "introduced_date": "2026-08-22 (0d4f93a9ff9 on main); wrong top hit of the tested query reachable end to end from 2026-10-09 (d150ba27d11, #16697)",
   "first_affected_version": "unreleased (main only; 11.0.0 would be the first release with it) [exec]",
   "affected_versions": "main (11.0.0-SNAPSHOT) from 0d4f93a9ff9 (2026-08-22) through 645d4fe14a2 (upstream main head on 2026-10-29) [exec]; not affected: 10.0.0 [exec] and 10.5.2 [exec] (the version-portable repro passes; the DoubleValues bound API does not exist there and FunctionScoreQuery's bound is +Infinity) and the parent commit a1fcd50799f [exec]; not applicable: 9.x [exec]; unreleased branch_10x and branch_10_6 do not contain #16431 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-221.html",
   "repro": "repro/LFV-221/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-841",
   "priority": "low",
   "priority_rank": 689,
   "novelty": "known",
   "withheld": false,
   "area": "codecs / legacy scalar-quantized vectors (util/quantization ScalarQuantizer, backward-codecs Lucene99ScalarQuantizedVectorsReader)",
   "title": "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)",
   "summary": "You index a field with the Lucene99 HNSW scalar-quantized format (int7, EUCLIDEAN) on 10.3.2 or 9.12.3, one segment holds only documents whose vector is [1,1,1,1], so the writer stores the quantiles (1, 1) and every code 0; you then open the unchanged index on main and search for [1,1,1,1]. Every release reader tested (9.9.2 to 10.5.2) decodes code 0 as 1.0, as the ScalarQuantizer formula for the stored quantiles says, and ranks those exact matches first with score 1.0. On main the reader rebuilds the quantizer through the min == max widening added by #14049, decodes those vectors as [-126,-126,-126,-126], and the exact matches score 1.5e-5 and rank last behind a document with half the similarity; int4 fields decode 15 units low, and DOT_PRODUCT and COSINE exact matches score 0.0.",
   "impact_class": "silent wrong results",
   "introduced_commit": "6b0112cdee284cae9143402d7dd80fdaf4d22f93 (GITHUB#14049 'Randomize KnnVector codec params in RandomCodec; addresses gh-14047', author msokolov, main only, milestone 11.0.0): it added 'if (minQuantile == maxQuantile) { minQuantile - divisor; maxQuantile + divisor }' to the ScalarQuantizer constructor, which the Lucene99 reader (a47ba3369f4, #12729, and 07d3be59af8, #13197) also applies to the quantiles it reads from old segments [exec]",
   "introduced_date": "2024-12-09 (author and commit date of 6b0112cdee2, 11:22:43 -0500; PR merged 2024-12-09T16:22:44Z)",
   "first_affected_version": "unreleased (main / 11.0.0-SNAPSHOT only: no release tag 9.9.0-10.5.2 and no head of branch_10x, branch_10_5 or branch_10_6 has the widening [read]; the first release that would ship it is 11.0.0)",
   "affected_versions": "main from 6b0112cdee2 (2024-12-09) through a9779ef3c193 [exec]; upstream main 20ced71c1e6 has a byte-identical ScalarQuantizer.java [read]. Affected data: segments written by 9.9.0-10.3.2, the releases that write this format [exec]; 10.x-written segments are read on main since 6b0112cdee2, 9.x-written ones by default since #16741 (2026-10-15) [read]. Not affected [exec]: the readers 9.9.2, 9.12.3, 10.0.0, 10.1.0, 10.3.2, 10.4.0 and 10.5.2 and the main snapshot a833887be67 pass on the same index bytes. A branch_10x backport of the ScalarQuantizer change was proposed in the #14049 review (2026-06-15, agreed 2026-07-10) but has not landed [read]. All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/13480",
    "https://github.com/apache/lucene/issues/14049",
    "https://github.com/apache/lucene/issues/16907",
    "https://github.com/apache/lucene/issues/13867",
    "https://github.com/apache/lucene/issues/13874",
    "https://github.com/apache/lucene/issues/13912"
   ],
   "doc": "",
   "repro": "repro/LFV-841/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-902",
   "priority": "low",
   "priority_rank": 690,
   "novelty": "new",
   "withheld": false,
   "area": "search / similarities (LMDirichletSimilarity)",
   "title": "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",
   "summary": "You configure LMDirichletSimilarity with mu = 0, which both constructors accept ('must be a non-negative finite value') and which upstream's TestLMDirichletSimilarity uses as its 'minimum value'. You expect documents that contain the query term more often than the collection model predicts to get a positive score and be ranked, as they are for every mu > 0 down to Float.MIN_VALUE, where the score already equals its finite mu -> 0 limit log(tf/(dl*P)). Instead score() computes log(1 + tf/0) + log(0/dl) = +Infinity + -Infinity = NaN, the 'score > 0 ? score : 0' clamp returns 0.0, and every hit scores 0.0, so the best match can come back last; explain() shows 'Infinity = term weight' and '-Infinity = document norm' under a 0.0 total.",
   "impact_class": "silent wrong results",
   "introduced_commit": "cfaf91c73981 (LUCENE-2959 / #4033, svn r1169470: the merge of the flexscoring branch into trunk, from JIRA patches, no PR) [read]. The two pieces were written on the flexscoring branch, which is not on main's ancestry: the two-log formula in 8f73f80d1d7 (LUCENE-3220 / #4293, 2011-07-15; mu = 0 gave NaN) and the clamp in 93bf76506b4 (LUCENE-3357 / #4430, 2011-08-20; it turned that NaN into 0). 42717d5f4bb (LUCENE-7997 / #9045, 2017-10-24, first in 8.0.0) added the 'non-negative finite value' check, which admits mu = 0, and the mu = 0 test case, and kept both logs and the clamp. Not a regression.",
   "introduced_date": "2011-09-11 (cfaf91c7398, author date; branch commits 2011-07-15 and 2011-08-20; constructor check admitting 0: 2017-10-24)",
   "first_affected_version": "4.0.0-ALPHA [exec] (the first release with LMDirichletSimilarity; first GA release 4.0.0 [exec]; 3.6.2 and earlier have no such class [exec])",
   "affected_versions": "every release that has the class: 4.0.0-ALPHA and all 130 GA releases 4.0.0..10.5.2 [exec], 4.0.0-BETA [read]; the candidate JUnit fails 2 of 2 on 9.12.3, 10.0.0, 10.5.2 and main, the independent reproduction's own JUnit fails 2 of 2 on 9.12.3 and 10.5.2 [exec]; the branch_10_6 head 4ae946e5a9b (10.6.0-SNAPSHOT) [exec]; main a9779ef3c193 [exec]. Before 8.0.0 score() ran in float and mu = Float.MIN_VALUE is degenerate too (one hit Infinity, the others 0), so the contrast with a tiny positive mu holds cleanly from 8.0.0; mu = 1e-10 gives the finite limit in every release [exec]. Not fixed upstream: the last commit on the file is dab731175c8 (#13845, author and committer date 2024-10-04) on main and its backport cbd8b5218ad on branch_10_6 [read]. All runs on JDK 25 (aarch64 Linux).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-902.html",
   "repro": "repro/LFV-902/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-750",
   "priority": "low",
   "priority_rank": 691,
   "novelty": "new",
   "withheld": false,
   "area": "misc / similarities (SweetSpotSimilarity hyperbolicTf helper)",
   "title": "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",
   "summary": "You subclass SweetSpotSimilarity so that tf() returns hyperbolicTf(freq), as its javadoc suggests, call setHyperbolicTfFactors(0, 2, 10, 400) and search, expecting the documented curve min+(max-min)/2*(tanh((freq-xoffset)*ln(base))+1): a tf near min (0) for frequencies far below the midpoint 400, rising to max (2) above it. Instead hyperbolicTf returns the maximum 2.0 for every frequency from 1 to 91 and drops to 0.0 at 92, so a document that contains the term once outranks an equally long one that contains it 400 times. Far below the midpoint Math.pow(base, xoffset - freq) overflows to Infinity (once xoffset - freq exceeds about 308 at base 10, about 2705 at the default base 1.3), the ratio becomes NaN, and the guard 'return Float.isNaN(result) ? max : result', which is right only for the overflow above the midpoint, returns max.",
   "impact_class": "silent wrong results",
   "introduced_commit": "d2b63d328be030bfd659319cdeea8b3adeb6f10e (LUCENE-577 'SweetSpotSimiliarity', initial check-in of SweetSpotSimilarity by hossman, SVN r409472, mirrored as apache/lucene#1655; no pull request) [read]: the Math.pow ratio and the NaN guard were both in the first check-in, so this is not a regression; the only later commit touching the method body, 2cbf261032dc (LUCENE-9570, 2021-01-05), is a whitespace-only reformat (the body is token-identical to 2006 on main), and 9089a6c0fb5 (2012) changed only javadoc (gnuplot/SVG links, documented default base)",
   "introduced_date": "2006-05-25",
   "first_affected_version": "2.0.0 [exec]; 1.9.1 is not affected because SweetSpotSimilarity does not exist there (the portable repro does not compile) [exec]",
   "affected_versions": "Every release that ships SweetSpotSimilarity, 2.0.0 through 10.5.2, 10.6.0 [exec], and main a9779ef3c193; never fixed (upstream main f7bcc0abd816, branch_10x and branch_10_6 still have the guard at SweetSpotSimilarity.java:178; no open PR touches the file; read 2026-10-27). [exec] the portable main() HyperbolicTfHistoryRepro fails with identical values, its four controls passing, on 17 releases (2.0.0, 2.4.1, 2.9.4, 3.0.3, 3.6.2, 4.0.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2) and on main (-ea and -da), and passes on main with the fix shadowed; the finder's JUnit fails 4 of 5 on 9.12.3, 10.5.2 and main (-ea and -da); the independent reproduction's JUnit fails 4 of 5 on 9.12.3, 10.5.2 and main (-ea and -da); the intended-behaviour check's probe shows the same overflow thresholds on 9.12.3, 10.5.2 and main. [read] the hyperbolicTf body (whitespace stripped) is identical at every other checked tag (2.9.2, 3.0.1, 8.8.1) and is the same in the releases in between. All runs with JDK 25.0.3 on aarch64; pure Java arithmetic (Math.pow overflow to Infinity is specified behaviour, and the trigger inputs sit far past the overflow point)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-750.html",
   "repro": "repro/LFV-750/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-258",
   "priority": "low",
   "priority_rank": 692,
   "novelty": "new",
   "withheld": false,
   "area": "document / FeatureField sigmoid scoring (FeatureField.SigmoidFunction behind newSigmoidQuery; the same arithmetic is copied in queries / intervals IntervalScoreFunction.SigmoidFunction behind the 4-argument IntervalQuery constructor)",
   "title": "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",
   "summary": "You rank documents with FeatureField.newSigmoidQuery (or IntervalQuery's pivot-and-exponent constructor) and pick a steep exponent with a large or tiny pivot, values the factory accepts because it only requires both to be positive and finite. You expect the documented score weight * S^exp / (S^exp + pivot^exp), a number between 0 and weight that equals weight/2 at S = pivot. Instead SigmoidFunction precomputes pivot^exp as a double, which becomes +Infinity or 0 for such parameters, so scores come out as Inf/Inf or 0/0 = NaN: with pivot 2^20 and exponent 60 every document scores NaN; since 10.2.0 NaN hits rank ahead of correctly scored ones, so the best document can come last, and on 9.x (assertions off) TopDocs even returns placeholder hits with doc id 2147483647.",
   "impact_class": "silent wrong results",
   "introduced_commit": "710993435f365fce44a60b7c498ce6af8327f92c (master) / 70cc7b68783b313a845996dac9e28c3ea6ad61e3 (branch_7x, the copy that shipped first, in 7.4.0): 'LUCENE-8197: Efficient integration of static scoring factors.' by jpountz, a JIRA patch with no pull request (the issue is now #9244). The commit created FeatureField; its SigmoidFunction already precomputed pivotPa = Math.pow(pivot, a) and scored (float) (weight * (1 - pivotPa / (Math.pow(f, a) + pivotPa))), and newSigmoidQuery already accepted every finite pivot > 0 and exp > 0, so no earlier version of the code was correct [read]. IntervalQuery copy: a8266492416dbc2fcf665983d1cac141e50fa9eb (master) / 18c3986cc4bdb38949fae14bd771621345d41776 (branch_8x), 'LUCENE-8633: Remove term weighting from IntervalQuery scores' by romseygeek (now #9679), which added IntervalScoreFunction.SigmoidFunction with the same arithmetic (IntervalScoreFunction.java:112, :117, :128 on main, blamed to a8266492416) [read]. Later commits that touched SigmoidFunction (9b9776a7143 LUCENE-8313, 2d6ad2fee6d LUCENE-9570 reformatting, 0f5359a2ac6 #13691 explain text, f59ff9220ec #15137 bulk scorer) left the arithmetic unchanged [read].",
   "introduced_date": "2018-03-20 (FeatureField, LUCENE-8197); 2019-01-16 (IntervalQuery copy, LUCENE-8633)",
   "first_affected_version": "7.4.0 [exec] (the first release with FeatureField; 7.3.1 does not have the API, the probe does not compile [exec]); IntervalQuery copy: 8.0.0 [exec] (in lucene-sandbox under org.apache.lucene.search.intervals; 7.7.3 has IntervalQuery but not the (field, source, pivot, exp) constructor [exec]; moved to lucene-queries in 8.2.0 by LUCENE-8856)",
   "affected_versions": "FeatureField copy: every lucene-core release from 7.4.0 to 10.5.2 (67 releases: 7.4.0-7.7.3, all 27 8.x, all 21 9.x and all 12 10.x up to 10.5.2) and main ea57360912ed [exec]. IntervalQuery copy: every release from 8.0.0 to 10.5.2 (60 releases) and main [exec]. Not affected: 7.0.0-7.3.1 (API absent) [exec]. The NaN arithmetic never changed, but the visible symptom depends on the collector [exec]: 7.4.0-10.0.0 with -ea, search() throws TopScoreDocCollector's AssertionError; 7.4.0-10.0.0 with -da, TopDocs holds placeholder hits (doc 2147483647, score -Infinity) in place of real documents; 10.1.0 returns only 1 of 4 hits; 10.2.0 to main return every hit, with NaN scores ranked ahead of finite ones; explain() reports NaN on every release. Not fixed on main, branch_10x or branch_10_5 [read]. All runs on aarch64 with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-258.html",
   "repro": "repro/LFV-258/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-898",
   "priority": "low",
   "priority_rank": 693,
   "novelty": "new",
   "withheld": false,
   "area": "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)",
   "title": "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",
   "summary": "You rank with FeatureField.newSaturationQuery, whose javadoc says it 'will score documents as weight * S / (S + pivot)' (newSigmoidQuery and IntervalQuery's scoring state the same kind of formula), a value that is positive and grows with S, so a document with a smaller feature value should score lower but above 0. The code instead computes weight * (1 - pivot / (S + pivot)) (and 1 - k^a / (S^a + k^a) for the sigmoid) so that rounding cannot make scores decrease, and when S is far below the pivot the sum S + pivot rounds to almost exactly the pivot and the subtraction cancels. With pivot 1000 a document with S = 1e-5 scores exactly 0.0 while explain() prints 'computed as w * S / (S + k)', with the library's default pivot 199 adjacent pairs of distinct stored values tie, and IntervalQuery gives intervals 1,000,000 and 1,030,000 positions wide the same score and a 2^25-wide interval 0.0.",
   "impact_class": "silent wrong results",
   "introduced_commit": "710993435f365fce44a60b7c498ce6af8327f92c on master / 70cc7b68783b313a845996dac9e28c3ea6ad61e3 on branch_7x (the copy that shipped in 7.4.0): 'LUCENE-8197: Efficient integration of static scoring factors.' by jpountz, committed from a JIRA patch with no pull request (the issue is now #9244). It created FeatureField with SaturationFunction already returning weight * (1 - pivot / (f + pivot)) and SigmoidFunction (float) (weight * (1 - pivotPa / (Math.pow(f, a) + pivotPa))), under the comment that the value 'should be f / (f + k)' and is rewritten 'to make sure it doesn't decrease with f in spite of rounding', so no earlier version was correct. IntervalQuery copy: a8266492416dbc2fcf665983d1cac141e50fa9eb (master) / 18c3986cc4bdb38949fae14bd771621345d41776 (branch_8x), 'LUCENE-8633: Remove term weighting from IntervalQuery scores' by romseygeek (now #9679), which copied both expressions and the comment into IntervalScoreFunction [read]",
   "introduced_date": "2018-03-20 (FeatureField, LUCENE-8197); 2019-01-16 (IntervalScoreFunction copy, LUCENE-8633)",
   "first_affected_version": "7.4.0 [exec] (the first release with FeatureField; 7.3.1 has no FeatureField, the repro does not compile [exec]); IntervalQuery: 8.0.0 [exec] (sandbox module; queries module from 8.2.0 [exec]; 7.7.3 scored the same IntervalQuery with BM25 and gave positive, distinct scores [exec])",
   "affected_versions": "FeatureField saturation and sigmoid: all 67 releases from 7.4.0 to 10.5.2; IntervalQuery: every release from 8.0.0 to 10.5.2 [exec], the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) [exec] and main a9779ef3c193 [exec]. Not fixed upstream: the last commit on FeatureField.java is 1518164afa3 (#15874, refactor, author and commit date 2026-04-01) and on IntervalScoreFunction.java 8ef6a0da568 (2020-12-28 reformat), checked on upstream main by author and committer date on 2026-10-28 [read]. All runs on aarch64 Linux with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-898.html",
   "repro": "repro/LFV-898/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-259",
   "priority": "low",
   "priority_rank": 694,
   "novelty": "new",
   "withheld": false,
   "area": "search / similarities (PerFieldSimilarityWrapper, Similarity#computeQueryTermWeight) and BooleanQuery duplicate-clause rewrite",
   "title": "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",
   "summary": "You configure BM25Similarity with its opt-in k3 parameter (new BM25Similarity(1.2f, 0.75f, true, 7f)), whose javadoc promises that a term repeated in a query is weighted ((k3 + 1) * qtf) / (k3 + qtf) instead of linearly, and you install it through a PerFieldSimilarityWrapper, the documented way to use per-field similarities, even one whose get() returns that same instance for every field. You expect the query 'apple apple' to score as it does with the bare BM25Similarity, where BooleanQuery's duplicate-clause rewrite gives (body:apple)^1.7777778. Instead the rewrite asks the wrapper, which does not forward Similarity#computeQueryTermWeight and inherits its linear default, so the query becomes (body:apple)^2.0 and the document scores 0.63013375 instead of 0.5601189; StableTflSimilarity's k3 is ignored the same way.",
   "impact_class": "silent wrong results",
   "introduced_commit": "05a788f0a4eb (#15818 'Add BM25 k3 query-term frequency saturation', author sgup432, merged by msfroh; related issue #15768) [read]; StableTflSimilarity's k3 override has the same gap from its first commit e3a7a733c8a (#16243) [read]",
   "introduced_date": "2026-03-30 (#15818 merged; StableTflSimilarity k3 since 2026-07-01, #16243)",
   "first_affected_version": "unreleased (11.0.0, main only; no release tag contains 05a788f0a4eb; CHANGES.txt lists #15818 under 11.0.0)",
   "affected_versions": "main from 05a788f0a4eb (2026-03-30) through ea57360912ed for BM25Similarity with k3 >= 0, and from e3a7a733c8a (2026-07-01) for StableTflSimilarity with k3 >= 0 [exec]; not affected: every release through 10.5.2, including 9.12.3, 10.4.0 and 10.5.0 (no k3 API: the repro does not compile, and a version-neutral probe shows wrapped and direct scoring agree) [exec]; branch_10_6 head 2763db11b0a7 (the branch of 10.6.0, released 2026-10-29) [exec] and branch_10x [read] have no computeQueryTermWeight, so 10.6.0 is not affected; not fixed upstream as of main ea57360912ed, the upstream main HEAD on 2026-10-26 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-259.html",
   "repro": "repro/LFV-259/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-103",
   "priority": "low",
   "priority_rank": 695,
   "novelty": "new",
   "withheld": false,
   "area": "search / BooleanQuery rewrite and similarities",
   "title": "BM25Similarity/StableTflSimilarity k3 query-term saturation is skipped for duplicate SHOULD clauses when 2 <= minimumNumberShouldMatch < number of SHOULD clauses",
   "summary": "You turn on BM25's opt-in k3 parameter (new BM25Similarity(1.2f, 0.75f, true, 8f), or StableTflSimilarity with k3), whose javadoc promises that a term repeated in a query is weighted ((k3 + 1) * qtf) / (k3 + qtf) instead of linearly, and you search with a BooleanQuery that repeats a SHOULD term, for example QueryBuilder.createMinShouldMatchQuery('body', 'a a b', fraction). You expect a document that matches every clause to get the same saturated score whatever minimumNumberShouldMatch is. Instead, when 2 <= minimumNumberShouldMatch < the number of SHOULD clauses, the repeated term is summed linearly: with k3=8 the document 'a b' scores 1.0150898 at msm=2 but 0.9568421 at msm=1 and at msm=3 (all clauses required).",
   "impact_class": "silent wrong results",
   "introduced_commit": "05a788f0a4eb (#15818 'Add BM25 k3 query-term frequency saturation', related issue #15768) [read]; StableTflSimilarity has the same behaviour from its first commit e3a7a733c8a (#16243) [exec]; not an older bug that k3 exposed: the guard (LUCENE-7925, ab793e7ab568 on main, 7.x backport 325263a9398, 2017-08-21) changed no score before k3, because merged and unmerged duplicates both sum linearly [exec]",
   "introduced_date": "2026-03-30 (#15818 merged; StableTflSimilarity k3 since 2026-07-01, #16243)",
   "first_affected_version": "unreleased (11.0.0, main only; no release tag contains 05a788f0a4e or e3a7a733c8a; CHANGES.txt lists #15818 under 11.0.0)",
   "affected_versions": "main from 05a788f0a4e (2026-03-30) through ea57360912ed for BM25Similarity with k3 >= 0, and from e3a7a733c8a (2026-07-01) for StableTflSimilarity with k3 >= 0 [exec]; not affected: every release, including 10.5.2 and 9.12.3 (no k3 API, the repro does not compile; a k3-free control scores msm=1, 2 and 3 identically) [exec]; branch_10x and branch_10_6 have no computeQueryTermWeight and no k3, so 10.6.0 (released 2026-10-29) is not affected [read]; not fixed upstream as of main ea57360912ed, the upstream main HEAD on 2026-10-26 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-103.html",
   "repro": "repro/LFV-103/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-608",
   "priority": "low",
   "priority_rank": 696,
   "novelty": "new",
   "withheld": false,
   "area": "core index / DOCS_AND_CUSTOM_FREQS (termdoc) field length vs term statistics; search similarities (BM25, SimilarityBase)",
   "title": "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",
   "summary": "You index two documents, 'a|5 b|5' and 'a|5 b|5 c|5 d|5', into a field with IndexOptions.DOCS_AND_CUSTOM_FREQS (DelimitedTermFrequencyTokenFilter, a TextField type with norms). Lucene stores their lengths as term counts, 2 and 4. FieldInfo#isTermDocField says such frequencies count as 1 'for statistical and scoring purposes', and FieldStats says sumTotalTermFreq 'is also the sum of each document's field length'. So you expect sumTotalTermFreq to be 6 and BM25's average length to be 3. Instead, sumTotalTermFreq and totalTermFreq sum the custom values (30), and BM25 explains dl=2.0 against avgdl=15.0. Each document's length is compared with an average inflated by the mean custom value, which quietly weakens length normalisation.",
   "impact_class": "minor",
   "introduced_commit": "5158a52a082b842c29918c8b955323d2a0848eb5. This is apache/lucene PR #15584, 'Compute 'length' of fields with custom term frequencies as docFreq', by msokolov, merged into main on 2026-04-24; it fixes #11086 (LUCENE-10048). It was backported to branch_10x as 3a55cc9ac5e96e39a75e837e326085c5efdc894d, and the 10.5.0, 10.5.1 and 10.5.2 tags contain that commit. The PR added three things together: IndexOptions.DOCS_AND_CUSTOM_FREQS with its javadoc, FieldInfo#isTermDocField with its javadoc, and the IndexingChain branch that adds 1 per term to the field length. Postings keep the custom value, so totalTermFreq and sumTotalTermFreq still sum it. Evidence [read]: blame and git log -S in the history clone, git tag --contains; the parent commit d8677f60a22 lacks the option. Evidence [exec]: on 10.4.0 the repro does not compile because the option is absent, and 10.5.0 fails. No commit-level bisection build was needed, because the option and the defect arrive in the same commit.",
   "introduced_date": "2026-04-24",
   "first_affected_version": "10.5.0 [exec]",
   "affected_versions": "Executed, failing 4 run / 2 failed with the same values: 10.5.0 (-ea and -da), 10.5.1 (-ea), 10.5.2 (-ea and -da) and main a9779ef3c193 (-ea and -da); the independent reproduction's independent JUnit also fails on 10.5.0 and 10.5.2. By reading, the heads of branch_10_5, branch_10_6 and branch_10x are affected too: they have the same IndexingChain branch and javadoc. Not affected: 10.4.0 and every earlier release, including all of 9.x, which lack the option; the repro does not compile on 9.12.3 or 10.4.0 [exec]. On those releases, custom frequencies on DOCS_AND_FREQS keep field length and sumTotalTermFreq in the same unit: the pre-option control passes on 9.12.3, 10.4.0, 10.5.0, 10.5.2 and main [exec]. The defect is not fixed upstream: main a95c754ee003 (2026-10-26) still has the code, and no open PR changes it.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-608.html",
   "repro": "repro/LFV-608/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-053",
   "priority": "low",
   "priority_rank": 697,
   "novelty": "new",
   "withheld": false,
   "area": "search / concurrency",
   "title": "Reusing a TotalHitCountCollectorManager after a failed search silently returns count 0 or hangs",
   "summary": "With intra-segment partitions, you reuse one TotalHitCountCollectorManager for a new search after an earlier search on the same reader failed. You expect the correct count. Instead its earlyTerminatedMap is only cleared in reduce(), so the count comes back as 0 (13 expected in the repro) or the search hangs.",
   "impact_class": "silent wrong results",
   "introduced_commit": "#13542 (fafd6af004e0) [read]",
   "introduced_date": "2024-09-10",
   "first_affected_version": "10.0.0 [read]",
   "affected_versions": "10.0.0+ [read]; 10.1.0, 10.5.2 and main [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-053.html",
   "repro": "repro/LFV-053/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-192",
   "priority": "low",
   "priority_rank": 698,
   "novelty": "new",
   "withheld": false,
   "area": "search / AutomatonQuery RAM accounting (NFARunAutomaton lazily built DFA states; LRUQueryCache RAM budget)",
   "title": "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",
   "summary": "You run a WildcardQuery or RegexpQuery whose automaton is not deterministic, for example '*a?????????' or 'a*b??????????', and expect its ramBytesUsed() to estimate the heap the query holds, which is what the Accountable javadoc says and what LRUQueryCache uses to stay within maxRamBytesUsed. On main such a query runs on an NFARunAutomaton that builds DFA states lazily during the search and keeps them on the query object, but AutomatonQuery stored ramBytesUsed() in a final field when it was constructed, so after one search the value is 36x to 310x too small (5,674 bytes reported vs 205,216 retained over 1,024 terms; 6,714 vs 2,081,152 on a 20,000-document field). An LRUQueryCache with a 1 MiB budget then keeps 4 such queries as keys that retain 2.7 to 7.4 MB while it accounts about 36 KB in total and evicts nothing; the matching documents are correct.",
   "impact_class": "silent wrong results",
   "introduced_commit": "c972c6a7754e9ff1f838ed72ff09e7def00be5f8, apache/lucene#225 'LUCENE-10010 Introduce NFARunAutomaton to run NFA directly' (zhaih, merged 2021-12-20): CompiledAutomaton began wrapping non-deterministic automata in an NFARunAutomaton that determinizes lazily and keeps its states for the life of the query, while AutomatonQuery kept the construction-time 'private final long ramBytesUsed; // cache' field added by LUCENE-8855 (a76c962ee61f, 2019-06-26, first released in 8.2.0; harmless while a CompiledAutomaton was always an immutable DFA) [read]. Default-path exposure on main only: 650684e6b440 (apache/lucene#15939, RegexpQuery(Term) no longer determinizes, merged 2026-04-12) and 86593e51b28d (apache/lucene#15961, WildcardQuery(Term) no longer determinizes and NFA-backed queries get value equality, so fresh per-request queries share one cache key, merged 2026-04-19) [exec]",
   "introduced_date": "2021-12-20 (root cause, #225); 2026-04-12 and 2026-04-19 (default WildcardQuery/RegexpQuery path, #15939 and #15961)",
   "first_affected_version": "10.0.0 [exec] through the opt-in NFA paths (an AutomatonQuery built from a non-deterministic automaton, e.g. new RegExp(s).toAutomaton(), which no longer determinizes since 10.0; RegexpQuery(..., doDeterminization=false) from #12767); the default WildcardQuery/RegexpQuery path is unreleased (main / 11.0.0); 9.12.3 is the last unaffected release [exec]",
   "affected_versions": "all 13 releases from 10.0.0 to 10.6.0 [exec]; main ea57360912ed [exec] and main 645d4fe14a20 [exec]. Not affected: 9.0.0 and 9.12.3 [exec]; 8.x and earlier [read]. Query-cache overrun: on 10.0.0 and 10.5.2 only when the application reuses the same NFA-backed query instance (NFA-backed queries compare by identity there) [exec]; with fresh per-request queries only on main [exec]. Not fixed upstream: upstream main HEAD was ea57360912ed (2026-10-24) when first checked on 2026-10-26, and on 2026-10-31 upstream main 2f424fd428da has the same AutomatonQuery.java, CompiledAutomaton.java, NFARunAutomaton.java, LRUQueryCache.java, WildcardQuery.java and RegexpQuery.java blobs as 645d4fe14a20 [read]; the last commit touching AutomatonQuery.java is #16390 (2026-07-14), and no open PR changes ramBytesUsed(); branch_10x and branch_10_6 were not checked. Executed on aarch64 Linux with JDK 25 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-192.html",
   "repro": "repro/LFV-192/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-400",
   "priority": "low",
   "priority_rank": 699,
   "novelty": "new",
   "withheld": false,
   "area": "spatial3d / PointInGeo3DShapeQuery RAM accounting (Accountable#ramBytesUsed; core LRUQueryCache RAM budget)",
   "title": "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)",
   "summary": "You filter with a Geo3DPoint polygon or path query, for example newLargePolygonQuery with 2,000 edges or newPathQuery with 200 points, and expect its ramBytesUsed() to estimate the heap it holds, which is what Accountable promises and what LRUQueryCache charges against its maxRamBytesUsed budget. Instead PointInGeo3DShapeQuery.ramBytesUsed() passes the shape and its bounds to RamUsageEstimator.sizeOfObject, which prices every object that is not Accountable (no GeoShape is) at a fixed 256 bytes, so every such query reports 592 bytes whatever its size: 4.9x too low for an 8-edge polygon, 47x for 99 edges, about 2,300x for the 2,000-edge large polygon (1,360,960 bytes retained). An LRUQueryCache with a 1 MiB budget therefore keeps 8 such filters that retain 10.9 MB, accounts about 6 KB for them and evicts nothing; the hits are correct.",
   "impact_class": "minor",
   "introduced_commit": "a76c962ee61f5185d30ff5bd94a23c16d21a5a98 (main; branch_8x backport 81208427d25f4541957eeeb03d971e1c45226428), LUCENE-8855 'Add Accountable to some Query implementations' (GitHub issue apache/lucene#9898; a JIRA patch by GitHub sigram, reviewed on the issue by jpountz and atris; no pull request): it made PointInGeo3DShapeQuery Accountable with ramBytesUsed() = BASE_RAM_BYTES + sizeOfObject(field) + sizeOfObject(shape) + sizeOfObject(shapeBounds) [read] [exec]. Not a regression of later work: no GeoShape class has ever implemented Accountable",
   "introduced_date": "2019-06-26",
   "first_affected_version": "8.2.0 [exec] (8.1.1 and earlier: PointInGeo3DShapeQuery is not Accountable and has no ramBytesUsed() [exec]). The cache-budget consequence through this method starts in 8.11.0 (LUCENE-10103, apache/lucene#346: LRUQueryCache charges Accountable queries their ramBytesUsed()); in 8.1.1-8.10.1 the cache charged a flat 1,024 bytes per query, which under-counted the same keys for a different reason [exec]",
   "affected_versions": "8.2.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2 and main ea57360912ed. [exec]: 8.2.0, 8.10.1, 8.11.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.5.2 and main (-ea and -da); ramBytesUsed() is 592 for every shape in every executed version. [read]: the other releases in those ranges (method body unchanged since 8.2.0); upstream main cf398bfb142 (2026-10-26) has the same method. Cache charge for 8 cached 2,000-edge keys [exec]: 9,168 bytes in 8.1.1-8.10.1 (flat 1,024 per key), 5,712 in 8.11.x, 5,904 in 9.0.0-10.5.2, 6,080 on main, against 10.9-11.0 MB retained. Not executed: 8.3.0-8.9.0, 9.2.0-9.11.1, 10.0.0-10.5.1, maintenance branches, x86",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-400.html",
   "repro": "repro/LFV-400/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-402",
   "priority": "low",
   "priority_rank": 700,
   "novelty": "new",
   "withheld": false,
   "area": "join / JoinUtil numeric query-time join RAM accounting (PointInSetIncludingScoreQuery, Accountable#ramBytesUsed; core LRUQueryCache RAM budget)",
   "title": "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)",
   "summary": "You build a numeric query-time join with JoinUtil.createJoinQuery(fromField, multipleValuesPerDocument, toField, numberType, fromQuery, fromSearcher, ScoreMode.Max) (or Min, Avg, Total) and expect its ramBytesUsed() to estimate the heap the query holds, which is what Accountable promises, what LRUQueryCache charges against maxRamBytesUsed, and what the string-field scoring join (TermsIncludingScoreQuery) and the ScoreMode.None numeric join (PointInSetQuery) do. Instead the PointInSetIncludingScoreQuery it returns adds up only its base object, field, from-query and packed join values, and leaves out aggregatedJoinScores, the FloatArrayList with one float per join value that its constructor fills: with 100,000 join values it reports 304,248 bytes while it retains 710,632 (2.3x; 1.5x-2.4x depending on how compactly the keys prefix-code), against 303,272 vs 304,544 for ScoreMode.None. A query cache holding such a join as a filter charges it the same low number (304,408 bytes charged, 710,632 retained), so the cache can hold up to about 2.5 times its budget in these keys; the matching documents are correct.",
   "impact_class": "minor",
   "introduced_commit": "a76c962ee61f5185d30ff5bd94a23c16d21a5a98 (main, then master, first released in 9.0.0; branch_8x backport 81208427d25f4541957eeeb03d971e1c45226428, first released in 8.2.0), LUCENE-8855 'Add Accountable to some Query implementations' (a JIRA patch by GitHub sigram, reviewed by jpountz; no pull request; migrated issue apache/lucene#9898): it made PointInSetIncludingScoreQuery Accountable with ramBytesUsed = BASE_RAM_BYTES + field + originalQuery + sortedPackedPoints and never added the score list that the same constructor fills, while the same commit counted TermsIncludingScoreQuery's scores array [read] [exec]. A branch_8_1 copy (5dfdc3029b2) was reverted the next day (edea7ebfbfb), so no 8.1.x release has it. Present since the method was written; not a regression of later work",
   "introduced_date": "2019-06-26",
   "first_affected_version": "8.2.0 [exec] (8.1.1 and earlier: the query is not Accountable and has no ramBytesUsed() [exec]). The query-cache consequence starts in 8.11.0 and 9.0.0 (LUCENE-10103, apache/lucene#346, 6a41bc6310e: LRUQueryCache charges Accountable queries their ramBytesUsed()); in 8.2.0-8.10.x the cache charged a flat amount per query whatever the query [exec], so there the wrong value reached only direct callers of ramBytesUsed()",
   "affected_versions": "8.2.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.6.0 (10.6.0 by reading) and main ea57360912ed. [exec]: 8.2.0, 8.8.1, 8.8.2, 8.9.0, 8.10.0, 8.10.1, 8.11.0-8.11.4, 9.0.0, 9.10.0, 9.11.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the finder's JUnit also fails on 10.5.2 and 9.12.3. [read]: 8.3.0-8.7.0, 8.8.0, 9.1.0-9.9.2, 9.11.1, 9.12.0-9.12.2, 10.1.0-10.5.1 (each tag implements Accountable and leaves the list out). Size [exec]: 6.20x in 8.2.0-9.10.0 (List<Float> of boxed Floats; a lower bound) and 2.43x from 9.11.0 (FloatArrayList since apache/lucene#13406); on main random Integer keys give 1.89x and random Long keys 1.49x. Not fixed upstream: upstream main cf398bfb142 (2026-10-26) still sums only field, originalQuery and sortedPackedPoints, the last commit touching the file is ce50d3a135d (2025-02-24), and branch_10x and branch_10_6 were unfixed at the prior-art check (2026-10-26). Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-402.html",
   "repro": "repro/LFV-402/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-923",
   "priority": "low",
   "priority_rank": 701,
   "novelty": "new",
   "withheld": false,
   "area": "queries / function queries (FunctionScoreQuery, FunctionMatchQuery, FunctionRangeQuery and FunctionQuery QueryVisitor traversal of DoubleValuesSource/ValueSource; consumer: IndexSearcher's cumulative clause limit)",
   "title": "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",
   "summary": "You search FunctionScoreQuery.boostByQuery(in, boostMatch, 2f), where in and boostMatch are each a 600-term disjunction (1,200 term clauses that all run), with the default maxClauseCount of 1024. You expect TooManyNestedClauses, which you do get for a BooleanQuery holding the same clauses (even when half of them are scoring-only SHOULD or MUST_NOT clauses), because the check counts 'total clauses cumulatively in all of its children' and LUCENE-8811 made it cumulative so that splitting clauses over sub-queries no longer bypasses it. Instead the search runs with correct hits: FunctionScoreQuery.visit visits only `in`, FunctionMatchQuery, FunctionRangeQuery and FunctionQuery.visit call visitLeaf(this), DoubleValuesSource and ValueSource have no visit hook, and the embedded query is rewritten later with searcher.rewrite, which checks it alone with a fresh count; FunctionScoreQuery(fromQuery), FunctionMatchQuery(fromQuery) and FunctionQuery/FunctionRangeQuery over QueryValueSource behave the same.",
   "impact_class": "minor",
   "introduced_commit": "53f56fb7ad44afab9c78fab2e89737438093247f (LUCENE-8811 'Move max clause checks to IndexSearcher', now apache/lucene#9855, a JIRA patch committed by GitHub romseygeek, no GitHub PR), first released in 9.0.0: it added the cumulative check query.visit(getNumClausesCheckVisitor()) to IndexSearcher.rewrite (IndexSearcher.java:878 on main), which never reaches a query held by a values source; its branch_8x backport fa3bf88783a was reverted by 2885a115782 (branch_8x) and 193c77fe1a0 (branch_8_2) on 2019-07-15, before 8.2.0. The fix site is older and was harmless before: fbd05167f455e3ce2b2ead50336e2b9c2521cd6c (LUCENE-3041 'QueryVisitor', apache/lucene-solr#581, by GitHub romseygeek; branch_8x ecf86ecab7a, released in 8.1.0) wrote the four visit() bodies as ports of Weight#extractTerms, which already skipped the values source [read]; not a regression of a check that once worked, so no bisect",
   "introduced_date": "2019-06-26 (author date of 53f56fb7ad4, LUCENE-8811, the cumulative check that made the hidden query matter); 2019-03-14 (author date of fbd05167f45, LUCENE-3041, the visit() bodies)",
   "first_affected_version": "9.0.0 [exec] (the first release with the cumulative check: the history probe's nested BooleanQuery controls are rejected while 5 of 5 function-query cases are accepted, and the finder's JUnit (9.0.0 import variant) fails 5 of 5, -da); the visit() bodies exist since 8.1.0 but are latent in 8.x, which has no cumulative check [exec]; the JUnit's API (TooManyNestedClauses, IndexSearcher.getMaxClauseCount) is absent in 8.11.4 [exec]",
   "affected_versions": "All 33 releases 9.0.0 to 10.5.2 on Maven Central, plus 10.6.0 (the branch_10_6 head 4ae946e5a9b, the RC1 revision) and main a9779ef3c193 [exec]; latent, not affected, in 8.1.0 to 8.11.4 (no cumulative check) [exec]; upstream main c5ab3e57b9b (author date 2026-10-28) still has the same visit() bodies: the last upstream commits on the fix-site files are #16697 (DoubleValuesSource.java, author date 2026-10-09), #16431 (FunctionScoreQuery.java, 2026-08-22), #15406 (ValueSource.java, 2025-12-02), #13440 (FunctionMatchQuery.java, FunctionRangeQuery.java, FunctionQuery.java, 2024-06-06) and LUCENE-9570 (QueryValueSource.java, 2020-12-28), none touching visit() [read]; not fixed anywhere. All runs on aarch64 Linux with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-923.html",
   "repro": "repro/LFV-923/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-910",
   "priority": "low",
   "priority_rank": 702,
   "novelty": "new",
   "withheld": false,
   "area": "grouping / GroupingSearch two-pass caching x search / CachingCollectorManager (new in 10.6.0) under a concurrent IndexSearcher",
   "title": "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)",
   "summary": "You enable caching for a grouped search with GroupingSearch.setCaching(600, true) (or setCachingInMB) and search through an IndexSearcher that has an executor, and expect what the unchanged javadoc says and what 10.5.2 and a sequential searcher do: the cache holds at most the limit, and when the query matches more it is purged and the second pass re-runs the query. Instead, since #16247 GroupingSearch hands the limit to the new CachingCollectorManager, which applies it to each slice separately, so with 1000 matching documents over 2 slices each slice cache stays under 600, the caches hold all 1000 documents, and the second pass is replayed (the query runs once instead of twice). Results are the same; what breaks is the documented memory bound and the replay decision, and the cache can reach (number of slices) x limit.",
   "impact_class": "minor",
   "introduced_commit": "3afffeef5a8d3bcbdcff9f2376e1c5a357764197 (main; apache/lucene#16247 'Introduce CachingCollectorManager to parallelize search when using CachingCollector', author gaobinlong, approved by javanna, merged 2026-07-08T09:27:54Z) and d60e550b47f (branch_10x, same author date and patch-id 1ae55a44eb1c; branch_10_6 forks from branch_10x at 3e416dce059, 2026-10-15, and contains it) [exec]. The GroupingSearch caching contract it breaks dates from 89b55566d83 (LUCENE-3778, 2012, first released in 4.0.0) and is unchanged except for reformatting (LUCENE-9570).",
   "introduced_date": "2026-07-08 (author date of 3afffeef5a8 on main and of d60e550b47f on branch_10x)",
   "first_affected_version": "10.6.0 (released 2026-10-29: the branch_10_6 head 4ae946e5a9b, RC1, fails [exec]; main from 3afffeef5a8 [exec]); no earlier release is affected (9.12.3, 10.0.0, 10.4.0, 10.5.0, 10.5.1 and 10.5.2 pass [exec]; 4.0.0-10.5.2 [read])",
   "affected_versions": "[exec] main a9779ef3c193 (-ea and -da; re-run at the registration check 2026-10-28: 2 run, 2 failed, seed DEADBEEF), the introducing commit 3afffeef5a8 (-ea, -da) and the branch_10_6 head 4ae946e5a9b = 10.6.0 RC1 (-ea, -da; re-run at the registration check: 2 of 2 fail) are affected; not affected [exec]: 10.5.2 (-ea, -da; re-run at the registration check: 2 of 2 pass), 10.5.1, 10.5.0, 10.4.0, 10.0.0, 9.12.3 and the parent commit 6f3c1d7ad69. [read] every release from 4.0.0 to 10.5.2 ran GroupingSearch's first pass through one CachingCollector in the sequential search(Query, Collector) loop, which ignores the executor, so the limit covered the whole search (10.5.1 and 10.5.2 were cut from branch_10_5 and contain neither commit). All runs used JDK 25 on aarch64 Linux. Not fixed upstream: no commit on main (head c5ab3e57b9ba) or branch_10_6 (head 4ae946e5a9b9) touches GroupingSearch.java, CachingCollectorManager.java, CachingCollector.java or IndexSearcher.java since 2026-10-20, and no open PR touches the limit [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-910.html",
   "repro": "repro/LFV-910/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b): 2 of 2 fail with -ea and -da; 10.5.2 passes 2 of 2."
  },
  {
   "id": "LFV-348",
   "priority": "low",
   "priority_rank": 703,
   "novelty": "known",
   "withheld": false,
   "area": "misc / memory-accounting bitset collector (MemoryAccountingBitsetCollector, MemoryAccountingBitsetCollectorManager, CollectorMemoryTracker) under IndexSearcher slicing",
   "title": "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",
   "summary": "You search with MemoryAccountingBitsetCollectorManager and a CollectorMemoryTracker on an IndexSearcher built with an executor, and expect each slice's collector to allocate a bitset only for the segments it searches, as the manager's javadoc says ('each collector only allocates a bitset for the slices it processes'). Instead each collector sizes its bitset to the doc-id range from the first to the last segment of its slice, and the default slicing groups segments by size, not by doc-id order, so in an index whose segments are 10, 300,000, 10, 300,000 and 10 documents the slice of the three small segments allocates a bitset over 600,030 doc ids for its 30 documents. The search tracks 243,960 bytes against 159,480 for the same search without an executor, and a tracker limit of 161,528 bytes that the sequential search fits throws IllegalStateException 'Memory limit exceeded' with the executor; the matched documents are correct.",
   "impact_class": "minor",
   "introduced_commit": "cd413bbfbb9f38c5a3c685f884091597bd68d770 ('Introduce MemoryAccountingBitsetCollectorManager (#15795)' by GitHub gaobinlong, squash merge to main; 10.x backport 47f3b1d8f42eb913115a52c2dada7d7c1a197a0c, contained in releases/lucene/10.5.0, 10.5.1 and 10.5.2) [read]. In the PR the span sizing first appeared in commit c6c93c7d04c ('Make the collector manager memory efficient') as an opt-in segment-local mode and became the only path in 8ac9a111446 ('Remove segmentLocal')",
   "introduced_date": "2026-06-04 (merge of #15795 to main and of the 10.x backport)",
   "first_affected_version": "10.5.0 [exec] (first release with MemoryAccountingBitsetCollectorManager; 10.4.0 and 9.12.3 have no manager, so the repro does not compile there [exec], and a probe with the bare collector and a user-written manager shows no span allocation on them [exec])",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2, 10.6.0 (by reading) and main ea57360912ed. [exec] the finder's JUnit fails 2 of 2 with identical numbers on 10.5.0, 10.5.1, 10.5.2 (-ea and -da) and main (-ea and -da), and on main jars with commit cd413bbfbb9's two classes shadowed; the independent reproduction's own JUnit fails 2 of 4 (both controls pass) on main (-ea and -da), 10.5.2 and 10.5.0; the intended-behaviour check re-ran the finder's JUnit on main (-ea and -da) and 10.5.2; the head 54531990803a of open PR #16663 still fails 2 of 2. [read] upstream main HEAD, branch_10_6 and branch_10x still contain 'length = maxDocEnd - minDocBase' (read 2026-10-26, not executed), so the released 10.6.0 (2026-10-29) has it; #16452 (10.6.0) changed only the Result bitset sizing. Not affected: 10.4.0, 9.12.3 and every earlier release (no manager; the bare collector there sized its bitset by the sum of visited maxDoc). Not checked: x86",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15795",
    "https://github.com/apache/lucene/issues/16452",
    "https://github.com/apache/lucene/issues/16663",
    "https://github.com/apache/lucene/issues/16649",
    "https://github.com/apache/lucene/issues/15655",
    "https://github.com/apache/lucene/issues/15656"
   ],
   "doc": "",
   "repro": "repro/LFV-348/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-917",
   "priority": "low",
   "priority_rank": 704,
   "novelty": "new",
   "withheld": false,
   "area": "facet / range queries (LongRange/DoubleRange ValueSourceQuery and MultiValueSourceQuery QueryVisitor traversal; consumers: IndexSearcher's cumulative clause limit, QueryVisitor.termCollector, RamUsageEstimator.sizeOf(Query))",
   "title": "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",
   "summary": "You build LongRange#getQuery(fastMatch, LongValuesSource) (or the DoubleRange or multi-valued overloads) with a fast-match query of 1,200 term clauses (two required 600-term disjunctions) and search it with the default maxClauseCount of 1024. You expect TooManyNestedClauses, which you do get when the same fast-match query is a sibling FILTER clause, because the check counts 'total clauses cumulatively in all of its children', Query#visit is documented to visit 'any child queries', and getQuery documents fastMatchQuery as 'a query to use as a filter'. Instead the search runs and returns the correct hits: ValueSourceQuery.visit and MultiValueSourceQuery.visit only call visitor.visitLeaf(this), so the fast-match query, which stays in the rewritten query and is executed as the approximation in createWeight, is seen by no clause check at all, and QueryVisitor.termCollector returns none of its terms.",
   "impact_class": "minor",
   "introduced_commit": "fbd05167f455e3ce2b2ead50336e2b9c2521cd6c (LUCENE-3041 'QueryVisitor', apache/lucene-solr#581, by GitHub romseygeek; branch_8x backport ecf86ecab7a34dc5fd77429b92a8a8b5d78f4844, released in 8.1.0) wrote ValueSourceQuery.visit as visitor.visitLeaf(this) in LongRange.java and DoubleRange.java, while the same commit kept rewrite() rewriting the fast-match query in place and createWeight() executing it; the symptom appeared with 53f56fb7ad44afab9c78fab2e89737438093247f (LUCENE-8811, #9855: the max clause check moved to IndexSearcher and was implemented with a QueryVisitor), first released in 9.0.0 (its branch_8x commit fa3bf88783ac was reverted by 2885a115782b and 193c77fe1a0a on 2019-07-15, before 8.2.0); the multi-valued MultiValueSourceQuery copied the same visit() in 82703757fe05a1d3b9efe28d766d4bc3df8a060f (LUCENE-10245, apache/lucene#543, by GitHub gsmiller; branch_9x 60b499b907d3), released in 9.1.0 [read]; not a regression of a check that once worked, so no bisect",
   "introduced_date": "2019-03-14 (author date of fbd05167f455, the leaf-only visit; branch_8x backport committed 2019-03-15); 2019-06-26 (author date of 53f56fb7ad44, LUCENE-8811, which made visit() the basis of the clause limit); 2022-01-10 (author date of 82703757fe05, the multi-valued copy)",
   "first_affected_version": "9.0.0 [exec] (the first release with the visitor-based cumulative check: the probe's control is rejected while LongRange/DoubleRange#getQuery with the same fast-match query is accepted, -ea and -da); the multi-valued overloads from 9.1.0 [exec] (9.0.0 has no Multi*ValuesSource: compile error [exec]); the defective visit() exists since 8.1.0 but is latent in all 26 releases 8.1.0 to 8.11.4 [exec] (no cumulative clause check there); 8.0.0 has no QueryVisitor [exec]",
   "affected_versions": "All 33 releases 9.0.0 to 10.5.2 (single-valued from 9.0.0, multi-valued from 9.1.0), plus 10.6.0 (the branch_10_6 head 4ae946e5a9b, the RC1 revision) and main a9779ef3c193 [exec]; upstream main c5ab3e57b9b (author date 2026-10-28), branch_11x, branch_10x and branch_10_6 still have the leaf-only visit (last commit on either file b59848c7049, #15842, author date 2026-04-02, does not touch visit) [read]; not fixed anywhere. All runs on aarch64 Linux with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-917.html",
   "repro": "repro/LFV-917/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-916",
   "priority": "low",
   "priority_rank": 705,
   "novelty": "new",
   "withheld": false,
   "area": "search / vector similarity queries (AbstractVectorSimilarityQuery QueryVisitor traversal; consumers: IndexSearcher's cumulative clause limit, QueryVisitor.termCollector, RamUsageEstimator.sizeOf(Query))",
   "title": "Float/Byte/Float16VectorSimilarityQuery.visit() never visits the filter, so the filter's clauses escape IndexSearcher's cumulative maxClauseCount check and QueryVisitor term collection",
   "summary": "You build BooleanQuery(MUST a 600-term disjunction, MUST FloatVectorSimilarityQuery.Adaptive(field, target, 0f, filter = another 600-term disjunction)), 1,200 term clauses in all, and search it with the default maxClauseCount of 1024. You expect TooManyNestedClauses, which you do get when the same 600 clauses are a sibling FILTER clause, because the check counts 'total clauses cumulatively in all of its children' and Query#visit is documented to visit 'any child queries'. Instead the search runs: AbstractVectorSimilarityQuery.visit only calls visitor.visitLeaf(this), so the filter, which stays in the rewritten query and is executed in createWeight, is checked only on its own; ByteVectorSimilarityQuery and Float16VectorSimilarityQuery behave the same, and QueryVisitor.termCollector returns none of the filter's terms.",
   "impact_class": "minor",
   "introduced_commit": "cd195980ecbcb45e19ce9465854fed0b6be79ea7 (apache/lucene#12679 'Add support for similarity-based vector searches', by GitHub kaivalnp, merged by benwtrent), released in 9.x through the branch_9x backport 8089b8c9d3374dc4d451a4280daae85e0b139b84 (plus 0212776677674db06439279849dafbafd7cc7dbc, a Java 11 adjustment of createWeight that leaves visit untouched); it created AbstractVectorSimilarityQuery with the leaf-only visit() copied from AbstractKnnVectorQuery and the createWeight line that rewrites and checks the filter on its own [read]; not a regression, so no bisect",
   "introduced_date": "2023-12-12 (author date, +0530; merged 2023-12-11T19:18:36Z; branch_9x backport committed 2023-12-11)",
   "first_affected_version": "9.10.0 [exec] (the first release with the vector similarity queries; 9.9.2 has none and the repro does not compile there [exec]); on the main line 10.0.0 [exec]; Float16VectorSimilarityQuery (#16735) is main only and unreleased",
   "affected_versions": "Every release that has the API: the 19 up to 10.5.2 (9.10.0, 9.11.0, 9.11.1, 9.12.0 to 9.12.3 and 10.0.0 to 10.5.2) and 10.6.0 (the branch_10_6 head 4ae946e5a9b, the RC1 revision), plus main a9779ef3c193 [exec]; the IndexSearcher visitor-based cumulative check (LUCENE-8811) already existed when the class was added; upstream main c5ab3e57b9ba, branch_10x and branch_10_6 still have the leaf-only visit (last commit on the file 6f30895add8, #16104, author date 2026-05-28, does not touch visit) [read]; not fixed anywhere. All runs on aarch64 Linux with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-916.html",
   "repro": "repro/LFV-916/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-951",
   "priority": "low",
   "priority_rank": 706,
   "novelty": "new",
   "withheld": false,
   "area": "spatial-extras / composite: CompositeVerifyQuery (Query#visit; consumers: QueryVisitor.termCollector and other visit-based term extraction, IndexSearcher's cumulative clause limit)",
   "title": "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",
   "summary": "You wrap your own index query, for example TermQuery(body:a) or a 20-clause DisjunctionMaxQuery, in new CompositeVerifyQuery(indexQuery, shapePredicate), then collect its terms with QueryVisitor.termCollector or search it after IndexSearcher.setMaxClauseCount(8). You expect [body:a] and an IndexSearcher.TooManyNestedClauses error, because Query#visit is documented to 'recurse through the query tree, visiting any child queries', the wrapper rewrites its index query and runs it as the approximation that every hit must match, and the same 20 clauses as a bare query or as a sibling FILTER clause are rejected. Instead CompositeVerifyQuery.visit only calls visitor.visitLeaf(this): termCollector returns [] and the clause check counts the whole query as one clause, so the over-limit query runs (its hits are correct).",
   "impact_class": "minor",
   "introduced_commit": "fbd05167f455e3ce2b2ead50336e2b9c2521cd6c (LUCENE-3041 'QueryVisitor', apache/lucene-solr#581, issue apache/lucene#4114, by GitHub romseygeek; branch_8x backport ecf86ecab7a34dc5fd77429b92a8a8b5d78f4844, released in 8.1.0) added Query#visit and wrote CompositeVerifyQuery.visit as visitor.visitLeaf(this), unchanged since (git blame on main a9779ef3c193 attributes CompositeVerifyQuery.java:87-90 to fbd05167f45) [read]; the clause-limit consequence appeared with 53f56fb7ad44afab9c78fab2e89737438093247f (LUCENE-8811, #9855: the cumulative clause check moved to IndexSearcher and was built on QueryVisitor), first released in 9.0.0 (its 8.x commit fa3bf88783a was reverted by 193c77fe1a0 before 8.2.0). Precursor: the class was written with term extraction delegated to its index query (489f56def84, LUCENE-5579, #6641, 2015-04-10, by GitHub dsmiley), and the LUCENE-6425 sweep (f4c05465673, #7484, 2015-04-16, by GitHub jpountz) deleted that delegation before any release, so the predecessor Weight#extractTerms already had the gap from 5.2.0 [exec]. Commit-level isolation [exec]: compiling only a recursive visit into the 8.1.0 and 9.0.0 jars makes the visitor probe pass on both and the clause probe pass on 9.0.0. The defect arrived with the API, so there is no earlier working state to bisect.",
   "introduced_date": "2019-03-14 (author date of fbd05167f455 and of its branch_8x backport ecf86ecab7a, committed 2019-03-15); 2019-06-26 (author date of 53f56fb7ad44, LUCENE-8811, which made visit() the basis of the cumulative clause limit); precursor 2015-04-16 (author date of f4c05465673, LUCENE-6425)",
   "first_affected_version": "8.1.0 [exec] for the term-collection half (the first release with Query#visit; 8.0.0 has no QueryVisitor: compile error [exec]); 9.0.0 [exec] for the clause-limit half (the first release with the visitor-based cumulative check; 8.1.0 and 8.11.4 have no cumulative limit, so the clause probe does not apply there [exec]); the predecessor Weight#extractTerms API had the same gap from the class's first release, 5.2.0 [exec]",
   "affected_versions": "Term-collection half: every release from 8.1.0 to 10.6.0 (10.6.0 run as its release revision, the branch_10_6 head 4ae946e5a9b) and main a9779ef3c193; clause-limit half: every release from 9.0.0 on, branch_10_6 and main [exec]. The branch_10_6 runs combined the branch head's core and test-framework jars with the 10.5.2 spatial-extras jar and the branch's own CompositeVerifyQuery.java compiled in (byte-identical to main; the other spatial-extras differences are in BBoxStrategy and PointVectorStrategy); not a 10.6.0 regression. Not fixed upstream: CompositeVerifyQuery.java was last changed by d0d2aa274fb (#13440, author date 2024-06-06), so upstream main head 645d4fe14a2 (author date 2026-10-28) and branch_10_6 still have the leaf-only visit [read]. All runs on aarch64 Linux with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-951.html",
   "repro": "repro/LFV-951/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1107",
   "priority": "low",
   "priority_rank": 707,
   "novelty": "known",
   "withheld": false,
   "area": "search / IndexSearcher clause-count limit (getNumClausesCheckVisitor)",
   "title": "IndexSearcher's nested clause check accepts maxClauseCount + 1 clauses because it compares before incrementing (known: #10339 / LUCENE-9299) (released since 9.0)",
   "summary": "You rewrite a query with two MUST disjunctions of 512 and 513 term clauses (1,025 leaves) under the default maxClauseCount of 1,024 and expect TooManyNestedClauses, because the limit is 'the maximum number of clauses permitted'. Instead the query is accepted: the visitor checks 'numClauses > maxClauseCount' before incrementing, so the first rejected total is maxClauseCount + 2.",
   "impact_class": "minor",
   "introduced_commit": "LUCENE-8811 (53f56fb7ad4) [read]",
   "introduced_date": "2019-06-26 (LUCENE-8811 author date) [read]",
   "first_affected_version": "9.0.0 [read]; oldest executed 9.12.3",
   "affected_versions": "9.12.3, 10.5.2 and 10.6.0 (released) [exec]; main 645d4fe14a20 and e1faeba08bde with -ea and -da [exec]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/10339",
    "https://issues.apache.org/jira/browse/LUCENE-9299",
    "https://github.com/apache/lucene/issues/16847",
    "https://github.com/apache/lucene/issues/16805"
   ],
   "doc": "",
   "repro": "repro/LFV-1107/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-432",
   "priority": "low",
   "priority_rank": 708,
   "novelty": "new",
   "withheld": false,
   "area": "facet / sampling (RandomSamplingFacetsCollector.createSample, cross-segment bin carry-over)",
   "title": "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)",
   "summary": "You count facets with RandomSamplingFacetsCollector on a multi-segment index for a query with many more hits than sampleSize, and expect systematic sampling: one random hit out of every run of binSize consecutive hits, with a run that is cut by a segment boundary continued in the next segment, so every hit has about a 1/binSize chance to be sampled. Instead, when the hit picked for such a run is the first hit of the next segment, createSample leaves its carry-over state unset (it tests only randomIndex > counter and randomIndex < counter), so that run contributes no sample, or one at a stale offset, and the first hit of a segment that starts mid-bin is never sampled. Nothing fails; the sample and the amortized counts are just smaller than the reported sampling rate implies (4 hits in segments [1 | 3], sampleSize 2: half the seeds sample 1 hit instead of 2).",
   "impact_class": "minor",
   "introduced_commit": "e50b392f467cf1e3dea3999b5449c48742cf2084, 'LUCENE-5476: add RandomSamplingFacetsCollector' (trunk, svn r1579594; no PR, a JIRA patch; issue mirrored as apache/lucene#6539; committer shaie), shipped in 4.x through the same-day branch_4x backport 4d26f04cedcdc487b8c8541bc23ff24df6b71f6a (svn r1579598) [read]. Not a regression: the defect is in the first committed version of the carry-over",
   "introduced_date": "2014-03-20",
   "first_affected_version": "4.8.0 [exec]; 4.7.2 does not have RandomSamplingFacetsCollector [exec]",
   "affected_versions": "4.8.0 through 10.5.2 (the last release before 10.6.0) and main ea57360912ed; not fixed upstream (upstream main and branch_10x still read 'randomIndex > counter' at line 199; the last commit to the file is fafd6af004e, 2024-09-10, already in the tested tree; read 2026-10-26). [exec] The history driver (4 documents, segments [1 | 3], sampleSize 2, sampler seeds 1..20, one small API adapter per era) fails with identical counts (10 of 40 complete bins empty, 0 doubly sampled, 30 of 40 intended sampled hits) on 4.8.0, 4.9.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-da also on 4.8.0, 9.12.3 and main), with both IndexSearcher.search(Query, Collector) (4.x-9.x) and createManager (10.x); the finder's JUnit fails on main (-ea, -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 4 of 5 on main (-ea, -da), 10.5.2 and 9.12.3. [read] The unchanged '>' / '<' block is in all 107 release tags from 4.8.0 to 10.5.2 in the history clone (8.9.0-8.11.x are not tagged there; 8.11.4 was executed). Not affected: 4.7.2 and older (no such class). Old releases ran on JDK 25 with their published jars",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-432.html",
   "repro": "repro/LFV-432/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-089",
   "priority": "low",
   "priority_rank": 709,
   "novelty": "new",
   "withheld": false,
   "area": "index / CheckIndex vectors",
   "title": "CheckIndex silently skips FLOAT16 vector fields: it reports 'OK [0 fields, 0 vectors]' and never runs checkFloat16VectorValues",
   "summary": "You index vectors with KnnFloat16VectorField (default codec) and run CheckIndex at level 2 or higher. You expect it to count and check the FLOAT16 fields the way it does FLOAT32 and BYTE fields; the same 2-field, 3-vector index built with KnnFloatVectorField reports 2 fields / 3 vectors. Instead it prints 'test: vectors.............OK [0 fields, 0 vectors]', because the skip guard in CheckIndex.testVectors tests only the FLOAT32 and BYTE getters, so every FLOAT16 field is skipped and the dedicated checkFloat16VectorValues (iteration, dimension, size and kNN self-search checks) never runs.",
   "impact_class": "minor",
   "introduced_commit": "bfe5c847d3c (#16383 'Add fp16 (float16) vector encoding') [read]; the guard itself is older (c02f07f2d5d LUCENE-9322, widened for BYTE in cc29102a24a #12064, renamed in 92e67ec626b #12105); not a regression: the FLOAT16 arm and checker were unreachable from the commit that added them",
   "introduced_date": "2026-07-27",
   "first_affected_version": "unreleased (main only, 11.0.0-SNAPSHOT; no release tag contains bfe5c847d3c)",
   "affected_versions": "main from bfe5c847d3c (2026-07-27) through 645d4fe14a2 [exec]; 10.5.2, 9.12.3 and the parent 606a26dafd5 not affected (no FLOAT16 API, the repro does not compile) [exec]; branch_10x 657014b3c579 (after #16905) and branch_10_6 4ae946e5a9b (10.6.0 RC1) have no FLOAT16 encoding [read]; not fixed upstream as of main 645d4fe14a2 [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-089.html",
   "repro": "repro/LFV-089/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-543",
   "priority": "low",
   "priority_rank": 710,
   "novelty": "known",
   "withheld": false,
   "area": "index / CheckIndex HNSW graph check",
   "title": "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",
   "summary": "You open, on Lucene main, an index that Lucene 9.12.0, 9.12.1, 10.0.0 or 10.1.0 wrote with the default codec, and run CheckIndex at level 2 or 3. You expect it to pass: main opens, reads, searches and merges the index correctly, and upstream calls repeated HNSW neighbours benign. Instead, when an old unmerged segment's graph lists the same neighbour twice (those releases' connectComponents step could add an existing link again, and their writers did not de-duplicate), CheckIndex reports 'has repeated neighbors': with failFast it throws CheckIndexException ('Segment ... check failed'), otherwise it prints 'test: hnsw graphs.........ERROR', because the rule applies to every segment whatever version wrote it.",
   "impact_class": "wrong error",
   "introduced_commit": "11eb2c86979e79b34cf5420ba2d9e3c4e322d938 (#13984 'Add some basic HNSW graph checks to CheckIndex', by benchaplin, merged by msokolov; only CheckIndex.java changed) [read]. The triggering data comes from #13566 (connectComponents, main 217828736c4 / branch_9x 98fbbe2d673, 2024-08-08, first released in 9.12.0 and 10.0.0) in writers without the de-duplication that #14157 added for 10.2.0. Decision point: #14157 (2025-01-22) skipped the version gate msokolov proposed in #14127",
   "introduced_date": "2025-01-08",
   "first_affected_version": "unreleased (main only, 11.0.0-SNAPSHOT; git tag --contains 11eb2c86979 is empty; would first ship in 11.0.0 unless fixed)",
   "affected_versions": "main from 11eb2c86979 (2025-01-08) through ea57360912ed [exec] and a9779ef3c193 [exec]; upstream main ffa9d816eeb4 has identical testHnswGraph/testHnswGraphs [read]; no release has the check: 9.12.0, 9.12.3, 10.0.0, 10.1.0, 10.2.0 and 10.5.2 pass [exec], every tag 9.12.0-10.5.2 and the branch_10x and branch_10_6 heads have no testHnswGraph [read], although main's CHANGES lists GITHUB#13984 under 10.2.0. Writers that produce the triggering segments: 9.12.0, 9.12.1, 10.0.0, 10.1.0 [exec]; 9.11.1, 9.12.2, 9.12.3, 10.2.2 produce none [exec]. 10.0.0/10.1.0 segments are readable on main throughout; 9.12.x segments only since #16741 (8476457b875, 2026-10-15) [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/14127",
    "https://github.com/apache/lucene/issues/14157",
    "https://github.com/apache/lucene/issues/13984",
    "https://github.com/apache/lucene/issues/14120",
    "https://github.com/apache/lucene/issues/13724",
    "https://github.com/apache/lucene/issues/15467"
   ],
   "doc": "",
   "repro": "repro/LFV-543/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-561",
   "priority": "low",
   "priority_rank": 711,
   "novelty": "new",
   "withheld": false,
   "area": "index / CheckIndex HNSW graph check",
   "title": "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",
   "summary": "You run CheckIndex at level 2 or 3 (the command line with -level 2, or setLevel) without failFast on an index whose HNSW graph is broken, for example a neighbour that is not on its level or a neighbour list out of order. You expect the segment to count as bad, as it does for every other sub-test: Status.clean false, exit code 1, and -exorcise able to act; with failFast on, the same index does throw CheckIndexException. Instead the HNSW sub-test prints 'test: hnsw graphs.........ERROR: ...' and only stores the exception, because testSegment's rethrow chain has no clause for hnswGraphsStatus.error, so the run ends with 'No problems were detected with this index.', Status.clean true, numBadSegments 0 and exit code 0.",
   "impact_class": "wrong error",
   "introduced_commit": "11eb2c86979e79b34cf5420ba2d9e3c4e322d938 (#13984 'Add some basic HNSW graph checks to CheckIndex', by benchaplin, squash-merged by msokolov; only CheckIndex.java changed, +229) [read]. Born with the feature: the commit added the sub-test, its status field and the call in testSegment, but no clause in the rethrow chain that LUCENE-9662 (424192e1704, #128, 2021-08-31) had written for every other per-segment sub-test; no revision of the PR ever had one",
   "introduced_date": "2025-01-08",
   "first_affected_version": "unreleased (main only, 11.0.0-SNAPSHOT; git tag --contains 11eb2c86979 is empty; would first ship in 11.0.0 unless fixed)",
   "affected_versions": "main from 11eb2c86979 (2025-01-08) [exec] through ea57360912ed [exec] and a9779ef3c193 [exec]; upstream main ffa9d816eeb4 (2026-10-26) still lacks the clause [read]. No release has the HNSW sub-test: 9.12.3, 10.1.0, 10.2.0 and 10.5.2 [exec], tags 10.1.0-10.5.2 and the branch_10x (657014b3c579) and branch_10_6 (c7788c5c48be) heads [read], although main's CHANGES lists GITHUB#13984 under 10.2.0; the parent d4f0a3244e51 [exec]: API absent",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-561.html",
   "repro": "repro/LFV-561/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-640",
   "priority": "low",
   "priority_rank": 712,
   "novelty": "new",
   "withheld": false,
   "area": "index / CheckIndex concurrent segment check and exorcise",
   "title": "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",
   "summary": "You repair an index that has a broken segment with CheckIndex -exorcise, or checkIndex() followed by exorciseIndex, on a multi-core machine, where threadCount defaults to the number of cores. You expect the same repaired commit that a sequential run (-threadCount 1) writes: the documentation describes the thread count and the executor overload only as ways to speed up the check, and exorcise only as removing the broken segments. Instead the concurrent path collects the segment results in ascending file-size order (a sort added so that small segments print first) and exorciseIndex commits that list as it is, so the surviving segments, and with them the relative order of their documents, are permuted; an index written in insertion order comes back reversed, so Sort.INDEXORDER returns the newest documents first instead of the oldest.",
   "impact_class": "minor",
   "introduced_commit": "424192e1704664dc0ebc55109feaad5990b945cb on main, 'LUCENE-9662: CheckIndex should be concurrent - parallelizing index check across segments (#128)' (apache/lucene#128 by GitHub zacharymorn, reviewed by dweiss, mikemccand and rmuir; issue LUCENE-9662 = apache/lucene#10701); 8.x backport 965b54ce3fd450dd42758244870b6228e1b5e5d4 on branch_8x (apache/lucene-solr#2567). It replaced the single commit-order loop that filled Status.segmentInfos and newSegments with a sequential branch (commit order) and a concurrent branch that sorts a copy of the commit by sizeInBytes and appends the results in that sorted order; exorciseIndex commits newSegments unchanged [read] [exec]. Follow-up 7f8607b59e034541d62687374b86197797a30a4f (#281) changed the default threadCount from min(cores, 4) to cores",
   "introduced_date": "2021-08-31 19:24 -0700 (commit) / 2021-09-01 UTC (merge) on main; 2021-09-10 on branch_8x (backport)",
   "first_affected_version": "8.11.0 [exec] (8.x line, through the backport lucene-solr#2567) and 9.0.0 [exec] (first main-line release); 8.10.1 and older are not affected [exec]",
   "affected_versions": "every release from 8.11.0 through 10.6.0, and main a9779ef3c193 and 645d4fe14a20; never fixed. [exec] the follow-up's version-portable history probe (public API and CLI, default and explicit thread counts, an executor, a sequential control) reorders on 8.11.0 (-ea and -da), 8.11.1, 8.11.2, 8.11.3, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da), and keeps commit order with -threadCount 1 everywhere; the independent reproduction's JUnit fails on main, 10.5.2 and 9.12.3 (and its main() variant on 8.11.2); the tie-breaker's command-line test fails on main, 10.5.2 and 9.12.3; the minimal test fails on main 645d4fe14a20 (-ea and -da) and on the 9.1.0 and 10.6.0 release jars (-da), 2026-10-31. [read] git tag --contains 424192e1704 lists every release tag from 9.0.0 to 10.6.0; CheckIndex.java on upstream main, branch_10x and branch_10_6 still sorts and appends in size order (contents API, 2026-10-27). Version note: in 8.11.0-8.11.4 and 9.0.0 the programmatic concurrent path with no infoStream first throws a NullPointerException (a separate known issue fixed by #637 in 9.1.0 and never backported to 8.11.x); the command line and callers that set an infoStream hit the reorder there [exec].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-640.html",
   "repro": "repro/LFV-640/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1060",
   "priority": "low",
   "priority_rank": 713,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter (hasUncommittedChanges: changeCount vs. buffered deletes in flight)",
   "title": "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)",
   "summary": "You delete a committed document with deleteDocuments, do not commit, and call hasUncommittedChanges() while another thread calls flush() or refreshes an NRT reader; you expect true, because the delete was acknowledged and is not in the last commit, and the javadoc allows only false positives. Instead the method reads changeCount first (still equal to the last commit's) and the in-RAM state second, and if the flush applies the delete, increments changeCount and empties the delete buffers between those two reads, it returns false; the next call returns true. A caller that commits only when the method returns true skips that commit.",
   "impact_class": "minor",
   "introduced_commit": "f9f0cdd56fdc550d193db5c841571d7bbb0ff6cb (trunk, svn r1533164, LUCENE-5289 = #6353 'IndexWriter.hasUncommittedChanges was returning false when only deletes were buffered', by Michael McCandless; a JIRA patch, not a GitHub PR): it appended '|| docWriter.anyChanges() || bufferedDeletesStream.any()' after the changeCount test, which created the read order; backports 00e4c287e87 (lucene_solr_4_5, 4.5.1) and a80e7e93243 (branch_4x, 4.6.0). Later commits kept the order (bc4da80776d, apache/lucene-solr#1460, 2020, extracted hasChangesInRam(); git blame on main points at it) [read]. Not a regression.",
   "introduced_date": "2013-10-17 (author date of f9f0cdd56fd and both backports)",
   "first_affected_version": "4.5.1 [exec] (lucene_solr_4_5 backport; also 4.6.0 from branch_4x). The method first appeared in 4.4.0 (LUCENE-5079), but 4.4.0 and 4.5.0 return false for any buffered-only delete even without concurrency (LUCENE-5289, fixed), so the concurrent-only form starts with 4.5.1",
   "affected_versions": "every release from 4.5.1 through 10.6.0, and main. [exec] the minimal JUnit fails on main 645d4fe14a20 (-ea and -da, seed DEADBEEF; 20 of 20 random seeds; re-run: -ea seed 5EED4641 and -da seed 5EED4642 fail), on the 10.6.0 release jars (4ae946e5a9b; -ea and -da), 10.5.2 (-da), 10.0.0 (-da), 9.12.3 (-ea and -da) and 9.1.0 (-da); the independent reproduction's own JUnit fails on main (-ea and -da), 10.5.2 (-ea and -da) and 9.12.3 (-da); a main() port with the same steps fails on 4.5.1 (-ea and -da), 4.6.0, 4.10.4, 5.5.5, 6.0.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.6.0 and main and passes with the operands swapped on 4.5.1 and main; the hook-free public-API race shows the false return on main, on the 10.6.0 RC1 and released core jars and on 10.5.2. [read] upstream main 716d6f216f5 (head at 2026-10-29) still has the same line at IndexWriter.java:4226 (re-read 2026-10-30); the last commit on IndexWriter.java is 169cbffd12f (author date 2026-09-21). Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1060.html",
   "repro": "repro/LFV-1060/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1043",
   "priority": "low",
   "priority_rank": 714,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter NRT (DocumentsWriterFlushQueue flush-ticket count, DocumentsWriter.anyChanges)",
   "title": "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",
   "summary": "Several threads add and delete documents on one IndexWriter; afterwards you commit and open an NRT reader without changing anything else, and you expect that reader's isCurrent() to be true, as it is on 10.5.2. Instead, if two threads pushed the buffered deletes at the same time and the second push found nothing left to freeze, DocumentsWriterFlushQueue.addTicket counted a ticket it never queued and never gives the count back (a regression of #15134). From then on DocumentsWriter.anyChanges() is always true, so every NRT reader of the writer, also ones opened after later commits, reports isCurrent() == false while openIfChanged() returns null.",
   "impact_class": "minor",
   "introduced_commit": "b85f030c6cce80fa44ee89b9f13b5aa346767fd5 (main; apache/lucene#15134 'Remove even more boolean success flags', author thecoop, approved by uschindler; label skip-changelog). In DocumentsWriterFlushQueue.addTicket it replaced the success flag plus finally { if (!success) decTickets(); }, which gave the count back both for an exception and for a null ticket, with catch (Throwable t) { decTickets(); throw t; }, which covers only the exception [read]. Enabling history, not defects: LUCENE-8813 (165d2d5ff531, 8.2.0) made the global-buffer freeze return null for a closed or empty queue and gave the count back for it on purpose; #12647 (268dd54a869, 9.9.0) introduced addTicket(Supplier) with the two null-capable callers in DocumentsWriter.applyAllDeletes and flushAllThreads and kept the give-back.",
   "introduced_date": "2025-10-09 (author and commit date of b85f030c6cc; PR merged 2025-10-09T08:22Z, opened 2025-08-28)",
   "first_affected_version": "unreleased (main since b85f030c6cc: 11.0.0-SNAPSHOT at 645d4fe14a20, upstream main is 12.0.0-SNAPSHOT since #16942; and branch_11x, so it would first ship in 11.0.0). No release has it: #15134 was never backported, so 10.6.0 (its RC1 revision 4ae946e5a9b) and every earlier release keep the old success-flag code",
   "affected_versions": "[exec] main 645d4fe14a20 (the minimal test fails with -ea and -da; the two-thread public-API test fails with -ea and -da, 20 of 20 iterations with -da, and the independent reproduction's own default-config test 10 of 10 with -da) and a build of the introducing commit b85f030c6cc (both tests, -ea and -da); main ea57360912ed. [read] upstream main 716d6f216f52 (head at 2026-10-29) and branch_11x: the last commit on DocumentsWriterFlushQueue.java is still b85f030c6cc. Not affected [exec]: the parent commit c67f8d38641 (both tests, -ea and -da), main with the parent's DocumentsWriterFlushQueue.java (-da), 10.6.0 RC1 4ae946e5a9b (core-jar main() forms of both tests, -da), 10.5.2 and 9.12.3 (-ea and -da), 9.9.0 (minimal test, -da) and 9.8.0 (a port to addDeletes, -da); [read] every release 9.0.0 to 10.5.2, 8.2.0 to 8.8.1 and branch_10_6 (old success-flag code; branch_10x was retired upstream by #16911 on 2026-10-29)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1043.html",
   "repro": "repro/LFV-1043/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-054",
   "priority": "low",
   "priority_rank": 715,
   "novelty": "new",
   "withheld": false,
   "area": "search / query cache",
   "title": "LRUQueryCache's 16 hard partitions give a 0% hit rate with the class-javadoc configuration (main only)",
   "summary": "On main, you build an LRUQueryCache with the configuration from its class javadoc (maxSize 256, 50 MB) and run one filter over more than 16 segments. You expect the filter to be cached. Instead maxSize and RAM are hard-split across 16 partitions routed by query, so it gets a 0% hit rate forever; maxSize < 16 caches nothing, and partition counts that are 0, negative or not a power of two crash or waste capacity.",
   "impact_class": "minor",
   "introduced_commit": "#15558 (d50fb36d9af) and #16657 (fadd63e0eb4)",
   "introduced_date": "2026-04-14 (#15558 merged); 2026-09-29 (#16657)",
   "first_affected_version": "unreleased (main only; #15558 not backported to 10.x)",
   "affected_versions": "main [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-054.html",
   "repro": "repro/LFV-054/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-991",
   "priority": "low",
   "priority_rank": 716,
   "novelty": "new",
   "withheld": false,
   "area": "search / query cache (LRUQueryCache.clear() and the onClear statistics callback)",
   "title": "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",
   "summary": "You subclass LRUQueryCache to keep per-index statistics the way its class javadoc suggests (count in onCacheEntryInserted/onCacheEntryEvicted, reset in onClear()) and call clear() while searches are running. You expect the subclass's numbers to match getCacheSize() and ramBytesUsed() afterwards, as on 10.x, where clear() and onClear() run under the same lock every insertion takes; on main, clear() empties the partitions one at a time, each under its own lock, and then calls onClear() with no lock, so an entry that a search caches into an already emptied partition (or just before onClear()) stays in the cache while onClear() wipes its count. The subclass then reports 0 entries and 0 bytes for a cache that holds 1 entry of 336 bytes, -1 and -336 once that entry is evicted, and the error lasts until the next clear().",
   "impact_class": "minor",
   "introduced_commit": "d50fb36d9af3 (GITHUB#15558 'Refactor QueryCache to improve performance', by Sagar Upadhyaya (sgup432), merged by Michael Froh (msfroh); design issue #14222; the clear()/onClear() shape is already in the PR's first partitioning commit ef7cf0ff101e, authored 2026-01-08) [exec]. The class javadoc sentence it made false for onClear ('called synchronously and under a lock') dates from LUCENE-6157 (d7e0fd28dd9, Adrien Grand, 2015) [read]",
   "introduced_date": "2026-04-14 (squash commit d50fb36d9af3, author and commit date; PR opened 2026-01-09)",
   "first_affected_version": "unreleased (main / 11.0.0-SNAPSHOT since 2026-04-14 and branch_11x, cut from main 2026-10-28; #15558 was deliberately not backported, so every release with LRUQueryCache, 5.1.0 to 10.5.2, and 10.6.0 (released 2026-10-29; branch_10_6 4ae946e5a9b) are unaffected [exec])",
   "affected_versions": "main from d50fb36d9af3 (2026-04-14) to a9779ef3c193 [exec]; branch_11x [read]; upstream main 645d4fe14a2 (2026-10-28) [read]. Not affected [exec]: 8.11.4, 9.12.3, 10.4.0, 10.5.0, 10.5.2, the 10.6 RC branch_10_6 4ae946e5a9b9 (core jar only) and main's parent commit 55b4574a20d2 (history driver; latch-free stress 0 of 1000 rounds on 10.5.2 and the parent); 10.5.2 and 9.12.3 with -ea and -da; 10.5.2; 10.5.2 and branch_10_6 (finder's compat JUnit; finder's stress 0 of 300 on branch_10_6). [read] Every release tag from 5.1.0 to 10.5.2 runs clear() and onClear() under the one lock insertions take (synchronized 5.1.0-6.0.1, ReentrantLock 6.1.0-9.10.0, ReadWriteLock write lock from 9.11.0, #13306); on 10.x a search that finds the write lock held skips caching (readLock.tryLock), so the interleaving cannot occur. All runs JDK 25.0.3 on Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-991.html",
   "repro": "repro/LFV-991/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1070",
   "priority": "low",
   "priority_rank": 717,
   "novelty": "new",
   "withheld": false,
   "area": "misc / index: BpVectorReorderer (BP doc-id reordering over a vector field, through BPReorderingMergePolicy, computeDocMap and the command line)",
   "title": "BpVectorReorderer never calls the Executor it is given; any non-null executor makes it fork its work onto ForkJoinPool.commonPool()",
   "summary": "You reorder a segment with BpVectorReorderer and pass an Executor, for example the same-thread intra-merge executor that IndexWriter hands to BPReorderingMergePolicy under SerialMergeScheduler, or the pool the command line builds for --thread-count, and expect the work to run on the calling thread or on that executor, as it does for the sibling BPIndexReorderer. Instead the executor is never called: the tasks are RecursiveActions forked with ForkJoinTask.invokeAll from a thread outside any ForkJoinPool, so any non-null executor only switches forking on and the forked work runs on ForkJoinPool.commonPool(). With a run-on-caller executor and 4,096 two-dimensional vectors, vectors are read on a common-pool worker as well as on the caller; the resulting order is still correct.",
   "impact_class": "minor",
   "introduced_commit": "02a09f6ab124e994fd1af42965617c8b5ec67bcc, apache/lucene#14097 'HNSW BP reordering' (by msokolov; author date = commit date 2025-01-07T14:41:31Z, PR merged 2025-01-07T14:41:35Z): it added BpVectorReorderer, the IndexReorderer interface ('@param executor may be used to parallelize reordering work.') and the BPReorderingMergePolicy(MergePolicy, IndexReorderer) constructor together, with RecursiveAction tasks that fork through ForkJoinTask.invokeAll and a TaskExecutor field that only shouldFork null-checks [exec]. Context, not the defect: #13289 (ff8b81afc59, 2024-09-12) had moved the sibling BPIndexReorderer from RecursiveAction to Callable tasks forked through TaskExecutor.invokeAll four months earlier.",
   "introduced_date": "2025-01-07",
   "first_affected_version": "unreleased (main and branch_11x; CHANGES.txt lists GITHUB#14097 under 11.0.0 New Features; BpVectorReorderer is absent from every 9.x and 10.x release including 10.6.0 (4ae946e5a9b) and from branch_10_6 and branch_10x [exec]); the first affected release would be 11.0.0 unless it is fixed first",
   "affected_versions": "main from 02a09f6ab12 (2025-01-07) through 645d4fe14a20 (2026-10-28) [exec]; upstream main f815e679bf6 (2026-11-01) and branch_11x da3ea39fa59 [read]. Not affected, the API is absent: the parent 72d93de50c2, 9.12.3, 10.1.0, 10.2.0, 10.5.2 and 10.6.0 [exec]; branch_10_6 and branch_10x [read]. All runs on Linux aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1070.html",
   "repro": "repro/LFV-1070/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-023",
   "priority": "low",
   "priority_rank": 718,
   "novelty": "new",
   "withheld": false,
   "area": "util / automaton",
   "title": "RegExp CASE_INSENSITIVE matching is asymmetric for U+0130 and U+0131 (dotted and dotless i)",
   "summary": "You match text that contains U+0130 or U+0131 with a CASE_INSENSITIVE RegExp. You expect case-insensitive matching to be symmetric (the study compared against ICU4J and java.util.regex). Instead the result depends on which member of the pair is in the pattern and which is in the text.",
   "impact_class": "silent wrong results",
   "introduced_commit": "#14192 (a288a6e987a) and #14384 (8914678afc1)",
   "introduced_date": "2025-02-18 (#14192); 2025-03-21 (#14384)",
   "first_affected_version": "10.2.0",
   "affected_versions": "10.2.0, 10.3.1, 10.4.0, 10.5.2 and main [exec]; 10.1.0 not affected (ASCII-only case-insensitivity) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-023.html",
   "repro": "repro/LFV-023/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-238",
   "priority": "low",
   "priority_rank": 719,
   "novelty": "known",
   "withheld": false,
   "area": "grouping / collector managers (FirstPassGroupingCollectorManager, TopGroupsCollectorManager and BlockGroupingCollectorManager reduce through the cross-shard merges SearchGroup.merge, TopGroups.merge and TopGroups.mergeBlockGroups; GroupingSearch)",
   "title": "With an executor, grouped search breaks ties by slice number instead of doc ID, so tied groups and tied documents differ from sequential search",
   "summary": "You run a grouped search (GroupingSearch, or the grouping collector managers) on an IndexSearcher that has an executor, and several groups or several documents tie on the sort, for example because every hit scores 1.0. You expect the tie to be broken by doc ID, as Sort's javadoc says and as the same search without an executor does, so the top group and the top documents are the same either way. Instead the per-slice results are combined with merges written for real shards, which break ties by shard index, here the slice number: the search returns doc 1 instead of doc 0, or group g1 instead of g0, and the choice changes whenever the slicing changes.",
   "impact_class": "silent wrong results",
   "introduced_commit": "e26a959e2c7efabddff02382763df8302098e16b, GITHUB#15603 'Introduce TopGroupsCollectorManager' (tied documents: TopGroupsCollectorManager.reduce -> TopGroups.merge; branch_10x backport 8e443458c2f, #15980), the first of the managers that reuse a cross-shard merge with one shard per slice. Further trigger paths: 636e8e9f587, #15574 FirstPassGroupingCollectorManager (tied groups: SearchGroup.merge; backport 5c701b3f553); d27d080d101, #15936 BlockGroupingCollectorManager with the new TopGroups.mergeBlockGroups, and GroupingSearch(Query) switched to it (tied blocks; backport 2e00e95ace6); 3afffeef5a8, #16247, which switched GroupingSearch(String)/(ValueSource) to the managers (main and branch_10_6 only, backport d60e550b47f). [read]. No commit-level build of the three manager commits. Latent origins, correct for real shards: SearchGroup.merge's 'Tie break by min shard index' (a1e74fd6c94, LUCENE-3191, 2011) and TopGroups.merge setting shardIndex before TopDocs.merge (f686167e710, LUCENE-8857, 2019).",
   "introduced_date": "2026-03-31 (#15603 merged on main); further paths 2026-06-02 (#15574), 2026-06-15 (#15936) and 2026-07-08 (#16247, released in 10.6.0)",
   "first_affected_version": "10.5.0 [exec] (the three collector managers and block GroupingSearch(Query)); 10.4.0 is the last release without it [exec]; the GroupingSearch(String)/(ValueSource) path is first released in 10.6.0 (2026-10-29; main and branch_10_6, #16247)",
   "affected_versions": "10.5.0, 10.5.1 and 10.5.2 [exec]: the finder's JUnit fails 3 of 6 (both manager tests and block GroupingSearch(Query); the GroupingSearch(String) tests pass because term GroupingSearch was still sequential there), also with -da on 10.5.2; the independent reproduction's own suite fails 5 of 7 on 10.5.0 and 10.5.2. main ea57360912ed [exec]: 6 of 6 fail with -ea and -da (the independent reproduction's suite 6 of 7, its core top-N control passes). 10.6.0 (released 2026-10-29): branch_10_6 contains every introducing commit [read]. Not affected [exec]: 10.4.0, 10.3.2, 10.0.0 and 9.12.3 (a GroupingSearch probe passes 4 of 4; the managers do not exist there, and GroupingSearch collected sequentially in doc-ID order). All runs on aarch64 with JDK 25.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15936",
    "https://github.com/apache/lucene/issues/16247",
    "https://github.com/apache/lucene/issues/9873",
    "https://issues.apache.org/jira/browse/LUCENE-8829",
    "https://github.com/apache/lucene/issues/16548",
    "https://github.com/apache/lucene/issues/16569"
   ],
   "doc": "",
   "repro": "repro/LFV-238/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-239",
   "priority": "low",
   "priority_rank": 720,
   "novelty": "new",
   "withheld": false,
   "area": "grouping / block grouping (TopGroups.mergeBlockGroups and BlockGroupingCollectorManager.reduce; GroupingSearch(Query groupEndDocs) on a searcher with an executor)",
   "title": "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",
   "summary": "You index each group as a document block and run block grouping (GroupingSearch(Query groupEndDocs)) with a field group sort on an IndexSearcher that has an executor. You expect TopGroups.maxScore to be the same number whether the search runs sequentially or concurrently: sequential block grouping and two-pass term grouping report the best score of the returned groups, and the javadoc says 'Highest score across all hits'. Since 10.5.0 the concurrent value is the maximum over every group that any slice kept, including groups that are not returned, so it changes with the slicing (sequential 1.0, concurrent 5.0 from an unreturned group, best hit 9.0 in the repro), while the returned groups and documents are correct.",
   "impact_class": "silent wrong results",
   "introduced_commit": "d27d080d1013fe86519a9843b221bada6c9466e1 (main) and the same change on the 10.x release line, 2e00e95ace619c697b499f6b3a55eb8476acf061: GITHUB#15936 'Introduce BlockGroupingCollectorManager' by gaobinlong, approved and merged by javanna [read]. The per-slice maxScore it aggregates is older (LUCENE-4077, 2012, reorganised by #15942) and correct for a single collector; #15942 is not a cause (the revert runs keep it and pass).",
   "introduced_date": "2026-06-15 (merged on main 09:29:25Z; the 10.x-line commit the same day)",
   "first_affected_version": "10.5.0 [exec] (release tag commit f6eaee8148b7, commit date 2026-06-19; 2e00e95ace6 is an ancestor of the 10.5.0, 10.5.1 and 10.5.2 tags and not of 10.4.0); 10.4.0 is the last release without it [exec]",
   "affected_versions": "10.5.0, 10.5.1 and 10.5.2 (every 10.5.x release) and main ea57360912ed [exec]: the finder's JUnit fails on all four (10.5.2 and main also with -da); the independent reproduction's suite fails 3 of 5 on main (-ea and -da), 10.5.0 and 10.5.2; the version-neutral default-slicing GroupingSearch repro fails on 10.5.0, 10.5.2 and main; the intended-behaviour check's default-slicing repro fails on main (-ea and -da) and 10.5.2. branch_10_6 (10.6.0, released 2026-10-29) has method-for-method identical code [read]. Not affected [exec]: 10.4.0 and 9.12.3 (version-neutral repros; the manager and mergeBlockGroups do not exist there, and GroupingSearch block grouping ran one sequential collector). Older releases are unaffected by construction but were not executed. All runs on aarch64 with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-239.html",
   "repro": "repro/LFV-239/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-272",
   "priority": "low",
   "priority_rank": 721,
   "novelty": "new",
   "withheld": false,
   "area": "search / SynonymQuery scoring (SynonymScorer.freq float sum) and its merged-impacts max-score bound",
   "title": "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()",
   "summary": "You run a SynonymQuery with three or more boosted terms, for example Synonym(a^0.2, b^0.2, c^0.3) over four identical documents 'a b c' with the default BM25, and expect identical documents to score the same and explain() to report the hit's score, because the query scores 'the sum of all term frequencies for the document'. SynonymScorer.freq() adds boost * freq in float, in the order of the disjunction's topList(), and that order depends on how the iterator reached the document, so the rounding differs: docs 0 and 3 score 0.038817033, docs 1 and 2 score 0.038817026, and explain(doc 1) reports 0.038817033. The same float sum can also round above the exact integer sum that the merged impacts use as the max-score bound once a field holds more than 2^24 occurrences of the terms: under ClassicSimilarity a document scores 1.032795 while getMaxScore() is 1.0327948, and a pruned top-1 search returns a different document than an exhaustive one.",
   "impact_class": "minor",
   "introduced_commit": "d8cfeba912ea9c474f81f336d1bf403477dc553c (LUCENE-8652 'SynonymQuery can now deboost the document frequency of each term when blending the score of the synonym', by jimczi, 2019-03-11; a JIRA patch with no pull request, migrated to GitHub issue #9698; branch_8x backport 24427f9f5cd2ab9883d1d3e5ca13a205326478a4) [read]. The exact long merged-impacts bound comes from LUCENE-8312 (0a1de2c4a57, first released in 8.0.0); it is not the cause",
   "introduced_date": "2019-03-11",
   "first_affected_version": "8.1.0 [exec] (released 2019-05-13; 8.0.0 passes [exec]); on the main line the first release is 9.0.0 [exec]",
   "affected_versions": "8.1.0 to 10.5.2 and main ea57360912ed [exec] [read]; not affected: 8.0.0 [exec] (exact int sum; the boosted repro does not compile there because SynonymQuery.Builder did not exist yet). Exposure: from 8.1.0 boosted synonym queries had to be built with the Builder; from 8.5.0 (LUCENE-9171) QueryBuilder passes token BoostAttribute values to it. Not fixed upstream as of 2026-10-26 (upstream main is ea57360912ed; main and branch_10x still have the float running sum). Not run: 10.6.0 (released 2026-10-29; branch not in the clone), x86",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-272.html",
   "repro": "repro/LFV-272/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-831",
   "priority": "low",
   "priority_rank": 722,
   "novelty": "known",
   "withheld": false,
   "area": "suggest / document (NRT) suggester (NRTSuggesterBuilder.finishTerm dedup bytes; NRTSuggester top-n search through Util.TopNSearcher; TopSuggestDocsCollector tie order)",
   "title": "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",
   "summary": "You index three documents with the same suggestion 'c' and weights 1, 1 and 2 in one segment and call SuggestIndexSearcher.suggest(PrefixCompletionQuery 'c', n, skipDuplicates=false). For n=3 you get docs [2, 0, 1] (score, then the smaller doc id, as the collector's comparator orders them), so n=2 should return the first two, [2, 0]; it returns [2, 1]. NRTSuggesterBuilder.finishTerm numbers the copies of one analyzed form (its dedup bytes) by iterating a java.util.PriorityQueue, whose iterator returns heap-array order ([doc 2, doc 1, doc 0] here), and the per-segment TopNSearcher breaks score ties by those bytes and stops after n results, so for n=2 doc 0 never reaches the collector.",
   "impact_class": "minor",
   "introduced_commit": "b7adb6ac7704a7e6364ee0d831bf77cf849f2090 (trunk, svn r1669698, 'LUCENE-6339: Added Near-real time Document Suggester via custom postings format', Areek Zillur, 2015-03-27; a JIRA patch, now GitHub issue #7400, no pull request; first release on that line 6.0.0) and its branch_5x backport 40e94c39ad3b0f018ae9647b7d30bd0cfe341d86 (svn r1669715, 2015-03-28), which shipped first, in 5.1.0 [read] [exec]. Present since the code was written, not a regression",
   "introduced_date": "2015-03-27 (b7adb6ac770, trunk; branch_5x backport 40e94c39ad3 on 2015-03-28)",
   "first_affected_version": "5.1.0 [exec] (release 2015-04-13, the first with the org.apache.lucene.search.suggest.document package, from the branch_5x backport; the history program fails there with -da and -ea with the same doc lists as main); 5.0.0 has no such package, so the program does not compile [exec]",
   "affected_versions": "every release from 5.1.0 through 10.5.2, 10.6.0 (by reading) and main a9779ef3c193; no version has a fix [exec] [read]. All runs used JDK 25; 10.6.0 (released 2026-10-29) was read at 4ae946e5a9b9 (above), not executed",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/14364",
    "https://github.com/apache/lucene/issues/11643",
    "https://issues.apache.org/jira/browse/LUCENE-10607",
    "https://github.com/apache/lucene/issues/970",
    "https://issues.apache.org/jira/browse/LUCENE-7686",
    "https://issues.apache.org/jira/browse/LUCENE-8529"
   ],
   "doc": "",
   "repro": "repro/LFV-831/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-273",
   "priority": "low",
   "priority_rank": 723,
   "novelty": "new",
   "withheld": false,
   "area": "queries / function scoring (FunctionScoreQuery and FunctionQuery negative-value clamps, LUCENE-7996; visible through core TopScoreDocCollector tie handling)",
   "title": "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",
   "summary": "You index doc 0 with FloatDocValuesField(\"f\", -0f) and doc 1 with FloatDocValuesField(\"f\", 0f) and search new FunctionScoreQuery(new TermQuery(k:x), DoubleValuesSource.fromFloatField(\"f\")) or new FunctionQuery(new FloatFieldSource(\"f\")), expecting doc 0 to score 0 like any negative function value since LUCENE-7996 ('Scorers are no longer allowed to produce negative scores'; the test framework's AssertingScorer checks Float.compare(score, 0f) >= 0) and the two zero-scored hits to tie in doc-id order. Instead doc 0 scores -0.0f, because the clamps test 'factor >= 0' (FunctionScoreQuery) and 'val >= 0 == false' (FunctionQuery) and -0.0 >= 0 is true in Java; explain() does not truncate it either. Since 10.2.0, search(q, 1) returns doc 0 while search(q, 2) returns [doc 1, doc 0], because TopScoreDocCollector's 'score <= topScore' test treats the two zeros as equal while its heap and HitQueue order -0.0 below 0.0.",
   "impact_class": "minor",
   "introduced_commit": "a8a63464e7da63b3dbc884634fd0e00b3f0c140b (LUCENE-7996 'Queries are now required to produce positive scores.', by jpountz; a JIRA patch, now GitHub issue #9044, no pull request), which created the non-negative score rule and, in the same commit, the four clamp conditions 'factor >= 0' and 'value < 0' (FunctionScoreQuery score/explain) and 'val >= 0 == false' and '< 0' (FunctionQuery score/explain) [read]; the top-1/top-2 consequence came with #13935 (main d92d0451738, branch_10x b635f5c436c, by original-brownbear, merged 2025-01-06: HitQueue.lessThan moved from == to Float.compare) [exec] and, independently of HitQueue from 10.3.0 on, with #14714 (main a309bd6da9b, branch_10x 57af705c68e, by gf2121: DocScoreEncoder sortable-bits heap) [exec]",
   "introduced_date": "2017-12-06 (a8a63464e7d); top-1/top-2 consequence from 2025-01-06 (#13935, first released in 10.2.0, tag 2025-04-10)",
   "first_affected_version": "8.0.0 [exec] for the -0.0 score (release tag 2019-03-13); 10.2.0 [exec] for the top-1/top-2 inconsistency; 10.3.0 [exec] for the AssertingIndexSearcher failure seen by test suites with -ea",
   "affected_versions": "every release from 8.0.0 through 10.6.0 (10.6.0 by reading) and main ea57360912ed [exec]; top-1 not the head of top-2: 10.2.0 to 10.5.2 and main [exec], not 8.0.0 to 10.1.0 [exec]; AssertingIndexSearcher rejects the score with -ea: 10.3.0 and later (10.2.2 accepts) [exec]; not applicable: releases before 8.0.0, which have no clamp and no non-negative score rule (6.5.0, 7.1.0, 7.2.0 and 7.7.3 return -0.0 for -0.0 and -1.0 for -1.0) [exec]; branch_10x (unreleased) and branch_10_6 (the branch of 10.6.0, released 2026-10-29) have the same clamp conditions (no commit has changed them since LUCENE-7996) [read], so 10.6.0 is very likely affected [not executed]; not fixed upstream [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-273.html",
   "repro": "repro/LFV-273/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-835",
   "priority": "low",
   "priority_rank": 724,
   "novelty": "new",
   "withheld": false,
   "area": "queries / payloads (PayloadScoreQuery payload-score clamp, LUCENE-7996; visible through core TopScoreDocCollector tie handling; sibling of LFV-273's function-query clamps)",
   "title": "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",
   "summary": "Index two documents whose float payloads are '-0.0' and '0.0' (WhitespaceTokenizer + DelimitedPayloadTokenFilter with FloatEncoder) and search PayloadScoreQuery(SpanTermQuery, MaxPayloadFunction or MinPayloadFunction, a decoder that calls PayloadHelper.decodeFloat, includeSpanScore false or true). You expect both hits to score 0 and tie in doc-id order, because PayloadScoreQuery maps every negative payload score to 0 (LUCENE-7996: 'Scorers are no longer allowed to produce negative scores'; the test framework's AssertingScorer checks Float.compare(score, 0f) >= 0), as it does for a payload of -1.0. Instead the -0.0 document scores and explains as -0.0, because the clamp 'score >= 0 == false' and the explain test 'value < 0' are both false for -0.0, and since 10.2.0 search(q, 1) returns that document while search(q, 2) ranks it second.",
   "impact_class": "minor",
   "introduced_commit": "187849f9b67ba6b7e6c2d06cc25359bf53b2ce9f [read] ('LUCENE-7996: PayloadScoreQuery must produce positive scores.', by jpountz, 2017-12-06; master only, for 8.0, never backported to 7.x; JIRA era, now GitHub issue #9044, no pull request): it added both conditions, 'if (score >= 0 == false) return 0' in getPayloadScore and 'if (expl.getValue() < 0)' ... 'truncated score' in getPayloadExplanation, hours after the rule itself (a8a63464e7d, same author and day: CHANGES, MIGRATE, AssertingScorer's 'Float.compare(score, 0f) >= 0', BoostQuery's -0f rejection and the function-query clamps of LFV-273); git log -G lists only 187849f9b67 for the score condition and 187849f9b67 plus c1030eeb74e (LUCENE-8012, getValue() -> getValue().floatValue()) for the explain condition [read]; [exec]. The top-1/top-2 consequence came with #13935 (main d92d0451738, branch_10x b635f5c436c, by original-brownbear, merged 2025-01-06: HitQueue.lessThan moved from == to Float.compare) [exec] and, independently of HitQueue from 10.3.0 on, with #14714 (main a309bd6da9b, branch_10x 57af705c68e, by gf2121: DocScoreEncoder sortable-bits heap) [exec]; the AssertingIndexSearcher failure with #14452 (846ff673301, by jpountz) [exec]",
   "introduced_date": "2017-12-06 (187849f9b67); top-1/top-2 consequence from 2025-01-06 (#13935, first released in 10.2.0, tag 2025-04-10)",
   "first_affected_version": "8.0.0 [exec] for the -0.0 score and explanation (release tag 2019-03-13); 10.2.0 [exec] for the top-1/top-2 inconsistency; 10.3.0 [exec] for the AssertingIndexSearcher failure seen by test suites with -ea. Not a regression from a clamp-free state: releases before 8.0.0 have no clamp and no non-negative score rule [exec]",
   "affected_versions": "every release from 8.0.0 through 10.5.2, 10.6.0 (by reading) and main a9779ef3c193 [exec]; the finder's, the independent reproduction's, the cross-model review's and the intended-behaviour check's tests agree on main, 10.5.2 and 9.12.3 [exec]; all 51 release tags from 8.0.0 in the history clone contain 187849f9b67 (8.8.2-8.11.4 come from the separate lucene-solr repository; 8.11.4 executed) [read]; not applicable before 8.0.0 (no clamp, no contract) [exec]; upstream main 20ced71c1e6e, branch_10x 657014b3c579 and branch_10_6 4ae946e5a9b9 have the same clamp lines [read], so 10.6.0 is affected by reading [not executed]; not fixed upstream; aarch64 with JDK 25 only",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-835.html",
   "repro": "repro/LFV-835/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-077",
   "priority": "low",
   "priority_rank": 725,
   "novelty": "known",
   "withheld": false,
   "area": "search / IndexSearcher timeout",
   "title": "A timed-out search reports its partial hit count as TotalHits.Relation.EQUAL_TO",
   "summary": "You set IndexSearcher#setTimeout and a search times out after matching part of the index. You expect the hit count to be marked as a lower bound. Instead the partial count (100 hits when 500 match) is reported with Relation.EQUAL_TO.",
   "impact_class": "silent wrong results",
   "introduced_commit": "unknown (not yet bisected)",
   "introduced_date": "unknown (not yet bisected)",
   "first_affected_version": "unknown (not yet bisected; 9.12.3 is the oldest version executed)",
   "affected_versions": "9.12.3, 10.1.0, 10.5.2 and main [exec]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/11188",
    "https://issues.apache.org/jira/browse/LUCENE-10151",
    "https://github.com/apache/lucene/issues/927"
   ],
   "doc": "",
   "repro": "repro/LFV-077/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-050",
   "priority": "low",
   "priority_rank": 726,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / flexible",
   "title": "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",
   "summary": "You parse i:{2147483647 TO *], i>2147483647, l>9223372036854775807 or i<\"-2147483648\" with the flexible StandardQueryParser and a PointsConfig for the field. You expect no hits, because no int is larger than Integer.MAX_VALUE (or smaller than MIN_VALUE). Instead PointRangeQueryNodeBuilder adds or subtracts 1 for the exclusive bound without an overflow check, so MAX+1 wraps to MIN, the query becomes the full range and matches every document with the field (5 of 5 in the repro; {MAX TO MAX} matches all but one).",
   "impact_class": "silent wrong results",
   "introduced_commit": "89cc676f2bf (LUCENE-7089)",
   "introduced_date": "2016-03-09",
   "first_affected_version": "6.0.0 [exec] (89cc676f2bf, LUCENE-7089, reached 6.0.0 through the branch_6_0 cherry-pick 306d3fe8524); 5.5.0 is not affected: it has no points API and its legacy numeric path gives 0 hits [exec]",
   "affected_versions": "every release from 6.0.0 to 10.6.0 (93 releases) and main 645d4fe14a20 [exec]; never fixed",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-050.html",
   "repro": "repro/LFV-050/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-059",
   "priority": "low",
   "priority_rank": 727,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / flexible",
   "title": "Flexible StandardQueryParser misses -0.0 documents for exclusive float/double bounds",
   "summary": "With the flexible StandardQueryParser and a Float/Double PointsConfig, you query x:[* TO 0} on an index that holds -0.0. You expect every document to match exactly one of x < 0 and x >= 0. Instead the parser uses Math.nextUp/nextDown for exclusive bounds, so x:[* TO 0} misses -0.0 documents and such a document matches neither x < 0 nor x >= 0.",
   "impact_class": "silent wrong results",
   "introduced_commit": "89cc676f2bf (LUCENE-7089; LUCENE-7594 came later, in 6.4.0) [read]",
   "introduced_date": "2016-03-09",
   "first_affected_version": "6.0.0 [exec] (89cc676f2bf, LUCENE-7089, reached 6.0.0 through the branch_6_0 cherry-pick 306d3fe8524); 5.5.0 and 5.5.5 are not affected: they have no points path and their numeric path counts -0.0 below 0 correctly [exec]",
   "affected_versions": "6.0.0 to 10.6.0 and main 645d4fe14a20 [exec]; the tagged releases in between carry the same builder blob [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-059.html",
   "repro": "repro/LFV-059/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-356",
   "priority": "low",
   "priority_rank": 728,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / flexible parser node serialization (QueryNode#toQueryString of FieldQueryNode, QuotedFieldQueryNode, FuzzyQueryNode, AbstractRangeQueryNode and the other field-printing nodes)",
   "title": "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",
   "summary": "The standard flexible-parser grammar accepts escaped field names on purpose ('my\\ field:x' is a query on the field 'my field', 'a\\:b:x' on 'a:b'), and QueryNode#toQueryString is documented to return 'a query string understood by the query parser' that 'can be parsed back by the original text parser'. Every toQueryString that prints a field appends the name raw (only the term goes through the escaper), so the node of 'my\\ field:x' prints 'my field:x', which parses as df:my OR field:x, and the node of 'a\\:b:x' prints 'a:b:x', which is a syntax error. The same happens for phrase and fuzzy nodes, for range nodes on main (after the #7865 range fix), and for hand-built nodes such as new FieldQueryNode(\"my field\", \"x\", 0, 0).",
   "impact_class": "minor",
   "introduced_commit": "343992fcbb4b31249f07354014723f18d0508d8a (LUCENE-1567 'New flexible QueryParser framework', SVN r800191; SVN era, no GitHub PR; issue migrated as apache/lucene#2641). The raw field printing in FieldQueryNode, QuotedFieldQueryNode and FuzzyQueryNode is unchanged since that commit, and its grammar already stripped escapes from field names (discardEscapeChar(fieldToken.image); LUCENE-9528 / 3a92e1b93eb moved this into FieldName() for 9.0 without changing it). [read]. The range variant was un-masked, not introduced, by 17ca89d52fa (PR #14697, fixes GITHUB#7865 / LUCENE-6807, merged 2025-05-29, unreleased 11.0.0): before it the range printer's output did not parse for any field, and it added sb.append(getField()).append(\":\") with the raw field. Other field-printing sites (read only): WildcardQueryNode (LUCENE-588, a25dc8b9d5c, 2010), RegexpQueryNode (LUCENE-2604, 838e19beae1, 2010), PointQueryNode (LUCENE-1768, c178c8eb1a8, 2011).",
   "introduced_date": "2009-08-03 (343992fcbb4b); range variant visible from 2025-05-29 (17ca89d52fa, main only)",
   "first_affected_version": "2.9.0 [exec] (the first release with the flexible query parser; 2.4.1 has no such API [exec]); range-on-escaped-field variant: unreleased (main only, after #14697, slated for 11.0.0)",
   "affected_versions": "every release from 2.9.0 to 10.5.2 (the last before 10.6.0) and main ea57360912ed for term, phrase, fuzzy, colon and hand-built nodes; no fixed release. [exec] a version-portable main() probe fails 5 of 5 field-name cases with 3 of 3 controls passing on 2.9.0, 3.6.2, 4.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the finder's JUnit fails 3 of 4 on main (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 6 of 11 on main (-ea and -da) and 7 of 11 on 10.5.2 and 9.12.3; the intended-behaviour check's fails 5 of 9 on main (-ea and -da) and 10.5.2. Range variant: on 9.12.3, 10.5.2 and older the range printer still has the pre-#14697 bracket bug ('[my field:a my field:b]', and the plain-field range control fails too, which is the independent reproduction's 7th failure), so the range-on-escaped-field failure is a clean, separate demonstration only on main; a commit-level check (AbstractRangeQueryNode at 17ca89d52fa^ shadowed onto main) makes the plain range control fail again. [read] source-checked in all 134 release tags 2.9.0..10.5.2 of the history clone; untagged releases (2.9.3, 2.9.4, 3.0.2, 3.0.3, 8.8.2, 8.9.0, 8.10.x, 8.11.0-8.11.3) inferred from identical neighbours. Upstream main still prints this.field raw (GitHub REST, 2026-10-26). Not executed: x86, the JDK of each release's era (all runs JDK 25.0.3 aarch64; the code path is pure string handling).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-356.html",
   "repro": "repro/LFV-356/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-748",
   "priority": "low",
   "priority_rank": 729,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / flexible StandardQueryParser interval function nodes (IntervalQueryNode#toQueryString; intervalfn FuzzyTerm, Wildcard and AnalyzedText toString)",
   "title": "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))",
   "summary": "You parse fn:fuzzyTerm(abc), fn:wildcard(ab* 5) or fn:or(\"a:b\" c) with the flexible syntax parser, print the node tree with toQueryString, and expect a string that StandardQueryParser reads back as the same query, as the flexible parser's package documentation promises ('a query string that can be parsed back by the original text parser'). Instead FuzzyTerm prints maxEdits and maxExpansions with no space between them (fn:fuzzyTerm(abc 2128), which re-parses as maxEdits 2128 and throws 'max edits must be 0..2'), Wildcard prints 'maxExpansions:5', a syntax error, and AnalyzedText quotes a literal only when it contains ASCII whitespace, so fn:or(\"a:b\" c) prints the unparsable fn:or(a:b c). A quoted literal with the ideographic space U+3000 prints unquoted and re-parses, with no error, as two separate literals.",
   "impact_class": "minor",
   "introduced_commit": "f725b27e12a992f12aab12a8e8bfb9b31125bdae (main, 2021-11-11, by dweiss): 'LUCENE-10223: interval support in standard syntax parser (#429)' (issue LUCENE-10223 = GitHub #11259, PR apache/lucene#429), which added IntervalQueryNode#toQueryString (field + ':' + the function's toString, the EscapeQuerySyntax argument unused), the whitespace-only quoting rule AnalyzedText.requiresQuotes and the unquoted wildcard glob; and f6cebac3337926ca871b922241976a4ba4799c70 (main, 2022-02-10, by dweiss): 'LUCENE-10414: Add fn:fuzzyTerm interval function to flexible query parser (#668)' (GitHub #11450, PR #668), which added FuzzyTerm.toString with the format 'fn:fuzzyTerm(%s %d%s)' and the Wildcard ' maxExpansions:' suffix; the branch_9x backports ff9ee28c603 and 9a293da5967 are the commits that shipped in 9.1.0 [read]",
   "introduced_date": "2021-11-11 (LUCENE-10223: literal quoting, unquoted glob, IntervalQueryNode#toQueryString); 2022-02-10 (LUCENE-10414: fuzzyTerm numbers run together, 'maxExpansions:N' suffix)",
   "first_affected_version": "9.1.0 (tagged 2022-03-21) [exec]: both introducing changes first shipped there; 9.0.0 has no interval functions in the flexible parser at all (fn:... parses as a field named 'fn') [exec], so no release that has the feature is unaffected",
   "affected_versions": "every release with fn: interval functions in the flexible StandardQueryParser, 9.1.0 through 9.12.3 and 10.0.0 through 10.6.0, and main a9779ef3c193 and 645d4fe14a20 (unreleased 11.0); never fixed. [exec] the minimal repro fails 1 of 1 on 10.6.0 with -ea and -da and on main 645d4fe14a20; the four defect files have the same blobs at releases/lucene/10.6.0 as at 645d4fe14a20. [exec] a portable main() probe reports the same 7 misprints, with its control OK, on 18 releases (9.1.0, 9.2.0, 9.3.0, 9.4.2, 9.5.0, 9.6.0, 9.7.0, 9.8.0, 9.9.2, 9.10.0, 9.11.1, 9.12.3, 10.0.0, 10.1.0, 10.2.2, 10.3.2, 10.4.0, 10.5.2) and on main (-ea and -da), byte-identical per-case output; the finder's JUnit fails 4 of 5 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the independent reproduction's JUnit fails 5 of 8 on 9.1.0, 9.12.3 and 10.5.2 (-ea) and on main (-ea and -da). [read] the other 14 releases of the range (9.4.0, 9.4.1, 9.9.0, 9.9.1, 9.11.0, 9.12.0-9.12.2, 10.2.0, 10.2.1, 10.3.0, 10.3.1, 10.5.0, 10.5.1): FuzzyTerm.java, Wildcard.java, AnalyzedText.java and IntervalQueryNode.java have identical blob hashes at all 32 release tags 9.1.0..10.5.2 and on main.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-748.html",
   "repro": "repro/LFV-748/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-975",
   "priority": "low",
   "priority_rank": 730,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / flexible parser node serialization (BoostQueryNode toQueryString/toString)",
   "title": "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",
   "summary": "You parse ab^0.0009 with the flexible StandardSyntaxParser, print the node tree with toQueryString, and expect text that parses back to the same boost, since QueryNode#toQueryString is documented as 'convert to a query string understood by the query parser' and the package documentation says the string 'can be parsed back by the original text parser'. Instead BoostQueryNode prints f:ab^9.0E-4, because its getValueString falls back to Float.toString, which uses E-notation below 0.001 and above 2^63 (ab^10000000000000000000 prints ab^1.0E19). The grammar's NUMBER token has no exponent, so re-parsing the printed text throws ParseException; the same happens to a per-field boost such as setFieldsBoost(Map.of(\"title\", 0.0005f)) in the processed tree (title:lucene^5.0E-4).",
   "impact_class": "minor",
   "introduced_commit": "343992fcbb4b31249f07354014723f18d0508d8a (LUCENE-1567 'New flexible query parser', the original contribution of the flexible query parser, svn trunk r800191, no PR; issue migrated as apache/lucene#2641), which created BoostQueryNode with this getValueString ('if (f == f.longValue()) return \"\" + f.longValue(); else return \"\" + f;'), its toQueryString, and the grammar whose NUMBER token has no exponent; the printer is unchanged since (835de0b44d4, LUCENE-1833, 2009-10-02, new Float -> Float.valueOf, same behaviour; 2cbf261032d, LUCENE-9570, 2021, reformatting) [read]. The symptom changed in 9.0.0 with 3a92e1b93eb (LUCENE-9528 grammar cleanup, apache/lucene#10568, PR apache/lucene-solr#1879), which removed the grammar's Boost lexical state: the printed text no longer re-parses silently into a different query but throws ParseException. That commit is neither a fix nor a regression of the printer; its discussion does not mention exponents or boost printing.",
   "introduced_date": "2009-08-03 (343992fcbb4, author date = commit date; the printer defect); 2020-09-18 (3a92e1b93eb author date; symptom change from silent misparse to ParseException, first released in 9.0.0)",
   "first_affected_version": "2.9.0 [exec] (the first release with the API; 2.4.1 has no flexible query parser and no lucene-queryparser artifact). 2.9.0 to 8.11.4: the re-parse silently builds a different query [exec]; 9.0.0 and later: ParseException [exec].",
   "affected_versions": "every final lucene-queryparser release from 2.9.0 to 10.5.2 (the last release before 10.6.0; 147 releases, 4.0.0-ALPHA/BETA not checked), plus 10.6.0 (branch_10_6 4ae946e5a9b) and main a9779ef3c193; no fixed release. [exec] the finder's JUnit fails 2 of 2 on main (-ea and -da), branch_10_6, 10.5.2, 10.0.0, 9.12.3 and 9.1.0; the independent reproduction's JUnit fails 4 of 5 (its control passes) on main (-ea and -da), 10.5.2 and 9.12.3; the version-portable main() of the version-history runs (public API only, control ab^0.5 round-trips) fails on 2.9.0, 3.6.2, 4.0.0, 7.7.3 and 8.11.4 (silent misparse: f:ab^9.0E-4 re-parses as f:ab^9 f:E-4, f:ab^1.0E19 as f:ab^1 f:E19) and on 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (ParseException). [bytecode] all 147 SHA-1-verified release jars have the same Float.toString fallback in getValueString. [read] the other releases.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-975.html",
   "repro": "repro/LFV-975/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-892",
   "priority": "low",
   "priority_rank": 731,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / flexible parser node serialization (SlopQueryNode and PhraseSlopQueryNode toQueryString/toString)",
   "title": "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)",
   "summary": "You parse \"a b\"~16777217, or the 'any distance' phrase \"a b\"~2147483647, with the flexible StandardSyntaxParser, print the node tree with toQueryString, and expect the same slop back, since QueryNode#toQueryString is documented as 'convert to a query string understood by the query parser' and the package documentation says the string 'can be parsed back by the original text parser'. Instead SlopQueryNode prints ~16777216, and ~2147483648 for the second query, which the same parser rejects with NumberFormatException, because getValueString boxes the int slop into a Float and prints its long value, so every slop above 2^24 is rounded to the nearest float. PhraseSlopQueryNode has the same helper (123456789 prints ~123456792), and toString() of both nodes uses it too.",
   "impact_class": "minor",
   "introduced_commit": "343992fcbb4b31249f07354014723f18d0508d8a (LUCENE-1567 'New flexible query parser', the original contribution of the flexible query parser, svn trunk r800191, no PR; issue migrated as apache/lucene#2641), which added SlopQueryNode and PhraseSlopQueryNode with an int slop and a getValueString() copied from BoostQueryNode, whose value really is a float ('Float f = new Float(this.value); if (f == f.longValue()) return \"\" + f.longValue(); else return \"\" + f;'); 835de0b44d4 (LUCENE-1833, 2009-10-02) only changed new Float to Float.valueOf. [read]. Exposed for parser-built trees by f725b27e12a992f12aab12a8e8bfb9b31125bdae on main / ff9ee28c60354fdb50337192883082192c8e494c on branch_9x (LUCENE-10223 'interval support in standard syntax parser', PR #429, first released in 9.1.0), which changed the grammar's slop action from '(int) Float.parseFloat(slop.image)' to 'parseInt(slop)', so the parser started to keep the exact int and the old printer became visible for parsed queries; the PR, its comments and the CHANGES entry do not mention the slop [exec]. Not a regression of the printer, which never changed.",
   "introduced_date": "2009-08-03 (343992fcbb4, author date = commit date; the printer defect); 2021-11-11 (f725b27e12a / ff9ee28c603 author date; the exposure for parser-built trees)",
   "first_affected_version": "2.9.0 [exec] for hand-built SlopQueryNode/PhraseSlopQueryNode (the first release with the API; 2.4.1 has no flexible query parser and no lucene-queryparser artifact). 9.1.0 [exec] for parser-built trees: a parsed slop above 2^24 prints a different number and ~2147483647 prints the unparseable ~2147483648 (2.9.0 to 9.0.0 round-trip parsed trees [exec], because their grammar itself rounded the slop through a float before storing it).",
   "affected_versions": "every release from 2.9.0 to 10.5.2 (the last release before 10.6.0), plus branch_10_6 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193; no fixed release. [exec] a version-portable main() probe (public API only) prints the same 4 wrong hand-built slops in every executed version (16777217 -> 16777216, 20000001 -> 20000000, 2147483647 -> 2147483648, PhraseSlopQueryNode 123456789 -> 123456792), with its 7 controls passing, on 2.9.0, 3.6.2, 4.0.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2, branch_10_6 and main (-ea; 9.1.0 parser group and main also -da); its 2 parser round-trip checks fail from 9.1.0 on (9.1.0, 9.12.3, 10.0.0, 10.5.2, branch_10_6, main) and pass on 2.9.0, 3.6.2, 4.0.0, 8.11.4 and 9.0.0; the finder's JUnit fails 3 of 3 on 9.1.0, 9.12.3, 10.0.0, 10.5.2, branch_10_6 and main (-ea and -da), and on 9.0.0 (one test at its parse-side precondition); the independent reproduction's JUnit fails 6 of 7 on main (-ea and -da), 10.5.2 and 9.12.3 and 5 of 7 on 9.0.0. [read] the other releases (same printer in all of them, same parse action within each era).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-892.html",
   "repro": "repro/LFV-892/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-610",
   "priority": "low",
   "priority_rank": 732,
   "novelty": "new",
   "withheld": false,
   "area": "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)",
   "title": "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]\")",
   "summary": "You parse an ordinary date range such as [1990 TO 1999] with DateRangePrefixTree.parseShape and print it, expecting a string that parseShape reads back as the same range, as NRShape#toString promises ('The result should be parseable by parseShape(String)'). Instead it prints \"[1990 TO 1000]\", which parseShape rejects with IllegalArgumentException 'Wrong order', and [* TO 1999-12-31] prints as \"[* TO 1000]\" ([1990 TO 2999] as \"[1990 TO 2000]\"), which parses without error to a range that ends up to 999 years early. Range normalization turns an end of 1999 into the thousand-year cell 1000-1999 (an end of 2 BC into a million-year cell), and the per-cell printer writes a cell as its FIRST year, which is right for a range start but wrong for a range end; searches are unaffected, only the text is wrong.",
   "impact_class": "minor",
   "introduced_commit": "bb267a143e009f7b1375f7fa9755b76fcc82ec4f (trunk, svn r1600555, 'LUCENE-5648: DateRangePrefixTree and NumberRangePrefixTreeStrategy', author GitHub dsmiley); branch_5x got it through the bulk backport 55594bad9b07 (LUCENE-5944, 2014-09-18). No PR (svn era; JIRA LUCENE-5648, now GitHub issue #6710). The defect is in the first version of the code, not a regression: toRangeShape already truncated trailing max values of the end, the range toString already printed both ends with the per-cell printer, and that printer already wrote a level-1/2 cell as its block's first year [read]. Later commits kept the behaviour: 29c90c668cb (LUCENE-6092, #7154) restructured the normalization, 0ddb7567f1c (2014-12-14) renamed the types and added the NRShape#toString javadoc, 2cbf261032d (2021) reformatted",
   "introduced_date": "2014-06-05 (trunk commit); 2014-09-18 (branch_5x backport)",
   "first_affected_version": "5.0.0 [exec] (first release with the API); 4.10.4 and earlier have no DateRangePrefixTree or NumberRangePrefixTree [exec]",
   "affected_versions": "Every release from 5.0.0 through 10.6.0 (10.6.0 by reading) and main a9779ef3c193, never fixed. [exec] the follow-up's version-neutral main() probe breaks 4 of 4 defect cases ([1990 TO 1999], [* TO 1999-12-31], [2014 TO 2999], [-9999 TO -1]) and 0 of 3 controls on 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main, and on commits bb267a143e0, af748a9254e and 29c90c668cb (shadowed over the 5.0.0 jars); the finder's JUnit fails on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the independent reproduction's JUnit fails 5 of 7 on main (-ea and -da), 10.5.2 (-ea and -da) and 9.12.3, and its probe fails on 8.11.4, 6.0.0 and 5.0.0. [read] releases between the executed points by git blame (no behaviour change to NumberRangePrefixTree.java:117-166, 399-406 or DateRangePrefixTree.java:349-383); upstream main a95c754ee003 (2026-10-26) has only mechanical commits on both files since then (latest 2026-06-14, typo checks), and branch_10x, branch_10_6 and branch_9_12 last changed NumberRangePrefixTree.java in 2023-12 (#12880, redundant modifiers), so 10.6.0 (released 2026-10-29) and the unreleased 11.0 line are affected (not executed). Not executed: x86 (pure Java string logic). JDK 25.0.3, aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-610.html",
   "repro": "repro/LFV-610/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-132",
   "priority": "low",
   "priority_rank": 733,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / StandardTokenizer and UAX29URLEmailTokenizer (JFlex no-buffer-expansion scanner)",
   "title": "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",
   "summary": "You set maxTokenLength to 1 on StandardTokenizer (or StandardAnalyzer, UAX29URLEmailTokenizer, or a factory with maxTokenLength=1) and tokenize text that contains a code point above U+FFFF, for example 'ab U+10400 cd' or 'hello U+1F600 world'. You expect what the setter documents, that too-long tokens are chopped and emitted as multiple tokens, so the words after that character are still tokenized and end() reports the input length as the final offset. Instead the 1-char scan buffer cannot hold the surrogate pair, the scanner's refill reports end of input at a token start, and the stream stops: [a, b] with final offset 3 of 8, [h, e, l, l, o], and nothing after the character is indexed.",
   "impact_class": "silent wrong results",
   "introduced_commit": "acf9242850739874c1f30ad7daf262081dac900f (LUCENE-5897 / LUCENE-5400, svn r1619730, trunk, the line of 6.0 and today's main), merged the same day to branch_4x as 86dcbcebf2b434df21f42d55a4672eaa90f88b12 (5.x) and to lucene_solr_4_10 as 33204ddd895a26a56c1edd92594800ef285f0d4a (the line released as 4.10.0); no pull request (svn era) [exec]; it needed the zzFinalHighSurrogate hold-back of LUCENE-5770 (JFlex 1.6, b2071884216c, same 4.10.0 release), which alone is harmless",
   "introduced_date": "2014-08-22 (LUCENE-5897 committed to trunk, branch_4x and lucene_solr_4_10 the same day)",
   "first_affected_version": "4.10.0 [exec]",
   "affected_versions": "4.10.0 through 10.5.2 (112 releases), 10.6.0 (by reading) and main ea57360912ed: the follow-up's history probe fails on 4.10.0, 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.6.0, 7.7.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main with -ea, and on 4.10.0, 9.12.3, 10.5.2 and main also with -da; the canonical JUnit repro fails on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main; the independent reproduction's repro on 10.5.2 (-ea, -da), 9.12.3 and main; the finder's main() on 8.11.4, 7.7.3, 6.6.6 and 5.5.5 [exec]; the other releases from a code scan of all 103 release tags 4.10.0..10.5.2 in the history clone (both the eof branch and the setBufferSize call present, no earlier tag has the branch) and git tag --contains [read]; 8.8.2 and 8.9.0-8.11.3 have no tag in the history clone and are inferred from the scan through 8.8.1 and the executed 8.11.4 failure [read]; unaffected: every release before 4.10.0, and 4.9.1 (a different LUCENE-5897 backport onto JFlex 1.5.1 code without the hold-back), executed on 4.0.0, 4.9.0 and 4.9.1 (-ea and -da); main, branch_10x, branch_10_6 and branch_9_12 still carry both early returns [read], so 10.6.0 (released 2026-10-29) is affected",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-132.html",
   "repro": "repro/LFV-132/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-289",
   "priority": "low",
   "priority_rank": 734,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / HTMLStripCharFilter (JFlex grammar, numeric character references; also the 'htmlStrip' char filter SPI)",
   "title": "HTMLStripCharFilter leaves hexadecimal character references with six hex digits (&#x10FFFD; &#x100000; the zero-padded &#x0000E9) undecoded, because its length check counts the leading 'x' and so lets only five hex digits through",
   "summary": "You run HTML through HTMLStripCharFilter and expect every numeric character reference up to U+10FFFF to be decoded, as the scanner's own comment says ('10FFFF: max 6 hex chars') and as its decimal branch does for &#1114111; and the zero-padded &#0000233;. Instead a hex reference with six hex digits, such as &#x10FFFD; &#x100000; or &#x0000E9; stays in the output as literal text: the length that is checked includes the leading 'x', so only five hex digits pass. Through StandardTokenizer, 'b&#x000061;d' is indexed as the tokens b, x000061 and d, and a TermQuery for 'bad' does not find the document.",
   "impact_class": "minor",
   "introduced_commit": "f3a363708ff95f28b5f29fe2cc27c1cd9fd0fca9 (trunk, svn r1234452; LUCENE-3690 / GitHub #4764 'JFlex-based HTMLStripCharFilter replacement', by sarowe; pre-GitHub, a JIRA patch, no PR) and its branch_3x backport d387ae60fcf7ecb65596b756a0f8fc79923d0370 (svn r1235308), which shipped in 3.6.0; the commit wrote the hex rule, the 'matchLength <= 6' check and its comment together [read]",
   "introduced_date": "2012-01-22 (trunk commit f3a363708ff); 2012-01-24 (branch_3x backport d387ae60fcf)",
   "first_affected_version": "3.6.0 [exec] (via the branch_3x backport; 3.5.0, the last release before, has no Lucene HTMLStripCharFilter [exec]); on the 4.x line 4.0.0-alpha [read], first GA release 4.0.0 [exec]",
   "affected_versions": "every release from 3.6.0 to 10.5.2 (the last release before 10.6.0) and main ea57360912ed: 3.6.0, 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main with -ea and -da [exec]; main, 10.5.2 and 9.12.3 also [exec], and 8.11.4 [exec]; the buggy line is present at all 126 release tags that contain HTMLStripCharFilter.jflex [read]; 4.0.0-alpha and 4.0.0-beta were not executed (the harness takes x.y.z versions only) but contain the line [read]; not fixed upstream: apache/lucene main, branch_10x and branch_10_5 still have the check (read 2026-10-26; the last commit to the .jflex, 02014a6245d of 2026-03-03, does not touch it) and no open PR touches HTMLStripCharFilter.java or .jflex. Context: the replaced Solr class (org.apache.solr.analysis.HTMLStripCharFilter, Solr 3.5.0) decoded the zero-padded &#x0000e9; [exec], so for zero-padded BMP references the 2012 rewrite was a regression; six-digit supplementary references were never decoded correctly by either implementation (the Solr class returned them from read() as one int above 0xFFFF)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-289.html",
   "repro": "repro/LFV-289/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1202",
   "priority": "low",
   "priority_rank": 735,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / StandardTokenizer (JFlex scanner buffer resize: StandardTokenizer.setMaxTokenLength, StandardTokenizerImpl.setBufferSize)",
   "title": "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)",
   "summary": "You tokenize 'hello' with a StandardTokenizer, read its only token, and then call setMaxTokenLength(2), a value inside the documented range [1, 1M], which the setter accepts. You expect the next incrementToken() to return false, because no input is left (it does without the call, or when the length is raised). Instead it throws ArrayIndexOutOfBoundsException 'arraycopy: last source index 5 out of bounds for char[2]' from StandardTokenizerImpl.zzRefill: the setter also resizes the scanner's buffer, and setBufferSize copies only min(old, new) chars but keeps the scanner's read positions, which now point past the end of the smaller buffer.",
   "impact_class": "minor",
   "introduced_commit": "acf9242850739874c1f30ad7daf262081dac900f (trunk, svn r1619730, 'LUCENE-5897, LUCENE-5400: JFlex-based tokenizers StandardTokenizer and UAX29URLEmailTokenizer tokenize extremely slowly ...' by Steven Rowe (sarowe)), which made StandardTokenizer.setMaxTokenLength, until then a plain field assignment, call the new StandardTokenizerImpl.setBufferSize, and gave UAX29URLEmailTokenizer the same pair; merged as 86dcbcebf2b (branch_4x), 33204ddd895 (lucene_solr_4_10, shipped in 4.10.0) and 690e43b5cae (lucene_solr_4_9, shipped in 4.9.1); issues LUCENE-5897 = #6959 and LUCENE-5400 = #6463 (JIRA era, no pull request; the discussion never mentions a call during a stream) [exec]",
   "introduced_date": "2014-08-22 (author date = commit date of acf92428507, 86dcbcebf2b and 33204ddd895; the 4.9.1 merge 690e43b5cae is 2014-09-17); first release 4.10.0 (release tag commit 2014-09-02)",
   "first_affected_version": "4.10.0 [exec] (the later 4.9.1 bugfix release, tag commit 2014-09-21, received the same change and fails too [exec]; 4.0.0 to 4.9.0 pass [exec])",
   "affected_versions": "4.9.1 and every release from 4.10.0 through 10.6.0 (4ae946e5a9b): 114 releases, each executed with the same steps (the one-test repro unchanged on 9.1.0 and later, the same steps adapted to the older APIs before that) and each failing with the same ArrayIndexOutOfBoundsException at StandardTokenizerImpl.zzRefill; main 5adff78bb168 with -ea and -da [exec]. Not affected: 4.0.0 to 4.9.0 (17 releases executed, all pass) [exec]. UAX29URLEmailTokenizer (analysis-common), which got the identical setter and setBufferSize in the same commit, fails the same way on main [exec]; ClassicTokenizer, whose setter only assigns the field, is not affected [exec]. Not fixed upstream: upstream main 1c2072f02843 (author date 2026-11-02) has no change to StandardTokenizer.java after #16063 (author date 2026-05-15) or to StandardTokenizerImpl.java after #15393 (2025-11-03) [read]. Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1202.html",
   "repro": "repro/LFV-1202/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-120",
   "priority": "low",
   "priority_rank": 736,
   "novelty": "known",
   "withheld": false,
   "area": "index / SegmentInfos commit read (forward version check)",
   "title": "Opening an index created by a newer Lucene major throws IllegalArgumentException ('indexCreatedVersionMajor is in the future') instead of IndexFormatTooNewException",
   "summary": "You open, with an older Lucene, an index that a newer Lucene major created, for example Lucene 9.12.3 opening an untouched index written by 10.5.2 with DirectoryReader.open or new IndexWriter. You expect IndexFormatTooNewException, whose javadoc says it 'is thrown when Lucene detects an index that is newer than this Lucene version', which is what you get when the newer release also bumped the segments_N format number. Instead SegmentInfos.readCommit hands the on-disk created major to the public SegmentInfos(int) constructor, whose argument check throws an unchecked IllegalArgumentException 'indexCreatedVersionMajor is in the future: 10', with a suppressed CorruptIndexException that says 'checksum passed ... possibly transient resource issue, or a Lucene or JVM bug'.",
   "impact_class": "wrong error",
   "introduced_commit": "23b002a0fdf2 (LUCENE-7756 'Only record the major Lucene version that created the index, and record the minimum Lucene version that contributed to segments', by jpountz; JIRA patch era, no GitHub PR; migrated issue apache/lucene#8807; fix version 7.0; the history also has fd9689cb36a with the same message and date, contained only in 8.0.0) added the SegmentInfos(int) check 'indexCreatedVersionMajor is in the future', which readCommit reaches with the on-disk created major [read]; precursor d9c0f2599d93 (LUCENE-7703, apache/lucene#8754, 2017-02-22) added the created-version field and the readCommit call new SegmentInfos(indexCreatedVersion) without a future check and was never released in that form; the suppressed 'checksum passed' note dates from LUCENE-9359 (lucene-solr#1483, 8.6.0), which made readCommit always call checkFooter [exec]",
   "introduced_date": "2017-03-30 (23b002a0fdf2, LUCENE-7756); precursor 2017-02-22 (d9c0f2599d93, LUCENE-7703)",
   "first_affected_version": "7.0.0 [exec]; first release reachable with a stock index written by the next major: 7.4.0 opening 8.0.0 [exec]",
   "affected_versions": "every release from 7.0.0 through 10.5.2 (the last release before 10.6.0) and main ea57360912ed [read]; synthesized next-major commit [exec]: 7.0.0, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main, and the JUnit repro on 9.12.3, 10.0.0, 10.5.2 and main; stock indexes written by the next major, no byte edits [exec]: 7.4.0 and 7.7.3 opening 8.0.0, 8.6.0 opening 9.0.0, 8.11.4 opening 9.12.3, 9.0.0 opening 10.0.0, 9.12.3 opening 10.5.2; masked by a segments_N format bump, correct IndexFormatTooNewException [exec]: 7.0.0 and 7.3.1 opening 8.0.0, 8.5.2 opening 9.0.0, 10.0.0 and 10.5.2 opening a main index (main writes VERSION_10_6 = 11, #16418); 10.6.x opening 11.0 takes the same path if 11.0 keeps segments format 11 [read]; not affected: 6.6.6 and older [exec]; not fixed upstream: main, branch_10x, branch_10_6 and branch_9_12 unchanged on 2026-10-26 [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/12872",
    "https://github.com/apache/lucene/issues/16571",
    "https://github.com/apache/lucene/issues/16847",
    "https://github.com/apache/lucene/issues/7014",
    "https://issues.apache.org/jira/browse/LUCENE-5952",
    "https://github.com/apache/lucene/issues/7016"
   ],
   "doc": "",
   "repro": "repro/LFV-120/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1095",
   "priority": "low",
   "priority_rank": 737,
   "novelty": "known",
   "withheld": false,
   "area": "index / DirectoryReader.listCommits (commit enumeration)",
   "title": "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)",
   "summary": "You call DirectoryReader.listCommits while an older commit is being deleted (a snapshot is released and the application commits, or a concurrent commit under the default policy) and expect the existing commits, since its javadoc says a commit in progress may or may not be returned. Instead it throws CorruptIndexException: readCommit wraps the NoSuchFileException of the deleted commit's .si file into a corruption exception, which listCommits does not catch.",
   "impact_class": "crash",
   "introduced_commit": "LUCENE-7662 (6.5.0) made readCommit wrap missing files into CorruptIndexException, which bypasses listCommits' LUCENE-948 catch [read]",
   "introduced_date": "2017 (LUCENE-7662, 6.5.0) [read]",
   "first_affected_version": "6.5.0 [exec] (6.4.2 passes [exec])",
   "affected_versions": "6.5.0, 7.7.3, 8.11.4, 9.12.3 [exec]; 10.5.2, 10.6.0, main 645d4fe14a20 [exec]; main e1faeba08bde with -ea and -da [exec].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/8894",
    "https://issues.apache.org/jira/browse/LUCENE-7843"
   ],
   "doc": "",
   "repro": "repro/LFV-1095/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-152",
   "priority": "low",
   "priority_rank": 738,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter open from a reader commit (version gate)",
   "title": "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",
   "summary": "You have an index that Lucene 8.x created and 9.x then fully re-indexed in place, so every segment is 9.x; since GITHUB#14607 (released in 10.4.0) Lucene 10.x and main open it normally for reading and with an IndexWriter in APPEND mode. You expect new IndexWriter(dir, new IndexWriterConfig().setIndexCommit(reader.getIndexCommit())), which the setIndexCommit javadoc documents for near-real-time readers, to open it as well. Instead it throws IllegalArgumentException 'createdVersionMajor must be >= 9, got: 8', because this one constructor branch still checks the index's creation major, the rule #14607 replaced on every other open path with a check of each segment's version.",
   "impact_class": "crash",
   "introduced_commit": "fe59fdec5c5 (apache/lucene#15431, the branch_10x backport of #14607 'Revise strategy for opening an index for reading', by rahulgoswami, merged by msokolov) for the releases, and dd70ed5801e (#14607) on main: both moved the read gate in SegmentInfos from the created major to each segment's minVersion and did not touch IndexWriter.java; the check that became stale is c1ae6dc07c9 (LUCENE-9669, apache/lucene-solr#2212, by s1monw, first released in 9.0.0), which matched every other open path until then [exec]",
   "introduced_date": "2025-11-25 (fe59fdec5c5, branch_10x); 2025-11-17 on main (dd70ed5801e; a first push 3bf1011a4e2 on 2025-10-27 was reverted the same day); the stale check dates from 2021-01-19 (c1ae6dc07c9)",
   "first_affected_version": "10.4.0 [exec]",
   "affected_versions": "10.4.0, 10.5.0, 10.5.1, 10.5.2 (the last release before 10.6.0) and main ea57360912ed (also with -da) [exec]; not affected [exec]: 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1 and 10.3.2 (consistent gates); not affected [read]: 9.0.0-9.12.2 (same gates as 9.12.3) and releases before 9.0.0 (no such check); main between 2025-11-17 and 2026-10-15, when its MIN_SUPPORTED_MAJOR was 10, was affected for created major 9 with all segments 10.x or newer [read]; branch_10x and branch_10_6 (10.6.0, released 2026-10-29): the check is unchanged, likely affected [read]; not fixed upstream: main head ea57360912ed and branch_10x still carry the check and no open PR touches it [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/14607",
    "https://github.com/apache/lucene/issues/16741",
    "https://github.com/apache/lucene/issues/15431",
    "https://github.com/apache/lucene/issues/15454",
    "https://github.com/apache/lucene/issues/15012",
    "https://github.com/apache/lucene/issues/15374"
   ],
   "doc": "",
   "repro": "repro/LFV-152/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-131",
   "priority": "low",
   "priority_rank": 739,
   "novelty": "new",
   "withheld": false,
   "area": "index / DirectoryReader reopen and isCurrent (expert old-index open)",
   "title": "A DirectoryReader opened with open(commit, minSupportedMajorVersion, leafSorter) forgets that minimum: isCurrent(), openIfChanged() and SearcherManager.maybeRefresh() throw IndexFormatTooOldException even on an unchanged index",
   "summary": "You open an index whose segments come from an older Lucene major, which the default open refuses, through the expert DirectoryReader.open(commit, minSupportedMajorVersion, leafSorter) with a lower minimum, and it opens fine. With nothing committed since, you expect isCurrent() to return true and openIfChanged(reader) to return null, so that SearcherManager.maybeRefresh() does nothing. Instead all three throw IndexFormatTooOldException ('Index has segments derived from Lucene version 8.x and is not supported ...'), because the reader does not keep the minimum it was opened with and re-reads the commit with the default Version.MIN_SUPPORTED_MAJOR.",
   "impact_class": "crash",
   "introduced_commit": "c1ae6dc07c9a (LUCENE-9669 'Add an expert API to allow opening indices created < N-1', apache/lucene-solr#2212 by s1monw, approved by jpountz and mikemccand; issue apache/lucene#10708) added the per-reader minimum to the initial open only and did not store it on the reader; the default-minimum re-reads in isCurrent() and doOpenFromCommit() predate it (c4bf601b68f, LUCENE-5969, 2014-10-22) [read]",
   "introduced_date": "2021-01-19 (c1ae6dc07c9, LUCENE-9669)",
   "first_affected_version": "9.0.0 [exec]",
   "affected_versions": "every release from 9.0.0 through 10.5.2 (the last release before 10.6.0; 33 release tags), 10.6.0 (by reading) and main ea57360912ed; executed and reproduced [exec]: commit c1ae6dc07c9, 9.0.0, 9.8.0, 9.12.3, 10.0.0, 10.3.2, 10.4.0, 10.5.2 and main (also with -da on c1ae6dc07c9, 9.0.0, 10.5.2 and main); real, unmodified back-compat fixtures [exec]: 7.7.3 on 9.0.0 and 9.12.3, 8.11.4 on 10.0.0 and 10.5.2, and an index the stock 9.12.3 IndexUpgrader produced from the 8.11.4 fixture on main, 10.5.2, 10.4.0 and 10.3.2; the releases in between carry the same two default-minimum calls and no stored minimum [read]; the gate rewrite #14607 (10.4.0) changed only the message; not affected: 8.x and older, which have no such API [exec]; not fixed upstream: main, branch_10x, branch_10_6 and branch_9_12 unchanged on 2026-10-26 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-131.html",
   "repro": "repro/LFV-131/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-202",
   "priority": "low",
   "priority_rank": 740,
   "novelty": "new",
   "withheld": false,
   "area": "search / IndexSearcher slicing (LeafSlice, LeafReaderContextPartition)",
   "title": "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)",
   "summary": "You build an IndexSearcher over a reader that contains an empty leaf, for example new ParallelLeafReader() with no sub-readers, possibly next to a real index inside a MultiReader, and you expect searches to work and simply find no hits in the empty part, as they do on 9.12.3. Instead the searcher throws IllegalArgumentException 'minDocId is greater than than maxDoc: [0] > [0]', because slicing wraps every leaf in a whole-segment partition that starts at doc 0 and the partition constructor rejects a start that is not below the leaf's maxDoc(). In the repro, a MultiReader of a 5-doc index plus an empty ParallelLeafReader cannot be searched at all instead of returning 5 hits.",
   "impact_class": "crash",
   "introduced_commit": "fafd6af004e0 on main: #13542 'Add support for intra-segment search concurrency' by javanna (merged 2024-09-10, closes #9721); it added LeafReaderContextPartition with three constructor checks, among them 'minDocId >= leafReaderContext.reader().maxDoc() -> IllegalArgumentException' (added after a review request by jpountz), and createForEntireSegment, which always passes minDocId 0 and maxDocId NO_MORE_DOCS [exec]; #13893 (main a888af76b2f, 10.1.0) and #14343 (main bdf4deff313, 10.2.0) later moved where the no-executor searcher throws (into the constructor), not the defect [exec]",
   "introduced_date": "2024-09-10 (#13542, authored and committed on main); first release 10.0.0 (tag commit eadc07cc6a1, 2024-10-09)",
   "first_affected_version": "10.0.0 [exec]; 9.12.3 and every 9.x release from 9.1.0 are not affected [exec] (branch_9x never received #13542; 9.12.x shipped after the merge from branch_9x)",
   "affected_versions": "all 12 releases from 10.0.0 to 10.5.2 (10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2) and main ea57360912ed through 645d4fe14a2 (2026-10-29) [exec]: the finder's JUnit fails 2 of 3 on each with -ea, and with -da on 10.0.0, 10.5.2 and main; the executor/static-slices test fails 4 of 4 on 10.0.0, 10.5.2 and main. Not affected [exec]: all 20 releases from 9.1.0 to 9.12.3 (3 of 3 pass; -da too on 9.12.3; the executor/static test's pre-#13542 variant passes 4 of 4 on 9.12.3) and the parent commit 942065cc3e7. Releases before 9.1.0 were not run (the test framework package differs); the failing check does not exist there [read]. [read] the check is unchanged on main 645d4fe14a2, branch_10x 657014b3c57 (IndexSearcher.java:1093) and branch_10_6 4ae946e5a9b (10.6.0 RC1), and 10.6.0 (released 2026-10-29) shipped with it: the minimal test fails on its release jars (4ae946e5a9b9) with -ea [exec]. Where it throws: on 10.0.0 and fafd6af004e the no-executor constructor succeeds and the first count()/search() throws; from 10.1.0 the constructor itself throws; with an executor it throws lazily from getSlices() in every affected version; the public static slices(leaves, ..., allowSegmentPartitions) throws for false and true. Not executed: x86; the history runs used JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-202.html",
   "repro": "repro/LFV-202/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1215",
   "priority": "low",
   "priority_rank": 741,
   "novelty": "new",
   "withheld": false,
   "area": "core / util (DocIdSetBuilder sparse build; reached from facet / FacetsCollector)",
   "title": "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)",
   "summary": "You create a DocIdSetBuilder for an empty doc-ID range (new DocIdSetBuilder(0), which FacetsCollector does for every leaf as new DocIdSetBuilder(context.reader().maxDoc())), add nothing and call build(), and expect the empty set, as the same class already returns for maxDoc 0 on its dense path and for every maxDoc >= 1. Instead build() throws IllegalArgumentException 'maxValue must be non-negative (got: -1)', because its sparse branch always computes the radix sort width as PackedInts.bitsRequired(maxDoc - 1) = bitsRequired(-1), even though there is nothing to sort. So faceting over a reader that contains a zero-document leaf (for example an empty ParallelLeafReader) fails instead of counting the other leaves; Lucene 6.0.x returned the empty set.",
   "impact_class": "minor",
   "introduced_commit": "ef45d4b2e1f9c967b62340acb027f50888a00ba2 (master, Adrien Grand, LUCENE-7261 'Speed up LSBRadixSorter', migrated as apache/lucene#8316; pre-GitHub-PR era, patch on JIRA) and its branch_6x copy 8ca6f6651ede19bfaee9051e9b87927685cb9be0 (same author date, the copy that shipped first, in 6.1.0): it replaced sorter.sort(buffer, 0, bufferSize) with sorter.sort(PackedInts.bitsRequired(maxDoc - 1), buffer, bufferSize) in DocIdSetBuilder.build() [read] [exec]",
   "introduced_date": "2016-04-28 (author date 2016-04-28T18:20:41+02:00 on both master and branch_6x)",
   "first_affected_version": "6.1.0 [exec] (tagged 2016-06-12; contains 8ca6f6651ed; CHANGES.txt lists LUCENE-7261 under 6.1.0 Optimizations); on the master line the first release is 7.0.0. Not a new API: DocIdSetBuilder(int) and build() exist since 5.3.0 (LUCENE-6645) and returned the empty set for maxDoc 0 in 5.3.0 through 6.0.1 [exec].",
   "affected_versions": "Every release from 6.1.0 through 10.6.0 (4ae946e5a9b, released 2026-10-29) and main 5adff78bb168 (12.0.0-SNAPSHOT); not fixed upstream (upstream main still has the line at DocIdSetBuilder.java:322, checked 2026-11-03). [exec] fail: 6.1.0 (-ea, -da), 6.6.6, 7.0.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2, 10.6.0 (-ea, -da) and main (-ea, -da) (the history sweep ran a main() form of the same steps on the older releases and the JUnit repro on 9.12.3, 10.0.0, 10.6.0 and main; 10.5.2 by the independent reproduction's own test); [read] all release tags from 6.1.0 on contain the commit. Not affected [exec]: 5.3.0, 5.5.5, 6.0.0, 6.0.1 (empty set); no release before 5.3.0 has DocIdSetBuilder. Public IndexSearcher route [exec]: 9.12.3 fails through IndexSearcher.search(MatchAllDocsQuery, FacetsCollectorManager) over MultiReader(2-doc index, new ParallelLeafReader()); 10.6.0 and main stop earlier with LFV-202's IllegalArgumentException. Not new in 10.6 (10.5.2 and older releases fail). All runs used JDK 25.0.3 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1215.html",
   "repro": "repro/LFV-1215/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-625",
   "priority": "low",
   "priority_rank": 742,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexFileDeleter start-up (inflateGens) with FSDirectory pending deletions",
   "title": "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)",
   "summary": "You keep a file of your own in the index directory (or let PersistentSnapshotDeletionPolicy store its snapshots_N files there, which its javadoc allows), delete it through Lucene's FSDirectory while another process still has it open, and then open a new IndexWriter on the same Directory object; you expect the writer to open, because Lucene leaves non-index files alone and since 7.4.0 no longer refuses to start while deletes are pending. Instead the IndexWriter constructor throws: IndexFileDeleter passes every pending deletion, unfiltered, to inflateGens, which treats any name that does not start with segments or pending_segments as a segment file, so with -ea it fails the assertion 'wtf? file=snapshots_0' (or 'wtf? file=app-notes.txt'), and with -da app-notes.txt gives NumberFormatException 'For input string: \"pp-notes\" under radix 36'. With -da the snapshots_0 case opens, but the writer names its next segment _napshott: the segment counter jumps to 1 + Long.parseLong(\"napshots\", 36), which is cosmetic.",
   "impact_class": "crash",
   "introduced_commit": "585952797cfe715aefa29380f08eb93a25acc55e on master (first released in 8.0.0) and its branch_7x backport b4239ed51f3552b74b30c9b2cb70cf6a09161a69 (first released in 7.4.0), both 'LUCENE-8310: Ensure IndexFileDeleter accounts for pending deletes' by Simon Willnauer (s1monw); JIRA LUCENE-8310 'Relax IWs check on pending deletes' = apache/lucene#9357 (JIRA-era patch, no pull request). The commit replaced inflateGens(segmentInfos, refCounts.keySet(), infoStream) with refCounts' key set plus directoryOrig.getPendingDeletions(), added with no filter (IndexFileDeleter.java:211-217, the same lines on main a9779ef3c193), and removed IndexWriter's 'still has pending deleted files; cannot initialize IndexWriter' refusal [read]. Commit-level A/B [exec]: at each parent (branch_7x 0f9e221ed45, master 25ebe0e35fb) the writer refuses every pending delete by design; at each LUCENE-8310 commit the index-file control opens and both non-index cases fail. The parser's assumption is older: inflateGens and its 'wtf? file=' assertion came with LUCENE-5904 (7a189a3aca6, first released in 4.10.1), when its input was only the first pass's filtered refCounts set.",
   "introduced_date": "2018-05-15 (author date of both commits); committed 2018-05-16 (master and branch_7x); first release 7.4.0 (tag dated 2018-06-22); master line 8.0.0 (2019-03-13)",
   "first_affected_version": "7.4.0 [exec]. 7.3.1, the last release before, is not affected [exec]: like every release from 6.0.0 to 7.3.1 (all 25 executed) it does not open the writer either, but by design, refusing any pending delete (index file or not) with IllegalArgumentException 'Directory ... still has pending deleted files; cannot initialize IndexWriter' (LUCENE-6835). 5.5.5 has no pending-delete mechanism; the refused delete throws IOException to the caller [exec].",
   "affected_versions": "Every release from 7.4.0 to 10.5.2 and main a9779ef3c193; not fixed. [exec] all 67 releases 7.4.0-10.5.2 with -ea (follow-up history probe: both non-index cases fail with the assertion, the no-pending and pending-segments_1 controls open); -da on 7.4.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main (application-file case NumberFormatException; PSDP case opens with segments [_0, _napshott]). Finder repro also on 10.5.2, 9.12.3, 8.11.4, 7.4.0 (-ea fail 2/2) and 10.5.2, 9.12.3 (-da fail 1/2); the independent reproduction on 10.5.2, 9.12.3, 8.11.4 (-ea and -da). 8.8.2-8.11.4 are not tagged in the local history clone, so for those six the evidence is execution only. [read] upstream main a95c754ee003 (2026-10-26) still adds the pending set unfiltered; no later commit (LUCENE-8150, LUCENE-9570 reformatting, LUCENE-9911, #15105, #12126) changes what reaches inflateGens.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9357",
    "https://issues.apache.org/jira/browse/LUCENE-8310",
    "https://github.com/apache/lucene/issues/7944",
    "https://issues.apache.org/jira/browse/LUCENE-6886",
    "https://github.com/apache/lucene/issues/9781",
    "https://issues.apache.org/jira/browse/LUCENE-8735"
   ],
   "doc": "",
   "repro": "repro/LFV-625/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1205",
   "priority": "low",
   "priority_rank": 743,
   "novelty": "new",
   "withheld": false,
   "area": "search / doc-values range queries, index-sort primary-sort shortcut (SortedSetDocValuesRangeQuery, SortedNumericDocValuesRangeQuery, IndexSortSortedNumericDocValuesRangeQuery, Sort.getPrimarySortField)",
   "title": "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)",
   "summary": "You wrap a segment in a FilterLeafReader whose getMetaData() reports Sort.INDEXORDER (true for any segment, whose documents are in index order) and run SortedDocValuesField.newSlowRangeQuery(\"f\", v2, v5) on a skip-indexed field; you expect the 4 matching documents, as on the unwrapped segment. Instead IndexSearcher.search throws NullPointerException 'Cannot invoke \"String.equals(Object)\" because the return value of \"org.apache.lucene.search.SortField.getField()\" is null': the query's index-sort shortcut asks Sort.getPrimarySortField for the leaf's primary sort field, which returns the DOC sort field (whose field name is null) on purpose, and then calls getField().equals(field) on it instead of skipping the shortcut. The same unguarded call is in SortedNumericDocValuesRangeQuery and IndexSortSortedNumericDocValuesRangeQuery.",
   "impact_class": "minor",
   "introduced_commit": "579427228d4297837c8c1794ddde98af0c9815fd (apache/lucene#13592 'Take advantage of the doc value skipper when it is primary sort', Ignacio Vera, GitHub iverase; reviewed by gsmiller and jpountz) for the SortedSetDocValuesRangeQuery and SortedNumericDocValuesRangeQuery sites: it added the shortcut guarded by indexSort.getSort()[0].getField().equals(field) [read]. #16424 (693a7234bad, Alan Woodward, author date 2026-07-30, in 10.6.0 via a22c06400da) moved the check into canUsePrimarySortShortcut on top of the new Sort.getPrimarySortField, whose null-field branch returns a DOC/SCORE sort field as primary on purpose, and kept the dereference. Older site of the same root cause: IndexSortSortedNumericDocValuesRangeQuery, in core since #12078 (102622842bf on main, f70530e5840 on branch_9x, LuXugang, 2023-01-13), which moved the LUCENE-7714 sandbox query (5bf023cf194, Julie Tibshirani, 2019-05-10, with the same indexSort.getSort()[0].getField().equals(field)) into core and made LongField/IntField.newRangeQuery return it [exec]",
   "introduced_date": "2024-08-22 (579427228d4, author date = commit date; first release 10.0.0); older site 2023-01-13 (#12078; first release 9.5.0)",
   "first_affected_version": "9.5.0 for the row, through the IndexSortSortedNumericDocValuesRangeQuery site that LongField.newRangeQuery returns [exec]; 10.0.0 for the repro's SortedSetDocValuesRangeQuery site and the SortedNumericDocValuesRangeQuery site [exec]",
   "affected_versions": "Repro site (SortedSetDocValuesRangeQuery): every 10.x release, 10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and 10.6.0 (4ae946e5a9b), all executed and failing with the one-test repro (-da; 10.0.0 and 10.6.0 also -ea), and main 5adff78bb168 (12.0.0-SNAPSHOT, -ea and -da) [exec]. SortedNumericDocValuesRangeQuery site: 10.0.0 (earlier inline form of the check), 10.5.2, 10.6.0 and main fail [exec]. IndexSortSortedNumericDocValuesRangeQuery site (auxiliary probe, LongField.newRangeQuery on the same kind of leaf, -da): every release from 9.5.0 to 9.12.3 (14 releases) and from 10.0.0 to 10.6.0 (13 releases), and main, all fail [exec]. Not affected: 9.4.2 and older (no core API) [exec]. Not fixed upstream: upstream main 1c2072f0284 (2026-11-02) differs from 5adff78bb168 only outside lucene/core, and no open PR changes the dereference [read]. Not new in 10.6: #16424 only moved the dereference.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1205.html",
   "repro": "repro/LFV-1205/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1209",
   "priority": "low",
   "priority_rank": 744,
   "novelty": "new",
   "withheld": false,
   "area": "search / kNN vector queries (AbstractKnnVectorQuery optimistic per-leaf top-k)",
   "title": "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)",
   "summary": "You build a reader that holds an empty leaf under an empty parent, such as new MultiReader(new ParallelLeafReader()), wrap it in an executor-backed IndexSearcher and rewrite a KnnFloatVectorQuery(\"v\", {1, 0}, 3) on it, expecting MatchNoDocsQuery: that is what the rewrite returns when nothing matches, and what 10.2.2 returns for the same input. Instead the optimistic per-leaf collector computes the leaf's share of its parent as 0 / 0f = NaN; Math.max(1, NaN) stays NaN and the int cast gives a per-leaf top-k of 0, so the rewrite fails at 'assert perLeafTopK > 0' with -ea, and with -da the heap behind the collector throws IllegalArgumentException 'initialCapacity must be > 0 and < 2147483630; got: 0'.",
   "impact_class": "minor",
   "introduced_commit": "d279af1961f40465a3a9e8ab84848afe69fd8424 (main; squash-merge of apache/lucene#14226 'OptimisticKnnVectorQuery' by Michael Sokolov (msokolov), parent 1e6106ae57b5), backported to branch_10x as 61424c489e65b545f62dd138d45efce1bfafedfb: it replaced the k-sized TopKnnCollectorManager with a per-leaf size computed from leafProportion = leaf maxDoc / parent maxDoc, and added the comment 'if we divided by zero above, leafProportion can be NaN and then this would be 0' followed only by 'assert perLeafTopK > 0' [exec]. The NaN comment and the assert were in the PR's first commit (939889056a, 2025-02-27, then an opt-in class); PR commit 571359aa15 (2025-04-17) made it the default path of every KnnFloatVectorQuery and KnnByteVectorQuery.",
   "introduced_date": "2025-05-05 (author date 2025-05-05T13:59:30-04:00, the merge time on main; branch_10x commit 61424c489e6 has the same author date and was committed 2025-07-17)",
   "first_affected_version": "10.3.0 [exec] (tag commit e2871287e4a, 2025-09-05; fails with -ea and -da); 10.2.2 does not contain 61424c489e6 and passes [exec]",
   "affected_versions": "10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and 10.6.0 (4ae946e5a9b), plus unreleased main 5adff78bb168 (12.0.0-SNAPSHOT) and branch_11x [read]. [exec] fail with -ea and -da: main 5adff78bb168, 10.6.0, 10.5.2 and 10.3.0 (on 10.3.x the -da error comes from LongHeap, 'maxSize must be > 0 and < 2147483630; got: 0', before #15163 switched NeighborQueue to TernaryLongHeap in 10.4.0). [exec] pass (MatchNoDocsQuery): 10.2.2 and 9.12.3. Not fixed upstream: the parent-maxDoc divisor, the comment and the assert are unchanged on upstream main 1c2072f0284 (2026-11-02), branch_11x and branch_10_6, and the newest commit on the file is 4b982fffe24 (#16271, author date 2026-07-09). Not new in 10.6 (10.5.2 and 10.3.0 fail). The regression covers the kNN rewrite path only: ordinary search/count on such readers already fails through LFV-202 since 10.0.0. All runs used JDK 25.0.3 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1209.html",
   "repro": "repro/LFV-1209/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-587",
   "priority": "low",
   "priority_rank": 745,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter merge waiting (close/shutdown waitForMerges, forceMerge, forceMergeDeletes) with NoMergeScheduler",
   "title": "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",
   "summary": "You configure an IndexWriter with NoMergeScheduler, keep the default merge policy, index normally (for example 15 one-document commits) and then call close(), forceMerge(1) or forceMergeDeletes(). You expect close() to commit and return without merging, since the NoMergeScheduler javadoc says it prevents merges 'regardless of the MergePolicy used', and the forced merges to return or fail. Instead each call waits forever: IndexWriter keeps registering the policy's merges as pending, NoMergeScheduler never takes them, and the calls re-check once a second in doWait() until no merge is pending, which never happens.",
   "impact_class": "hang",
   "introduced_commit": "c8c5dfa543184a077ba993cc0fb02515770973d4 'LUCENE-2331: add NoMergePolicy, NoMergeScheduler' (Subversion r926289; issue apache/lucene#3407; patch by @shaie, committed by @mikemccand), which added the public NoMergeScheduler with an empty merge(); IndexWriter's wait loops are older and unchanged since (the waitForMerges loop dates from LUCENE-1703, 629c7ed4c7f, 2009-06-23) [read]",
   "introduced_date": "2010-03-22",
   "first_affected_version": "3.1.0 [exec] (tag releases/lucene-solr/3.1, 2011-03-30, contains c8c5dfa5431; 3.0.3 has no NoMergeScheduler [exec]; a package-private never-merging scheduler hangs 3.0.3 the same way [exec], which shows the wait predates the class but is not a public-API trigger)",
   "affected_versions": "every release from 3.1.0 through 10.5.2 (the last release before 10.6.0) and main a9779ef3c193, never fixed; the previous hunt main ea57360912ed too [read]. [exec] the repro fails at all 13 points run: 3.1.0 and 3.6.2 (main() port with optimize/expungeDeletes), 4.0.0, 4.10.4 and 5.0.0 (JUnitCore ports), 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main (-ea; main also -da), each with the NoMergeScheduler + NoMergePolicy control returning; the independent reproduction's own JUnit also fails on 10.5.2 and 9.12.3 and the intended-behaviour check's natural-flush JUnit on 10.5.2. How the symptom changed (not the defect): in 3.1-4.10.x the public close(false) dropped the pending merges (a workaround); 5.0.0 removed close(boolean) and from then close() commits by default through shutdown() -> waitForMerges(), with setCommitOnClose(false) or rollback() avoiding the wait but losing the commit-on-close; in 4.0.0 an interrupt ends the wait and close() then finishes, from 4.10.4 the interrupt surfaces as ThreadInterruptedException [exec].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/5316",
    "https://issues.apache.org/jira/browse/LUCENE-4246",
    "https://issues.apache.org/jira/browse/LUCENE-5871",
    "https://github.com/apache/lucene/issues/6933",
    "https://github.com/apache/lucene/issues/4446",
    "https://issues.apache.org/jira/browse/LUCENE-3373"
   ],
   "doc": "",
   "repro": "repro/LFV-587/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1153",
   "priority": "low",
   "priority_rank": 746,
   "novelty": "new",
   "withheld": false,
   "area": "index / ConcurrentMergeScheduler merge limits (setMaxMergesAndThreads reset to AUTO_DETECT_MERGES_AND_THREADS, initialize, maybeStall)",
   "title": "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",
   "summary": "You reset the merge limits of the ConcurrentMergeScheduler that an open IndexWriter uses to the documented automatic default with setMaxMergesAndThreads(AUTO_DETECT_MERGES_AND_THREADS, AUTO_DETECT_MERGES_AND_THREADS), a pair the setter accepts. You expect the scheduler to go back to its CPU-based defaults, as it did up to 8.5.2. Instead both limits stay at -1, because only initialize() (run once, when the writer is opened) resolves AUTO, so the next commit, close or forceMerge that registers a merge waits in maybeStall forever, with no error and no merge thread started, until concrete limits are set again (a rollback() from another thread freed a stalled forceMerge, but by reading it cannot free a stalled commit on the merge-on-commit path or a stalled close()).",
   "impact_class": "hang",
   "introduced_commit": "d7e0b906abcbc43d3737224cadcda7d2c795ccb0 on main and 9598d43bb629b0434e7ce557fe12ea88c19a5d00 on branch_8x, the same change: LUCENE-9345 'Separate MergeSchedulder from IndexWriter' (apache/lucene-solr#1451, migrated issue #10385) by Simon Willnauer [read]. Before it, merge() resolved AUTO on every call (5.0.0 to 8.5.2). A commit-level bisect inside 8.5.2..8.6.0 was not executed; by reading, of the three ConcurrentMergeScheduler commits in that range only 9598d43bb62 removes initDynamicDefaults from merge().",
   "introduced_date": "2020-04-24 (author and committer date of d7e0b906abc and 9598d43bb62; PR merged 2020-04-24); first release 8.6.0",
   "first_affected_version": "8.6.0 [exec]; 8.5.2 not affected [exec]; the constant exists since 5.0.0 (LUCENE-5951), so 5.0.0 to 8.5.2 resolve the reset at the next merge [read]",
   "affected_versions": "Every release from 8.6.0 (2020) through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT); never fixed. [exec] the finder's one-test commit-path JUnit fails on main (-ea and -da), 10.6.0 (-ea and -da) and 9.12.3 (-ea), and the one-test forceMerge repro on main (-ea and -da) and the 10.6.0 jars (-ea, the fact check); a version-neutral main() variant fails on 8.6.0, 8.11.4, 9.0.0 and 9.12.3 (-da) and passes on 7.7.3 and 8.5.2; the independent reproduction's own test fails on main (-ea and -da), 10.6.0, 10.5.2 and 9.12.3 (-da); the intended-behaviour check's own test fails on main (-ea and -da) and 10.6.0 (-da); re-run on main 2026-11-02 fails with -ea and -da. The releases between the executed ones were not run one by one; by reading, no commit after d7e0b906abc resolves AUTO outside initialize(). Not new in 10.6 (10.5.2 and every executed release from 8.6.0 fail). Not fixed upstream: no commit has touched ConcurrentMergeScheduler.java since 54283150a81 (author date 2026-06-14, typos), and the only open PR on the file updated in the last 48 h (#16889) does not resolve AUTO.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1153.html",
   "repro": "repro/LFV-1153/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1001",
   "priority": "low",
   "priority_rank": 747,
   "novelty": "new",
   "withheld": false,
   "area": "search / query cache (LRUQueryCache.cleanUp() locking vs the statistics callbacks)",
   "title": "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",
   "summary": "You subclass LRUQueryCache to keep your own statistics in the callbacks its javadoc offers (onHit, onMiss, onCacheEntryInserted, onCacheEntryEvicted) and make them thread-safe the plain Java way, with synchronized methods or synchronized (this), and you let the cache clean up stale entries as documented. You expect searches and cleanUp(), which its javadoc calls 'safe to call concurrently', to keep running, as the same subclass does on 10.x, where Lucene never locks the cache object itself; on main, cleanUp() is a synchronized method, so it holds the cache object's monitor while it waits for a partition lock, while a search holds that partition lock and waits for the same monitor inside your callback. Both threads wait for each other forever (the JVM's deadlock detector names the cycle for the insertion callback; for onHit it cannot, because a read-lock holder has no owner), and every later search whose callback needs the monitor, every clearQuery() on that partition and every later cleanUp() block behind them.",
   "impact_class": "hang",
   "introduced_commit": "d50fb36d9af3 (GITHUB#15558 'Refactor QueryCache to improve performance', by Sagar Upadhyaya (sgup432), merged by Michael Froh (msfroh); design issue #14222; 'public synchronized void cleanUp()' is already in the PR's first revision ef7cf0ff101, 2026-01-08) [exec]",
   "introduced_date": "2026-04-14 (commit author date 2026-04-14T18:55:32+02:00, merged 2026-04-14T16:55:32Z)",
   "first_affected_version": "unreleased (main / 11.0.0-SNAPSHOT since 2026-04-14 and branch_11x, cut from main 2026-10-28 [read]; #15558 was deliberately not backported, so no release, 10.6.0 (released 2026-10-29; branch_10_6 4ae946e5a9b) included, is affected [exec])",
   "affected_versions": "main from d50fb36d9af3 (2026-04-14) to a9779ef3c193 [exec]; branch_11x [read]; upstream main 645d4fe14a2 (2026-10-28) [read]. Not affected [exec]: 9.12.3, 10.5.2 and the 10.6 RC branch_10_6 4ae946e5a9b (core jar only): the JUnit does not compile (no cleanUp(), no CacheCleanUpParameters, no onCacheEntryInserted/Evicted) and the 10.x analog (the same synchronized (this) subclass against clearQuery()/clear()) passes 3 of 3; the independent reproduction ran the analog on 10.5.2, 9.12.3 and main (pass). [read] From LUCENE-7237 (bf232d7635e, 2016) to #15558 LRUQueryCache used only private locks (ReentrantLock, then ReentrantReadWriteLock from #13306) and never its own monitor; in 5.x (LUCENE-6303, 2015) every method was synchronized on the cache, a single re-entrant lock, so no cycle was possible. All runs JDK 25.0.3 on Linux aarch64 with -XX:ActiveProcessorCount=4",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1001.html",
   "repro": "repro/LFV-1001/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-581",
   "priority": "low",
   "priority_rank": 748,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter commit (merge-on-commit under commitLock, SerialMergeScheduler, tragic-event rollback)",
   "title": "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)",
   "summary": "You configure IndexWriter with SerialMergeScheduler and keep merge-on-commit on (the default since 9.3); one thread calls commit() while another thread's addDocument runs a merge, and that merge fails, for example because the disk is full. You expect IndexWriter to close itself on the tragic merge failure and both calls to return with an exception, as they do with ConcurrentMergeScheduler or with merge-on-commit off. Instead commit() holds IndexWriter's commit lock while it waits to enter SerialMergeScheduler's synchronized merge method, and the failing merge thread, still inside that method, waits for the commit lock in the tragic rollback, so both threads hang forever and the writer cannot be closed.",
   "impact_class": "hang",
   "introduced_commit": "7f352a96659b4d304ae3ef0c7a1b62784ce2a406 (main) and its branch_8x backport 9b1c92809e7 (shipped in 8.6.0): apache/lucene-solr#1617, LUCENE-8962 'Merge small segments on commit' (GitHub issue #10005; author s1monw, co-authors msfroh, msokolov and mikemccand; merged 2020-06-27), which added mergeScheduler.merge(mergeSource, MergeTrigger.COMMIT) to prepareCommitInternal while the caller holds commitLock [read]. #1617 added the last edge of the cycle; the others predate it: SerialMergeScheduler.merge synchronized since 2.3 (299d6357dd2), a merge failure tragic since 5.3.0 (LUCENE-6579, 926397824e9), rollbackInternal taking commitLock since 5.4.0 (LUCENE-6790, 690f6d6578b). Two unreleased precursors with the same call (#1155 043c5dff6f4, #1552 972c84022ec) were reverted in 2020.",
   "introduced_date": "2020-06-27",
   "first_affected_version": "8.6.0 [exec]; with default merge-on-commit settings and a stock LogDocMergePolicy from 9.3.0 [exec] (LUCENE-10078, #921); 8.5.2 and older not affected [exec]",
   "affected_versions": "every release from 8.6.0 through 10.5.2 (the last release before 10.6.0) and main a9779ef3c193; the previous hunt main ea57360912ed too [read]. [exec] JVM-detected deadlock on 8.6.0 (-ea/-da), 8.7.0, 8.11.4 (-ea/-da), 9.0.0 and 9.2.0 with merge-on-commit opted in, and on 9.3.0, 9.12.3, 10.5.2 and main (each -ea and -da) with default settings and stock LogDocMergePolicy; passes on 8.5.2 (no merge-on-commit), on 8.6.0, 8.11.4 and 9.2.0 with defaults (merge-on-commit off by default before 9.3.0), with stock policies before 9.3.0 (no full-flush merges selected), and on main with merge-on-commit off (control). [exec] the finder's JUnit fails on 9.9.0, 9.12.3, 10.5.2 and main (-ea/-da; its 9.1.0 and 9.8.0 failures are a test artifact and not counted, because before 9.9.0 a commit with nothing buffered runs no commit merges); the independent reproduction's main() on main (-ea/-da, 20 of 20 iterations), 10.5.2, 9.12.3, 9.3.0 and 9.0.0 (opt-in); the intended-behaviour check's stock-policy JUnit on main (-ea/-da) and 10.5.2; a separate JUnit on main (-ea/-da) and 10.5.2. Reach by version: 8.6.0-9.2.x needs an explicit nonzero wait, a merge policy implementing findFullFlushMerges and (before 9.9.0) a commit that flushes buffered documents; 9.3.0+ default settings suffice; 9.9.0+ (#12549) also a commit that flushes nothing. [read] a static scan of the tagged releases in the history clone (8.6.0-10.5.2; its 8.9-8.11 tags are missing, 8.11.4 was executed instead) finds the COMMIT merge call under commitLock in each; not executed individually: 8.6.1-8.6.3, 8.8.x-8.11.3, 9.4-9.11.x, 9.12.0-9.12.2, 10.0-10.5.1. Not fixed on upstream main a95c754ee003 (2026-10-26) [read]. Releases were run on JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-581.html",
   "repro": "repro/LFV-581/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-648",
   "priority": "low",
   "priority_rank": 749,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter close (waitForMerges, ConcurrentMergeScheduler, tragic merge failure)",
   "title": "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)",
   "summary": "You start a background forced merge with forceMerge(1, false) and then call close(), and you expect close() to commit and return, or, if a merge fails, to throw and leave the writer closed, as its javadoc says. Instead, if one merge fails (for example disk full) just after another forced merge finished and queued the next round, close() waits forever in waitForMerges(): the failure does not roll the writer back because close() is already closing, since 9.3.0 IndexWriter refuses to start any pending merge after such a failure, and the wait loop never looks at the failure. The write lock stays held and a rollback() from another thread blocks as well; only interrupting the closing thread ends the wait.",
   "impact_class": "hang",
   "introduced_commit": "7d9de759f244896d47da77c842051845199d316e on branch_9x (shipped first, in 9.3.0; parent 19735c611ce4) and b5795db0cf517f8942eed868752249df9b105603 on main (squash merge, first released in 10.0.0), both 'LUCENE-10078: Enable merge-on-refresh by default. (#921)' by jpountz (issue #11116, approved by s1monw). The bug-relevant part is 8 added lines in IndexWriter.java: getNextMerge() and hasPendingMerges() throw IllegalStateException('this writer hit an unrecoverable error; cannot merge') once a tragedy is set; neither the PR, the review nor CHANGES mentions them [read]. A regression of the close() path: before it, the registering merge thread still checked out the pending merge, which failed in _mergeInit, and close() threw. Older ingredients: the waitForMerges loop with no tragedy check (shape from 52b2a30bccb6, 2014), the tragic rollback skipped while closing (LUCENE-6579 926397824e9f, LUCENE-8205 5dfba25e3496), forced-merge cascade registration in IndexWriter.merge's finally block (LUCENE-2618 25828363ec11) and ConcurrentMergeScheduler.runOnMergeFinished catching only AlreadyClosedException/IOException (LUCENE-9337 2b6ae53cd9f0)",
   "introduced_date": "2022-06-07 (main b5795db0cf51 committed 16:59:55 +0200; branch_9x 7d9de759f244 17:00:16 +0200)",
   "first_affected_version": "9.3.0 [exec] for the pending-merge trigger (9.2.0, the last release before the introducing commit, passes the same schedule [exec]); 8.6.0 [exec] for the stopped-merge trigger (a merge fails while ConcurrentMergeScheduler has stopped another merge; 8.5.2 passes [exec])",
   "affected_versions": "Every release from 9.3.0 on, and main: the follow-up history matrix executed the same latch schedule on all 30 releases 9.3.0, 9.4.0, 9.4.1, 9.4.2, 9.5.0, 9.6.0, 9.7.0, 9.8.0, 9.9.0, 9.9.1, 9.9.2, 9.10.0, 9.11.0, 9.11.1, 9.12.0, 9.12.1, 9.12.2, 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and on main a9779ef3c193 (-ea and -da); all hang in waitForMerges [exec]. Finder and the independent reproduction independently: main -ea/-da, 10.5.2 (-ea and -da), 9.12.3 and 9.3.0 hang; 9.2.0 passes [exec]. Not affected by the pending-merge trigger (close() throws and the writer ends up closed): 9.2.0, 9.1.0, 9.0.0 and 8.11.4 [exec]; no release before 9.3.0 has the getNextMerge()/hasPendingMerges() refusal (git tag --contains; bytecode of the 8.11.4 and 9.0.0-9.2.0 core jars has 'cannot merge' only in _mergeInit) [read]. Not fixed upstream: upstream main a95c754ee003 (2026-10-26) has no IndexWriter.java change since 2026-09-21 and no ConcurrentMergeScheduler.java change since before 2026-09-01; IndexWriter.java, ConcurrentMergeScheduler.java, MergePolicy.java and LogMergePolicy.java are identical on ea57360912ed and a9779ef3c193 (git diff empty). Re-run 2026-11-02: the finder JUnit still fails 1 of 2 (its control passes) on released 10.6.0 and on main e1faeba08bde (-da) [exec]. Stopped-merge trigger: 8.6.0, 9.12.3 and 10.5.2 [exec], released 10.6.0 (-da) and main e1faeba08bde (-ea, -da) [exec] hang; 8.5.2 returns [exec].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/4446",
    "https://issues.apache.org/jira/browse/LUCENE-3373",
    "https://issues.apache.org/jira/browse/LUCENE-10078",
    "https://github.com/apache/lucene/issues/11619",
    "https://issues.apache.org/jira/browse/LUCENE-10583",
    "https://github.com/apache/lucene/issues/2287"
   ],
   "doc": "",
   "repro": "repro/LFV-648/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-846",
   "priority": "low",
   "priority_rank": 750,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter flush hand-off (DocumentsWriterFlushControl.checkOutForFlush, updateStallState, waitForFlush)",
   "title": "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)",
   "summary": "You index with IndexWriter's InfoStream turned on, and one logging call throws (an OutOfMemoryError while Lucene builds its 'now stalling flushes' message, or an exception from the logging backend) just as a full in-memory buffer is handed over to be flushed. You expect what the IndexWriter javadoc promises: after an Error the writer closes itself, and after an exception close() or rollback() still finish. Instead the buffer is already registered as 'flushing' when the log call throws, nothing ever flushes or releases it, and every later wait for running flushes waits forever: after an Error addDocument hangs inside the writer's own rollback, and after an exception close() and rollback() hang (and, by code reading, commit() and an NRT reopen too).",
   "impact_class": "hang",
   "introduced_commit": "614b45d2dff43cb05df1f4fa65a40d0568bda616 (mikemccand, 'reduce IW.infoStream noise when stalling happens due to too many total bytes flushing; only notifyAll in stall/unstall when it changes'; a direct commit with no JIRA key or PR; branch_6x backport 30db9e72ba3a with identical Java hunks). It moved the stall logging (infoStream.isEnabled(\"DWFC\") plus a String.format'd 'now stalling flushes' / 'done stalling flushes' message) from DocumentsWriterStallControl, where the waiting thread logged it with no buffer checked out (LUCENE-6209, 669e9cf617c, 2015), into DocumentsWriterFlushControl.updateStallState(). The hand-off already called updateStallState() in its finally, after adding the buffer to flushingWriters (try/finally from LUCENE-3090, 4fd5dceb998b, 2011; the call from LUCENE-4158, c4e4b36037a3, 2012; harmless until then because updateStallState called no InfoStream method). [exec]",
   "introduced_date": "2016-07-25 (author date of 614b45d2dff4 and of the branch_6x backport 30db9e72ba3a)",
   "first_affected_version": "6.2.0 [exec]. 6.1.0 and 5.5.5 are not affected [exec]. 6.2.0 shipped the branch_6x backport 30db9e72ba3a; the master commit 614b45d2dff4 first shipped in 7.0.0.",
   "affected_versions": "main a9779ef3c193 [exec]. 6.2.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0 and 10.5.2 [exec]. Every release tag from 6.2.0 to 10.5.2 has the InfoStream call in updateStallState [read]; the unreleased branch_10_5 and branch_10x heads and the branch_10_6 head have the same hand-off and logging [read], and DocumentsWriterFlushControl.java is the 10.5.2 file at the 10.6.0 commit 4ae946e5a9b (released 2026-10-29), so 10.6.0 is affected by reading; upstream main e1faeba08bd [exec]: since 10.6.0, DocumentsWriterFlushControl.java was changed only by #16867 (2813efa40a3, 2026-10-30), outside checkOutForFlush; branch_11x da3ea39fa59 is the same as main and branch_10_6 91eaab4fb29 the same as 10.6.0 [read]. Not affected: 6.1.0 and 5.5.5 [exec], 4.1.0-6.1.0 [read]. All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-846.html",
   "repro": "repro/LFV-846/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1174",
   "priority": "low",
   "priority_rank": 751,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter full-flush abort (DocumentsWriterFlushControl.abortPendingFlushes, doAfterFlush, waitForFlush)",
   "title": "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)",
   "summary": "Several threads index into one IndexWriter, so it holds three or more in-memory segments, and you open an NRT reader; the full flush fails, and while the writer aborts the segments still queued behind the failed one an Error (realistically an OutOfMemoryError) is thrown. You expect what the IndexWriter javadoc promises: after an Error the writer closes itself, DirectoryReader.open(writer) throws, and later calls throw AlreadyClosedException. Instead abortPendingFlushes catches only Exception, so the Error leaves its loop after releasing just the current segment, the segments it has not visited yet stay registered as flushing with nothing left to release them, and the writer's self-close waits for them forever, so DirectoryReader.open(writer) never returns.",
   "impact_class": "hang",
   "introduced_commit": "2e35ef2b3daa1c1fdccbf78326d589e873489311 on the main line (first release 8.0.0) and its branch_7x cherry-pick ddb0bd78f7dbf207f8bf78fdcbb68914d98cdc3a (first release 7.4.0), the same change: LUCENE-8215 'Fix several fragile exception handling places in o.a.l.index' by Simon Willnauer (migrated issue #9262; reviewed on a pull request in the author's own fork, which now returns 404; no CHANGES entry). It changed both per-entry 'catch (Throwable ex) { // ignore - keep on aborting the flush queue }' clauses of DocumentsWriterFlushControl.abortPendingFlushes to 'catch (Exception ex)' [read]. The rest of the mechanism is older and was harmless while the catch took Throwable: the outer finally that clears the queues (LUCENE-4277, b26dd733f77, 2012) and the per-entry finally doAfterFlush (LUCENE-5002, c0e7a50ab8e, 2013). LUCENE-8205 and LUCENE-8212, both authored a few days before LUCENE-8215, let an Error out of DWPT.abort through IOUtils.closeWhileHandlingException; an Error from the InfoStream's 'now abort' line escapes DWPT.abort even without them. Individual 2018 commits were not built.",
   "introduced_date": "2018-03-19 (author date of 2e35ef2b3da and ddb0bd78f7d; committed 2018-03-20 on main and branch_7x); first release 7.4.0",
   "first_affected_version": "7.4.0 [exec]; 7.3.1 is not affected [exec]; on the main line the first release is 8.0.0 [exec]. Releases before 4.0.0-beta have no abortPendingFlushes, and 4.0.0-beta to 7.3.1 catch Throwable there [read]",
   "affected_versions": "Every release from 7.4.0 (2018) through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT); never fixed. [exec] the one-test repro TestErrorAbortingQueuedSegments hangs on main with -ea and -da (the final repro check and gradle) and on the 10.6.0 and 9.12.3 jars (-da, the fact check); the independent reproduction's earlier, longer version of it (same class name and fault model) hangs on main (-ea and -da: the independent reproduction, the re-run of 2026-11-03 and the audit; -da: the adjudication), on 10.6.0, 10.5.2 and 9.12.3 (-da, the independent reproduction; 10.6.0 and 9.12.3 again in the history step) and, adapted for the 7.x/8.x test framework, on 7.4.0, 7.7.3, 8.0.0 and 8.11.4 (-da); 7.3.1 passes. The finder's InfoStream-based test hangs on main (-ea, -da), 10.6.0 and 9.12.3 (-da). [read] all 59 release tags from 7.4.0 to 10.6.0 in the release-tag clone have catch (Exception) in this loop and all 64 tags from 4.0.0-beta to 7.3.1 have catch (Throwable); 8.9.0 to 8.11.3 are not in the clone and fall between 8.8.1 (read) and 8.11.4 (exec). Not new in 10.6 (10.5.2 and every executed release from 7.4.0 hang). Not fixed upstream: main 1c2072f0284 (2026-11-02), branch_11x 6c5889ee89f and branch_10_6 5deb5791f6c still catch only Exception there; the last commit on DocumentsWriterFlushControl.java is #16867 (2813efa40a3, author date 2026-10-30), which 5adff78 contains and which leaves these catches alone.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1174.html",
   "repro": "repro/LFV-1174/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-586",
   "priority": "low",
   "priority_rank": 752,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter addIndexes(CodecReader...) (merge-scheduler hand-off, NoMergeScheduler)",
   "title": "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",
   "summary": "You configure an IndexWriter with NoMergeScheduler (also with NoMergePolicy, the pairing the NoMergeScheduler javadoc recommends) and call addIndexes(CodecReader...). You expect the call to add the readers, as it did up to 9.3.0, or at least to return or throw. Instead, since 9.4.0 (LUCENE-10216) the call hands its reader merge to the merge scheduler and then waits for it with no time limit; NoMergeScheduler.merge does nothing, so the call blocks until another thread interrupts it or rolls the writer back.",
   "impact_class": "hang",
   "introduced_commit": "698f40ad51af0c42b0a4a8321ab89968e8d0860b (main): apache/lucene#633, LUCENE-10216 'Use MergeScheduler and MergePolicy to run addIndexes(CodecReader[]) merges' (issue #11253; author vigyasharma; merged 2022-07-06), and its branch_9x backport 5dd8e9bdc5ae72fc726a98a64bfce5119c77b558 (#1051, merged 2022-08-01), which shipped in 9.4.0. They replaced the inline SegmentMerger merge with registerMerge + mergeScheduler.merge(addIndexesMergeSource, ADD_INDEXES) + spec.await() and removed the javadoc note 'this method does not call or make use of the MergeScheduler' [exec]. NoMergeScheduler.merge has been empty since the class was added (c8c5dfa5431, LUCENE-2331, 2010).",
   "introduced_date": "2022-07-06 (main); 2022-08-01 (branch_9x backport); first release 9.4.0 (tag dated 2022-09-30)",
   "first_affected_version": "9.4.0 [exec]",
   "affected_versions": "every release from 9.4.0 through 10.5.2 (29 releases: 9.4.0 to 9.12.3 and 10.0.0 to 10.5.2) and main a9779ef3c193, -ea and -da [exec]; the previous hunt main ea57360912ed too [read]. Not affected [exec]: 9.1.0, 9.2.0 and 9.3.0 (candidate JUnit), 9.0.0 and 8.11.4 (core-only probe); older releases predate the scheduler hand-off [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-586.html",
   "repro": "repro/LFV-586/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-208",
   "priority": "low",
   "priority_rank": 753,
   "novelty": "known",
   "withheld": false,
   "area": "index / ConcurrentMergeScheduler merge spawn (CMS.merge hand-back, IndexWriterMergeSource.onMergeFinished, IndexWriter.mergeFinish)",
   "title": "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",
   "summary": "You use the default ConcurrentMergeScheduler, and something fails while it hands a merge to a new merge thread: for example the JVM cannot create another thread, or a negative forced-merge rate that setForceMergeMBPerSec accepted is rejected right after the thread started. You expect the merge either to run normally or to be abandoned cleanly, so that calls waiting for it see the failure. Instead the scheduler's catch block only unregisters the merge: if the thread never started, the merge is never completed, so addIndexes(CodecReader...) waits forever and forceMerge/forceMergeDeletes return with the work undone; if the thread had already started, its segments look free while they are being merged, a second merge of the same segments starts, and the writer is closed by a tragic exception.",
   "impact_class": "hang",
   "introduced_commit": "89fde6f3f069 (svn r1649539) with its follow-up bfb1e10161fe (svn r1650026, 'fix just arrived merge to throttle correctly') on branch_5x; trunk equivalents 41fcc722ff07 and 941f6e64c828: LUCENE-6119 'Add auto-IO-throttling to ConcurrentMergeScheduler' by mikemccand (svn era, no pull request; the JIRA issue was migrated to #7181). It added setForceMergeMBPerSec without validation, MergeRateLimiter.setMBPerSec (rejects negative rates), an updateMergeThreads() that applies the forced-merge rate to running forced merges, and the merge-thread cascade (a finished merge thread spawns follow-on merges itself), and the follow-up put updateMergeThreads() back directly after start() inside the hand-back region [read]. Older latent shape: the hand-back 'if (!success) writer.mergeFinish(merge)' is from LUCENE-1573 (7aa012ca2712, 2009, first released 2.9.0) and the post-start updateMergeThreads() inside it from LUCENE-2820 (765eab4008f4 trunk / 587791cfa0d branch_3x, 2010, first released 3.1 / 4.0.0), reachable before 5.0.0 only through a protected hook [exec]",
   "introduced_date": "2015-01-05 (89fde6f3f069; follow-up bfb1e10161fe 2015-01-07; no release in between); latent shape 2009-03-28 (LUCENE-1573) and 2010-12-20 (LUCENE-2820)",
   "first_affected_version": "5.0.0 [exec] (release commit 2015-02-19; both manifestations reproduce there); 4.10.4 (2015-03-03, separate 4.10 bugfix branch) and, by date, 4.10.3 are the last releases without a public trigger [exec], although an injected failure in the protected updateMergeThreads() hook shows the same running-merge-unregistered state on all 23 4.x releases",
   "affected_versions": "Every release from 5.0.0 to 10.5.2 on Maven Central (107 releases) and main ea57360912ed [exec]: the version-adapted (a) and (b) probes fail on all 107 under -ea (release sweep, seed DEADBEEF) and under -da on 5.0.0, 8.5.2, 9.12.3, 10.5.2 and main; the finder's JUnit fails on main (-ea and -da; 20 of 20 test runs over 10 -da iterations), 10.5.2 and 9.12.3 (9.x variant, test (a)) and with open PR #16889 applied (heads e304ea8cbd6, 2026-10-26, and 6c281d1cb52, 2026-11-02 on main e1faeba08bd with -ea and -da); the independent reproduction's own repro fails on main, 10.5.2 and 9.12.3 under -ea and -da. Consequences by version [exec]: 5.0.0-5.2.1 (a) fails merges but the writer stays open, from 5.3.0 (LUCENE-6579) it closes the writer tragically; from 8.6.0 (LUCENE-8962) a merge dropped by (b) never completes its completion future; from 9.4.0 (LUCENE-10216) addIndexes(CodecReader...) can block forever on it; from 10.4.0 (#15378) forceMergeDeletes() returns a MergeObserver that never completes. Not affected through public triggers: 4.0.0-4.10.4 [exec]; releases before 4.0.0 were not run. Not fixed upstream: main ea57360912ed was the upstream main head at search time, ConcurrentMergeScheduler.java last changed 2026-06-14 (#16255) with the catch block unchanged, and no open PR changes it [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15761",
    "https://github.com/apache/lucene/issues/16226",
    "https://github.com/apache/lucene/issues/4446",
    "https://issues.apache.org/jira/browse/LUCENE-3373",
    "https://github.com/apache/lucene/issues/2287",
    "https://issues.apache.org/jira/browse/LUCENE-1210"
   ],
   "doc": "",
   "repro": "repro/LFV-208/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-844",
   "priority": "low",
   "priority_rank": 754,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter merge hand-off to the merge scheduler (IndexWriterMergeSource.getNextMerge, runningMerges)",
   "title": "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)",
   "summary": "You turn on IndexWriter's InfoStream for merge-scheduler messages, and the logging call throws once (an OutOfMemoryError, or an exception from the logging backend). It throws on the message the writer prints right after it hands a merge to the merge scheduler. You expect what the IndexWriter javadoc promises: after an Error the writer closes itself, and after an exception close() still finishes, because no merge is actually running. Instead, the merge has already been moved from 'pending' to 'running', and no thread ever runs or finishes it, so after an Error addDocument hangs forever inside the writer's own rollback (abortMerges), and after an exception close() hangs forever in waitForMerges.",
   "impact_class": "hang",
   "introduced_commit": "d7e0b906abcbc43d3737224cadcda7d2c795ccb0 (LUCENE-9345 'Separate MergeSchedulder from IndexWriter', apache/lucene-solr#1451 by s1monw, merged 2020-04-24; branch_8x backport 9598d43bb629). It moved the merge log line out of ConcurrentMergeScheduler.merge's protected try/finally, which called writer.mergeFinish when the merge did not start. The line went into the new IndexWriterMergeSource.getNextMerge, after the pending-to-running check-out, with no hand-back [read]",
   "introduced_date": "2020-04-24 (author date of d7e0b906abc and of the branch_8x backport 9598d43bb62)",
   "first_affected_version": "8.6.0 [exec]. 8.5.2 is not affected [exec]: there, the analogous post-check-out message (' consider merge ...') sat inside CMS.merge's protected try, so the writer closes itself after the Error and close() returns after the exception. 8.5.x shipped from branch_8_5, which does not contain the backport [read]",
   "affected_versions": "main a9779ef3c193 [exec]. 10.5.2, 9.12.3, 9.0.0, 8.11.4 and 8.6.0 [exec]. SerialMergeScheduler was executed by the independent reproduction on main, 10.5.2 and 9.12.3; for the other releases it is from code reading. The releases in between that were not run have the same code [read]. branch_10_6 and upstream main 20ced71c1e6 have the same code [read]; IndexWriterMergeSource.getNextMerge is the same at the 10.6.0 commit 4ae946e5a9b (released 2026-10-29), so 10.6.0 has it by reading. Not affected: 8.5.2 [exec] and earlier [read]. All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-844.html",
   "repro": "repro/LFV-844/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1210",
   "priority": "low",
   "priority_rank": 755,
   "novelty": "new",
   "withheld": false,
   "area": "index / ConcurrentMergeScheduler (updateMergeThreads infoStream logging; IO-throttle setters, merge start and finish)",
   "title": "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",
   "summary": "You give IndexWriterConfig an InfoStream that follows a logger level, and you switch merge-scheduler logging on while the writer runs, at a moment when ConcurrentMergeScheduler.updateMergeThreads is running (it runs in setForceMergeMBPerSec, enableAutoIOThrottle and disableAutoIOThrottle, and at every merge start and finish). You expect the call to finish normally and logging to start, as it does with a constant InfoStream and as it did in 4.x. Instead the method, which skipped creating its log buffer because its first verbose() check said false, sees true at a later check and throws NullPointerException ('Cannot invoke \"java.lang.StringBuilder.toString()\" because \"message\" is null').",
   "impact_class": "minor",
   "introduced_commit": "41fcc722ff07 on trunk (svn r1649532) and 89fde6f3f069 on branch_5x (svn r1649539, how 5.0.0 got it): LUCENE-6119 'CMS dynamically rate limits IO writes of each merge depending on incoming merge rate' by mikemccand (no pull request; the JIRA issue is now #7181). It rewrote updateMergeThreads around one StringBuilder log buffer that is allocated only when the first verbose() check is true ('message = null' otherwise) and then appended to and flushed under separate verbose() checks, and added the public setters setForceMergeMBPerSec, enableAutoIOThrottle and disableAutoIOThrottle that call it [read] [exec]",
   "introduced_date": "2015-01-05 (41fcc722ff0 at 14:28:28Z; 89fde6f3f06 at 15:00:32Z)",
   "first_affected_version": "5.0.0 [exec] (released 2015-02-19); 4.10.3 and 4.10.4 are not affected: each verbose() check there guards its own message() call and there is no buffer [exec]",
   "affected_versions": "every release from 5.0.0 through 10.6.0, and main 5adff78bb168 [exec] [read]; not fixed upstream (main tip 1c2072f0284, 2026-11-02, has the same lines; the newest commit on the file is 54283150a81, #16255, author date 2026-06-14, outside updateMergeThreads). A regression relative to 4.x. Not new in 10.6 (10.5.2 fails). All runs used JDK 25 on one aarch64 Linux host",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1210.html",
   "repro": "repro/LFV-1210/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1084",
   "priority": "low",
   "priority_rank": 756,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter full flush (DocumentsWriter.finishFullFlush, DocumentsWriterFlushControl blocked flushes and stall control)",
   "title": "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)",
   "summary": "You enable an InfoStream on an IndexWriter, and the logging sink throws a RuntimeException once, on the message DocumentsWriter.finishFullFlush logs at the end of a commit (prepareCommit, flush() and NRT opens take the same path). You expect commit() to fail with that exception and the writer, which stays open and has no tragic exception, to keep honouring its flush settings ('the writer will flush every maxBufferedDocs added documents'). Instead the log call runs before the code that ends the full flush, so the writer stays in full-flush mode: every in-memory segment that should flush is parked as blocked (10 more adds with maxBufferedDocs=2 leave 10 documents buffered), and with the default RAM-based flushing a thread that keeps indexing without another commit or refresh eventually waits forever in addDocument.",
   "impact_class": "minor",
   "introduced_commit": "78d186e081f56b1e53d8bd8aef4e90d3cf81dbab (LUCENE-3348 'IndexWriter applies wrong deletes during concurrent flush-all', Subversion trunk r1155278, committed by s1monw, patch by mikemccand and s1monw; LUCENE-3348 = apache/lucene#4421; svn era, no pull request) [exec]. It added the log line as the first statement of finishFullFlush, ahead of flushControl.finishFullFlush()/abortFullFlushes(). LUCENE-3551 (73dec384b40, 2011-11-04) later wrapped the body in try/finally with only pendingChangesInCurrentFullFlush in the finally, and LUCENE-8317 (2018) added applyAllDeletes() there, both keeping the release behind the log line [read]",
   "introduced_date": "2011-08-09 (78d186e081f, author date = commit date 2011-08-09T09:22:15Z, git-svn import)",
   "first_affected_version": "4.0.0-ALPHA [exec]; first GA release 4.0.0 [exec]; not affected: 3.6.2 and every earlier release, which have no per-thread writers and no finishFullFlush [exec]",
   "affected_versions": "every release from 4.0.0-ALPHA through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main e1faeba08bde (unreleased) [exec]; the releases in between by git tag --contains 78d186e081f (124 release tags, plus the 8.8.2-8.11.4 releases of the separate lucene-solr branch_8x) and git log -L of the method (no later change moves the release ahead of the log line) [read]. The permanent addDocument stall exists from 8.8.0 on (LUCENE-9508, c71f119e9ac, made stalled threads wait until unstalled); in 8.7.0 and earlier indexing crawls instead (stall-rate probe with a 1 MB buffer: 20 documents in 20 s on 8.7.0, 0 on 8.8.0) [exec]. Not affected: 3.6.2 and earlier, and trunk fda091ef24e [exec]. Not new in 10.6. All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1084.html",
   "repro": "repro/LFV-1084/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-447",
   "priority": "low",
   "priority_rank": 757,
   "novelty": "new",
   "withheld": false,
   "area": "index / TieredMergePolicy parameter validation (findMerges allowed-segment-count loop, IndexWriter.updatePendingMerges)",
   "title": "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)",
   "summary": "You build an IndexWriter with the default TieredMergePolicy, call setSegmentsPerTier(Double.NaN), add one document and call flush() or commit(), expecting the setter to throw IllegalArgumentException as it does for every other value outside 'segmentsPerTier must be >= 2.0', or at least a flush that returns. Instead the setter stores NaN (its only check is 'v < 2.0', which is false for NaN) and flush() never returns: findMerges computes mergeFactor = (int) NaN = 0, the level size drops to 0, both exit tests of its while (true) loop stay false, and the thread spins forever while holding the IndexWriter lock, so every other thread that needs the writer blocks. The other four double setters (maxMergedSegmentMB, deletesPctAllowed, floorSegmentMB, forceMergeDeletesPctAllowed) accept NaN through the same ordered-only checks; with forceMergeDeletesPctAllowed = NaN, forceMergeDeletes() expunges nothing.",
   "impact_class": "hang",
   "introduced_commit": "f10d92398bc688b40498d9a4c765728ed446e050 (trunk, 'LUCENE-1076: new TieredMergePolicy'; Subversion era, no pull request; the issue was migrated as apache/lucene#2153, whose comments never mention NaN or segmentsPerTier validation) added setSegmentsPerTier with only the 'v < 2.0' check and the allowed-segment-count loop whose only exit was 'segCountLevel < segsPerTier', both false for NaN [read]; it shipped through the branch_3x backport ec542dd385e588075207cde69b9eefc072bcea3f ('LUCENE-1076: new TieredMergePolicy (merged from trunk)') [exec]. The current mechanism (mergeFactor = (int) NaN = 0, so levelSize falls to 0) comes from LUCENE-8392 (#9439; master 9433ab79e22, branch_7x 43481f26db0) and LUCENE-8393 (master 8e0d9849bd4, branch_7x 97833b729e3), both 7.5.0, and on main only #14165 (d2c69c1472c, mergeFactor = (int) segsPerTier); these changed how the loop spins, not whether it does [exec]. Not a regression: no commit ever added a NaN check to the file (git log -G isNaN finds nothing)",
   "introduced_date": "2011-04-02 (trunk f10d92398bc); 2011-05-05 (branch_3x backport ec542dd385e)",
   "first_affected_version": "3.2.0 [exec] (the first release with TieredMergePolicy; 3.1.0, the release before, has no such class: the repro fails to compile with 'cannot find symbol TieredMergePolicy')",
   "affected_versions": "every release that has TieredMergePolicy, 3.2.0 through 10.6.0 (10.6.0 by reading), and main ea57360912ed [exec] [exec] [read]. The forceMergeDeletesPctAllowed = NaN no-op was executed only on 9.12.3, 10.5.2 and main (same age by reading). Mechanism by era: 3.2.0-7.4.0 the loop's only exit is 'segCountLevel < segsPerTier'; from 7.5.0 mergeFactor = (int) Math.min(maxMergeAtOnce, NaN) = 0 and the added exit 'levelSize == maxMergedSegmentBytes' is taken only when maxMergedSegmentBytes is 0 [read]; from 9.x commit() also reaches findMerges through MergePolicy.findFullFlushMerges. All runs used JDK 25.0.3 on aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-447.html",
   "repro": "repro/LFV-447/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-207",
   "priority": "low",
   "priority_rank": 758,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter forceMergeDeletes MergeObserver (registerMerge, MergePolicy.MergeObserver)",
   "title": "IndexWriter.forceMergeDeletes returns a MergeObserver that also tracks merges IndexWriter refused to register, so the observer never completes and await() blocks forever",
   "summary": "You use LogDocMergePolicy or LogByteSizeMergePolicy (or a custom merge policy), call IndexWriter.forceMergeDeletes(false) while another merge is already running on one of the segments with deletes, and wait on the returned MergeObserver, whose javadoc says it lets you 'monitor merge progress and wait for completion'. IndexWriter refuses to register the conflicting forced-deletes merge (it only logs 'reject merge'), so that merge never runs, but it still puts the merge into the observer. The observer then reports 0 of 1 merges complete forever: await() blocks forever even after the writer is closed, await(timeout) returns false, and the blocking forceMergeDeletes() returns at once with an incomplete observer although its javadoc says 'merges will already be complete when it returns'.",
   "impact_class": "hang",
   "introduced_commit": "c85c69f19082 (main, unreleased 11.0) and 6862ef978845 (branch_10x backport, released in 10.4.0), the same patch: #15378 'Return MergeObserver from IndexWriter.forceMergeDeletes() (#14515)' by salvatorecampagna, merged 2025-11-02 (fixes #14515) [read] [exec]; the patch wrapped the policy's unfiltered MergeSpecification in the new public observer; the older ingredients it exposed are the registration loop that ignores registerMerge's boolean result (1d4ab6879680, LUCENE-325, 2008, first released in 2.4.0) and LogMergePolicy.findForcedDeletesMerges not skipping merging segments (LFV-178, same 2008 commit)",
   "introduced_date": "2025-11-02 (#15378, merged 2025-11-02T23:36:21Z on main; the branch_10x backport was committed the same day)",
   "first_affected_version": "10.4.0 [exec] (first release with MergePolicy.MergeObserver); 10.3.2 and every earlier release, including the whole 9.x line, do not have the API (forceMergeDeletes returns void; the repro does not compile on 10.3.2 and 9.12.3 [exec])",
   "affected_versions": "10.4.0, 10.5.0, 10.5.1, 10.5.2, 10.6.0 and main ea57360912ed and 645d4fe14a20: every release that contains MergeObserver. [exec] the finder's JUnit fails 2 of 2 on 10.4.0 (-ea, -da), 10.5.0, 10.5.1, 10.5.2 (-ea, -da) and main (-ea, -da; 20/20 over --iters 10), and also with open PR #16889 applied (heads e304ea8cbd6, 2026-10-26, and 6c281d1cb52, 2026-11-02 on main e1faeba08bd with -ea and -da); the independent reproduction's own JUnit fails 3 of 5 (both controls pass) on main (-ea, -da), 10.5.2 and 10.4.0; the intended-behaviour check's natural-merge variant fails on main (-ea, -da) and 10.4.0; the follow-up's custom-policy variant fails on main (-ea, -da) and 10.5.2. [read] the forceMergeDeletes body, MergeObserver, LogMergePolicy.findForcedDeletesMerges and registerMerge hash identically at the 10.4.0, 10.5.0, 10.5.1 and 10.5.2 tags and on main; git tag --contains put the backport in exactly those four releases before 10.6.0 was tagged; re-run on 2026-10-31, it also lists 10.6.0 (tag 4ae946e5a9b) [read]. Not affected: 10.3.2 and earlier, all 9.x (API absent) [exec]. Before 10.4.0 the same rejection already made the blocking forceMergeDeletes(true) return while the competing merge still ran [exec], but there was no observer to hang and no 'complete when it returns' promise, so no claim is made for those versions. 10.6.0 (released 2026-10-29): the minimal test fails on the release jars (4ae946e5a9b9), -ea and -da, and on main 645d4fe14a20, -ea and -da [exec]. All runs on aarch64 with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-207.html",
   "repro": "repro/LFV-207/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-637",
   "priority": "low",
   "priority_rank": 759,
   "novelty": "new",
   "withheld": false,
   "area": "monitor / ParallelMatcher worker lifecycle (Monitor#match)",
   "title": "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",
   "summary": "You match documents with Monitor#match using ParallelMatcher.factory(executor, matcher, threads), for example on Executors.newFixedThreadPool(threads), and you expect what the default serial matcher does: Monitor#match returns the matches or throws, and leaves nothing running on your executor. Instead the ParallelMatcher constructor submits `threads` workers that only finish() can release, so when the match throws before finish() (here IndexSearcher.TooManyClauses from the presearcher for a document with terms in 1,025 fields used by registered queries, the same exception the serial matcher throws) the workers stay parked forever and the next valid match on the same pool never returns. A rejected submit leaks the already-accepted workers the same way, and with CallerRunsPolicy on a saturated pool the calling thread runs a worker itself and Monitor#match never returns.",
   "impact_class": "hang",
   "introduced_commit": "251dbe7cea8126cb7ecadc921ba444c63d06c618 on master and its branch_8x backport b8773d13ad8e249a045862249bf476c30a444461, 'LUCENE-8766: Add monitor subproject' by romseygeek (import of the Luwak library as lucene/monitor; JIRA LUCENE-8766 = apache/lucene#9811; PR apache/lucene-solr#648 closed unmerged after the direct commit, no line review comments) [read]. Not a regression: the defect arrived with the module import; the last Luwak version has the same design, its earlier history was not inspected",
   "introduced_date": "2019-06-13 (author and commit date of 251dbe7cea8 and b8773d13ad8)",
   "first_affected_version": "8.2.0 [exec] (first release with lucene-monitor; 8.1.1 has no monitor module: lucene-monitor 8.1.1 is not on Maven Central, setup_error); first main-line release 9.0.0 [exec]",
   "affected_versions": "Every lucene-monitor release, 8.2.0 through 10.6.0 (10.6.0 by reading), and main a9779ef3c193; never fixed. [exec] follow-up history matrix with the finder's JUnit (5 run / 4 failed each, the serial control passes): 8.2.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da); the finder also ran 8.11.2, 9.1.0, 9.12.3 and 10.5.2; the independent reproduction's own JUnit fails on 10.5.2 and 9.12.3, the intended-behaviour check's probe on 10.5.2. [read] a source check of all 48 release tags in the history clone (8.2.0-8.8.1, 9.0.0-10.5.2) finds the submit-in-constructor, take-until-END, put(END)-only-in-doFinish and finish-only-on-success statements in every tag; the clone has no 8.8.2-8.11.x tags (8.11.2 and 8.11.4 were executed). Not fixed upstream: no open apache/lucene PR touches ParallelMatcher.java or Monitor#match (2026-10-27).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-637.html",
   "repro": "repro/LFV-637/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-485",
   "priority": "low",
   "priority_rank": 760,
   "novelty": "known",
   "withheld": false,
   "area": "analysis / CharArraySet and CharArrayMap unmodifiable views (stop-word, keyword and protected-word sets)",
   "title": "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",
   "summary": "You create a small CharArraySet (new CharArraySet(0, true)), add \"the\", hand out CharArraySet.unmodifiableSet(set) as a read-only view, as its javadoc suggests, and keep adding stop words to the original. You expect the view to be a consistent set, either a live view whose size and contents follow the original or a snapshot, and in any case a contains() that returns. Instead the view shares the original's hash-table arrays but copied its size, so after one more add it reports size() 1 while it iterates 2 words, after the original rehashes it sees only some of the later words, and once the original's 8-slot table takes its 8th word the view keeps that full table and contains() of any word not in the set (and a StopFilter or StandardAnalyzer over the view analysing \"lucene\") never returns.",
   "impact_class": "hang",
   "introduced_commit": "ea7e4ad3443ff1519a8a98514ae265d73522666a (SVN r794078, 2009-07-14), LUCENE-1688 = GitHub issue #2762 'Deprecate static final String stop word array in and StopAnalzyer and replace it with an immutable implementation of CharArraySet.' (patch by s1monw, committed by markrmiller; an SVN commit, no pull request): it added the public CharArraySet.unmodifiableSet as a non-delegating wrapper, with the comment 'Instead of delegating calls to the given set copy the low-level values to the unmodifiable Subclass', which shares the table array and copies the count; all three symptoms were present in that commit [read] [exec]. Current form: 924d7faa6843255986f765219ca4b7f5b93f3649 (SVN r906032, 2010-02-03), LUCENE-2247 = #3323 (uschindler), which moved the same sharing into the private CharArrayMap(CharArrayMap) copy constructor ('used internally for readonly maps...') and UnmodifiableCharArrayMap, and added the public CharArrayMap.unmodifiableMap and its map.isEmpty() -> emptyMap() shortcut [read]. Later commits on these lines (LUCENE-5512, LUCENE-5859, LUCENE-7329, LUCENE-9497, LUCENE-9570) did not change the sharing, the copied count or the rehash threshold [read]. Not a regression",
   "introduced_date": "2009-07-14 (ea7e4ad3443, LUCENE-1688); 2010-02-03 for the current CharArrayMap form, unmodifiableMap and the empty-set shortcut (924d7faa684, LUCENE-2247)",
   "first_affected_version": "2.9.0 [exec] (tagged 2009-09-24), the first release with CharArraySet.unmodifiableSet; 2.4.1 and earlier lack the API [exec]. CharArrayMap.unmodifiableMap and the empty-set shortcut are affected from 3.1.0, where they first appear [exec]",
   "affected_versions": "every release from 2.9.0 to 10.5.2, 10.6.0 (by reading) and main ea57360912ed; never fixed. [exec] the follow-up's history probe (with two controls that terminate on every version) fails on 2.9.0, 3.0.3, 3.1.0, 4.0.0, 6.6.6, 7.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main; the finder's JUnit fails 3 of 3 on main (-ea, -da), 10.5.2 and 9.12.3, and its main() probe fails on 8.11.4, 7.7.3, 5.5.5 and 4.10.4; the independent reproduction's JUnit fails 5 of 5 on main (-ea, -da), 10.5.2, 9.12.3 and 8.11.4. Other releases by unchanged line history [read]. Upstream main, branch_10x and branch_10_6 have not touched the copy constructor, unmodifiableMap or unmodifiableSet (CharArrayMap.java last changed 2025-10-10, a build change) [read]; open PR #16381 edits the copy constructor but keeps the sharing. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16381",
    "https://github.com/apache/lucene/issues/16261",
    "https://github.com/apache/lucene/issues/7687",
    "https://issues.apache.org/jira/browse/LUCENE-6629",
    "https://github.com/apache/lucene/issues/11866",
    "https://github.com/apache/lucene/issues/2762"
   ],
   "doc": "",
   "repro": "repro/LFV-485/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-326",
   "priority": "low",
   "priority_rank": 761,
   "novelty": "new",
   "withheld": false,
   "area": "monitor / concurrent candidate matchers (ParallelMatcher, PartitionMatcher)",
   "title": "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",
   "summary": "You register queries in a Monitor and match documents with ParallelMatcher or PartitionMatcher, which the package docs offer as a performance option, and one registered query throws an unchecked exception at match time, for example an IntPoint range query meeting a field indexed as LongPoint (IllegalArgumentException). You expect what the default serial matcher does: that query is reported in getErrors() and every other match is returned. Instead the worker threads catch only IOException, so Monitor.match throws RuntimeException('Interrupted during match') and the whole batch's matches are lost, and with ParallelMatcher, once every worker has died, the caller blocks forever in LinkedBlockingQueue.put (executed: 4 threads, one registered query with 4 failing disjuncts plus 1,100 other queries, still blocked after 20 s, 77 interrupts to stop).",
   "impact_class": "hang",
   "introduced_commit": "251dbe7cea8126cb7ecadc921ba444c63d06c618 on master and its identical branch_8x commit b8773d13ad8e249a045862249bf476c30a444461, 'LUCENE-8766: Add monitor subproject' by romseygeek (import of the Luwak library as lucene/monitor; JIRA LUCENE-8766 = apache/lucene#9811) [read]. The IOException-only worker catch, the bounded LinkedBlockingQueue(1024), the blocking queue.put and the 'Interrupted during match' wrapper are all in the first commit, as is the serial collector's catch (Exception e). No merged PR: the import PR apache/lucene-solr#648 was closed unmerged after the direct commit. The divergence already existed in the Luwak predecessor [read]",
   "introduced_date": "2019-06-13 (author and commit date of 251dbe7cea8 and b8773d13ad8)",
   "first_affected_version": "8.2.0 [exec] (first release with lucene-monitor; 8.1.1 has no monitor module: no lucene-monitor 8.1.1 artifact, compile_error against 8.1.1; on the master line the first release is 9.0.0)",
   "affected_versions": "Every lucene-monitor release: 8.2.0-8.11.4 (24), 9.0.0-9.12.3 (21) and 10.0.0-10.6.0 (13), 58 in total, plus main ea57360912ed and 645d4fe14a20. [exec] the follow-up's history matrix fails the minimal test on all 58 releases (-da; 8.2.0 also -ea) and on main 645d4fe14a20 (-ea and -da), and its ParallelMatcher hang probe hangs on 8.2.0, 10.6.0 and main 645d4fe14a20 (2026-10-31); the minimal test also fails on 10.6.0 with -ea; the follow-up's portable public-API repro fails on 8.2.0 (-ea and -da), 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); JUnit repro fails on 9.1.0, 9.12.3, 10.5.2 and main; the independent reproduction on main, 10.5.2 and 9.12.3 (-ea and -da); the intended-behaviour check on main (-ea and -da) and 10.5.2. [read] the introducing commit is in every release tag of the history clone from 8.2.0 (the 8.x tags up to 8.8.1 and all 34 from 9.0.0 to 10.6.0), and no later commit changes the behaviour. Not fixed: no open apache/lucene PR touches ParallelMatcher.java or PartitionMatcher.java (2026-10-26).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-326.html",
   "repro": "repro/LFV-326/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-513",
   "priority": "low",
   "priority_rank": 762,
   "novelty": "known",
   "withheld": false,
   "area": "monitor / bulk query loading (ConcurrentQueryLoader worker error handling)",
   "title": "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",
   "summary": "You bulk-load standing queries into a Monitor with the documented pattern, loader.add(q) in a loop inside try-with-resources, and Monitor.register fails inside the loader's worker threads, for example because the query index cannot fsync or create a file. You expect the load to stop and close() to throw the IOException, which the loader records for exactly that purpose. Instead each worker leaves its loop at its first failure and is never replaced, so once every worker is gone nothing drains the bounded queue: the next add() calls block in LinkedBlockingQueue.put forever, close() is never reached and the error is never reported (repro: 1 worker, queue size 4, one simulated fsync failure; add() is still blocked 30 s later).",
   "impact_class": "hang",
   "introduced_commit": "251dbe7cea8126cb7ecadc921ba444c63d06c618 (main, 2019-06-13, 'LUCENE-8766: Add monitor subproject', by GitHub romseygeek), with the branch_8x twin b8773d13ad8e249a045862249bf476c30a444461 shipped in 8.2.0 (git diff of ConcurrentQueryLoader.java between the two is empty); submitted as apache/lucene-solr#648, which GitHub shows closed unmerged because the code was committed directly; JIRA LUCENE-8766 (migrated as #9811). [read]. Not a regression. The structure (IOException caught outside the worker loop, blocking put in add()) predates Lucene: it is in the donated Luwak library from its commit 100c318d9e (2015-10-09), where a per-query error type was still caught inside the loop; the port dropped that inner catch, so any exception from register now ends a worker [read].",
   "introduced_date": "2019-06-13 (251dbe7cea8 on main and b8773d13ad8 on branch_8x)",
   "first_affected_version": "8.2.0 [exec] (the first lucene-monitor release); there is no unaffected earlier release: 8.1.1 has no monitor module (lucene-monitor 8.1.1 is not on Maven Central, HTTP 404)",
   "affected_versions": "Every release that ships lucene-monitor, 8.2.0 to 10.5.2 (the last release before 10.6.0), plus main ea57360912ed. [exec] the follow-up's portable JUnit 4 repro (failing Directory plugged in through the public MonitorConfiguration.buildIndexWriter override) fails on 8.2.0 (-ea and -da), 8.11.4, 9.0.0, 9.1.0, 9.2.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 and main, and passes with only ConcurrentQueryLoader replaced by the finder's fix on 8.2.0, 10.5.2 and main; the finder's JUnit fails on main (-ea and -da), 10.5.2, 9.12.3 and 9.2.0 (it does not compile against 9.1.0); the independent reproduction's JUnit fails 3 of 3 on main (-ea and -da), 10.5.2 and 9.12.3. [read] ConcurrentQueryLoader.java is one blob from 8.2.0 to 8.8.1 and one from 9.0.0 to 10.5.2; 8.3.0-8.11.3, 9.3.0-9.12.2 and 10.1.0-10.5.1 were not executed but carry the same source. Not fixed upstream (2026-10-26): Worker.run and add() are unchanged on main and branch_10x, and no open PR touches ConcurrentQueryLoader.java. Not executed: x86, and the JDK of each release's era (all runs used JDK 25.0.3).",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-9241",
    "https://github.com/apache/lucene/issues/10281",
    "https://github.com/apache/lucene/issues/604"
   ],
   "doc": "",
   "repro": "repro/LFV-513/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-552",
   "priority": "low",
   "priority_rank": 763,
   "novelty": "known",
   "withheld": false,
   "area": "monitor / read-only query index (ReadonlyQueryIndex background refresh)",
   "title": "A read-only Monitor's background refresh stops for good after one run throws an unchecked exception, and no error is reported",
   "summary": "You open a read-only Monitor over a query index that a writable Monitor updates, and count on its background thread to pick up the writer's changes at the configured purge frequency, which the upstream test TestMonitorReadonly.testReadonlyMonitorGetsRefreshed asserts. You expect a failed refresh run to be reported through MonitorUpdateListener.onPurgeError and the next run to try again, as the writable Monitor's purge task does. Instead the read-only task catches only IOException, so one unchecked exception (for example from an onPurge listener that throws once, or a ConcurrentModificationException when a listener is added while a run is calling the listeners) escapes the scheduled task, the executor silently cancels every later run, and the Monitor keeps matching its old query set with no error.",
   "impact_class": "minor",
   "introduced_commit": "be9917895645f99573833859e0c5c0d1cfc5b6d8 on main ('LUCENE-10422: Read-only monitor implementation (#679)', author GitHub mogui, merged by romseygeek; first released in 10.0.0), backported the same day to branch_9x as 72cf36a2b8d8811536b74e742c75bf33331dc923 with an identical ReadonlyQueryIndex.java (first released in 9.2.0) [read]. Inside the squash-merged PR, bcb9c0956815 (2022-03-01) added the refresh executor with catch (IOException) -> RuntimeException, and f3c6daa48082 (2022-03-15) made the task call purgeCache() with the onPurge listeners inside the try and routed IOException to onPurgeError, leaving the catch at IOException [read]. Before it, the Monitor's only background task (the writable purge, LUCENE-8766, 251dbe7cea81) caught Throwable, and #679 kept that for WritableQueryIndex.",
   "introduced_date": "2022-03-21 (merge of #679 on main and the branch_9x backport, same day)",
   "first_affected_version": "9.2.0 [exec] (the first release with the read-only Monitor; 9.1.0 has no ReadonlyQueryIndex and both repros fail to compile there)",
   "affected_versions": "Every release with the read-only Monitor: 9.2.0 to 9.12.3 (all 19 releases), 10.0.0 to 10.5.2 (all 12 releases) and 10.6.0 (released 2026-10-29; by reading), plus main ea57360912ed. [exec] the independent reproduction's JUnit (its 2 bug tests fail, its 2 controls pass) and the finder's JUnit fail on all 31 releases and main (seed DEADBEEF, -ea), also with -da on 9.2.0, 10.5.2 and main, and pass with catch (Throwable) shadowed into the ReadonlyQueryIndex of 9.2.0 and of main; a writable-Monitor control with the same throwing listener passes on 9.1.0, 9.2.0 and main. [read] upstream main a9779ef3c193 (2026-10-26), branch_10_6 and branch_10x still catch only IOException. Not affected: 8.2.0 to 9.1.0 (no read-only Monitor API). Not executed: x86; an OutOfMemoryError or another unchecked exception thrown by maybeRefresh().",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16847",
    "https://github.com/apache/lucene/issues/13948",
    "https://github.com/apache/lucene/issues/365",
    "https://github.com/apache/lucene/issues/13949",
    "https://github.com/apache/lucene/issues/16911",
    "https://github.com/apache/lucene/issues/16907"
   ],
   "doc": "",
   "repro": "repro/LFV-552/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1025",
   "priority": "low",
   "priority_rank": 764,
   "novelty": "known",
   "withheld": false,
   "area": "replicator / NRT segment replication (PrimaryNode.releaseCopyState, PrimaryNode.close)",
   "title": "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",
   "summary": "A replica takes primary.getCopyState(), then an I/O error while indexing (say, disk full while creating a stored-fields file) closes the primary's IndexWriter, the replica calls releaseCopyState as documented ('Called once replica is done (or failed) copying an NRT point'), and the application calls primary.close(); you expect close() to return (or throw), because no copy is in progress any more. Instead close() never returns: releaseCopyState first calls writer.decRefDeleter, which throws AlreadyClosedException, so the copyingCount.decrementAndGet() after it never runs, and close() loops in waitForAllRemotesToClose forever because the default remote-close timeout is -1 ('means forever'). Moving the decrement into a finally block makes close() return at once.",
   "impact_class": "hang",
   "introduced_commit": "1ae7291429bad742715344f86cfa5200229b3698 ('current patch', mikemccand; LUCENE-5438 'add near-real-time replication', migrated as GitHub #6501; first commit of branch jira/lucene-5438-nrt-replication, merged to main by 12b8721a44d; no GitHub PR) wrote releaseCopyState as decRefDeleter followed by the decrement with no finally, and waitForAllRemotesToClose as an unbounded loop on copyingCount [read]; present since the class was written. #11822 (f3d85be476c, first released in 9.5.0) only added the opt-in timeout with default -1 [read]",
   "introduced_date": "2016-01-24 (author date of 1ae7291429b; merged to main 2016-02-11 by 12b8721a44d)",
   "first_affected_version": "6.0.0 [exec]; 5.5.5 and earlier lack the API (no org.apache.lucene.replicator.nrt package) [exec]",
   "affected_versions": "every release from 6.0.0 to 10.5.2 (92 releases) [read]; executed affected: 6.0.0 (-ea, -da), 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4 (-ea, -da), 9.0.0, 9.1.0 (-ea, -da), 9.4.2, 9.5.0 (first release with setRemoteCloseTimeoutMs; its default -1 still hangs), 9.12.3 (-ea, -da), 10.0.0, 10.5.2 (-ea, -da) [exec]; main 645d4fe14a20 (-ea, -da) and ea57360912ed (-da) [exec]; unreleased branch_10x 657014b3c579 and the released 10.6.0 (RC1 4ae946e5a9b, 2026-10-29) [read]. Not affected: 5.5.5 and earlier (API absent) [exec]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/11674",
    "https://issues.apache.org/jira/browse/LUCENE-10638",
    "https://github.com/apache/lucene/issues/11822",
    "https://github.com/apache/lucene/issues/13045",
    "https://github.com/apache/lucene/issues/13142"
   ],
   "doc": "",
   "repro": "repro/LFV-1025/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-250",
   "priority": "low",
   "priority_rank": 765,
   "novelty": "known",
   "withheld": false,
   "area": "facet / taxonomy (SearcherTaxonomyManager.getRefCount and tryIncRef; the misuse guard in core ReferenceManager.acquire)",
   "title": "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",
   "summary": "You use SearcherTaxonomyManager and, through a bug in your own code, call decRef() or close() on the taxonomy reader of a pair you acquired (for example by wrapping pair.taxonomyReader() in try-with-resources), then release the pair as usual. Since LUCENE-5436 (4.7.0) the next acquire() is meant to detect such an outside reference-count change and throw IllegalStateException, which is what SearcherManager and the index-reader half of the same pair do. Instead acquire() retries forever in a busy loop, because SearcherTaxonomyManager.getRefCount reports only the index reader's count, so the guard never sees that the taxonomy reader is closed; only closing the manager ends the loop, with AlreadyClosedException.",
   "impact_class": "hang",
   "introduced_commit": "50ad64476ee696fedf29c1c6235a188f6dd75b7e (trunk, svn r1565429; backported to branch_4x as 1bc4419261dc, svn r1565430, the commit the 4.7.0 to 5.5.5 releases contain), 'LUCENE-5436: RefrenceManager#accquire can result in infinite loop if manager resource is abused outside of the manager' by s1monw, reviewed by mikemccand in the JIRA issue (now #6499), no pull request [read]. It is an incomplete fix, not a regression: the busy loop itself dates from 03694e76930 (LUCENE-3786, #4859, 'add SearcherTaxonomyManager', mikemccand, 2013-04-10), whose two-reader tryIncRef is unchanged since",
   "introduced_date": "2014-02-06 (50ad64476ee, the guard with the index-only getRefCount); the busy loop itself since 2013-04-10 (03694e76930)",
   "first_affected_version": "4.7.0 [exec] (tag 2014-02-25 in the history clone; the first release with the LUCENE-5436 guard, in which the index-reader case throws and the taxonomy-reader case still spins); 4.3.0 to 4.6.1 also spin [exec], but as the general pre-guard loop of every manager; 4.2.1 has no SearcherTaxonomyManager [exec]",
   "affected_versions": "every release from 4.7.0 through 10.5.2, and main ea57360912ed [read]; 4.3.0 to 4.6.1 also spin (pre-guard, every manager) [exec]; not fixed on main; the 10.6 branch and 10.6.0 (released 2026-10-29) were not checked",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/6499",
    "https://issues.apache.org/jira/browse/LUCENE-5436",
    "https://github.com/apache/lucene/issues/15985",
    "https://github.com/apache/lucene/issues/16152",
    "https://github.com/apache/lucene/issues/15068",
    "https://github.com/apache/lucene/issues/15112"
   ],
   "doc": "",
   "repro": "repro/LFV-250/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-384",
   "priority": "low",
   "priority_rank": 766,
   "novelty": "new",
   "withheld": false,
   "area": "util / OfflineSorter concurrent sort (partitionsInRAM permits on a rejected submit)",
   "title": "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)",
   "summary": "You give OfflineSorter your own bounded thread pool, one sort() fails with RejectedExecutionException because the pool was full (or shut down), and you expect the same sorter to work again once the pool is idle, since every other exception path gives the partition's partitionsInRAM permit back. Instead the permit that readPartition took for the rejected partition is never released (only the task's finally block releases it, and a rejected task never runs; the semaphore belongs to the sorter instance), so with maxPartitionsInRAM = 1 the next sort() on that sorter waits forever in Semaphore.acquire with an idle executor (executed: 'sort() did not return within 20 s; waiting for a partition permit: true; executor active=0 queued=0'). With maxPartitionsInRAM = k each rejection costs one permit and after k rejections every later sort() hangs; with a shut-down executor, a call that should fail fast with RejectedExecutionException waits instead.",
   "impact_class": "hang",
   "introduced_commit": "db92a9efc2ee (LUCENE-7792 'add optional concurrency to OfflineSorter', by GitHub mikemccand, master; branch_6x backport bb8dd7a9f98d; committed from JIRA patches, no GitHub PR; the issue is now #8843) [read]",
   "introduced_date": "2017-04-26",
   "first_affected_version": "6.6.0 [exec] (first release with the ExecutorService constructor, via the branch_6x backport; 7.0.0 [exec] is the first from the master line; 6.5.1 has no such constructor, executed compile_error)",
   "affected_versions": "every release that has the ExecutorService constructor, 6.6.0 through 10.5.2, plus main ea57360912ed (not fixed; upstream main e1c4184cb98 of 2026-10-26 still has the unguarded submit [read]), and only with a non-null executor that rejects. Executed with the finder repro (1 of 2 tests fails, the no-rejection reuse control passes): 6.6.0 (-ea and -da), 6.6.6, 7.0.0, 7.7.3, 8.11.2, 8.11.4, 9.0.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) [exec]; the independent reproduction's own public-API test fails 3 of 4 on main (-ea and -da), 10.5.2, 9.12.3, 8.11.2 and 6.6.0 [exec]; the releases between the executed ones are inferred: git log -L shows the submit lines in sort() untouched since db92a9efc2e [read] (the 8.9.0 to 8.11.4 tags are not in the history clone; those jars came from the release cache)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-384.html",
   "repro": "repro/LFV-384/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-633",
   "priority": "low",
   "priority_rank": 767,
   "novelty": "new",
   "withheld": false,
   "area": "classification / ConfusionMatrixGenerator (classifier evaluation utility)",
   "title": "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",
   "summary": "You evaluate a classifier with ConfusionMatrixGenerator.getConfusionMatrix and one document's classification is slow (more than about 10 s) or hangs. You expect, as the code's own comment ('fail if classification takes more than 5s') and its skip-and-continue timeout branch intend, that only that document counts as a timeout and the other documents are still classified and counted. Instead the timed-out classification is never cancelled and keeps the generator's only worker thread, so the next documents wait behind it, their own 5 s waits expire while they are still queued, and they are dropped too: with a hung first document 0 of 2 instantly classifiable documents are counted (empty matrix, average time Infinity), with a 12 s one 1 of 2.",
   "impact_class": "minor",
   "introduced_commit": "8b2e0d937d58470edac86135c602ef70356c68b3 (LUCENE-6479 'improved cm testing, added stats, minor fixes', svn r1700914, by tteofili; SVN era, no pull request; issue migrated as apache/lucene#7538) [exec]. Related later commits: 9e340d3e82f (2015-09-03, NamedThreadFactory 'confusion-matrix-gen-', no logic change); 2507015f4c9 on master / 646081c3dd5 on branch_6x (LUCENE-7193, 2016-04-08, 6.1.0: the aggregate timeoutMilliseconds and numberOfEvaluatedDocs counting classified documents; defect unchanged, symptom changes)",
   "introduced_date": "2015-09-02 (the LUCENE-7193 change that altered the symptom: 2016-04-08)",
   "first_affected_version": "6.0.0 [exec] (the first release with ConfusionMatrixGenerator; 5.5.5 has no such class [exec], so no release ever had the API without the defect)",
   "affected_versions": "every release with the API, 6.0.0 through 10.5.2, and main a9779ef3c193.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-633.html",
   "repro": "repro/LFV-633/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-252",
   "priority": "low",
   "priority_rank": 768,
   "novelty": "new",
   "withheld": false,
   "area": "search / ControlledRealTimeReopenThread (NRT generation tracking: close(), the HandleRefresh refresh listener, waitForGeneration)",
   "title": "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",
   "summary": "You use a ControlledRealTimeReopenThread with a SearcherManager, close the reopen thread (for example at shutdown), the application refreshes the still-open manager once more, and a request thread that still holds the closed instance calls waitForGeneration(gen) for its own new change. You expect the call to return, because close() sets the searching generation to Long.MAX_VALUE 'so any waiting search threads will return', the method's @return says it returns when 'this instance was closed', and a wait with no refresh in between does return at once. Instead the HandleRefresh listener that the constructor registered on the manager is never removed, so that one refresh writes the writer's generation back over Long.MAX_VALUE, and the untimed wait blocks until some later refresh covers gen, which never comes once the manager is closed; only an interrupt or a second close() releases the thread.",
   "impact_class": "hang",
   "introduced_commit": "7b90561178d5ab8ca5a165e8f7a3a1e0da48b205 (trunk, svn r1478438; branch_4x 79ee60d41bcc, svn r1478446, the commit the 4.4.0 release contains), 'LUCENE-4967: move NRTManager entirely into a reopen thread so it can interact with any ReferenceManager' by mikemccand (JIRA LUCENE-4967, now #6031, no pull request; its comments do not discuss close semantics or listener removal) [read]. It replaced NRTManager, whose refresh hook kept the closed generation ('if (searchingGen != MAX_SEARCHER_GEN)', LUCENE-3776, 9da52f43527; the sentinel itself from LUCENE-3528, 57461996e2f), with a listener on an external manager that has no such guard; the history does not show whether dropping the guard was deliberate. LUCENE-9304 (18af6325ed9, lucene-solr PR #1427, 8.6.0) moved the generation capture into beforeRefresh, which changed the hang from permanent to 'until the next refresh that covers the target'",
   "introduced_date": "2013-05-02",
   "first_affected_version": "4.4.0 [exec] (tag 2013-07-22; the first release with ControlledRealTimeReopenThread: a public-API port fails with -ea and -da and its no-refresh control passes); 4.3.1 has no such API [exec], and the analogous probe on its predecessor NRTManager passes [exec]",
   "affected_versions": "every release from 4.4.0 through 10.6.0 and main ea57360912ed and 645d4fe14a20. [exec] fail, every control passes: 4.4.0 (-ea and -da), 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.5.2, 8.6.0, 8.11.4, 9.0.0, 9.12.3 (-ea and -da), 10.5.2 (-ea and -da) and main (-ea and -da) with the follow-up's history ports; the finder's JUnit on main (-ea, -da, 5 of 5 with --iters 5), 10.5.2, 9.12.3, 9.0.0 and 8.11.4; the independent reproduction's JUnit on main (-ea, -da, 20 of 20 with --iters 10), 10.5.2 and 9.12.3. [read] all 115 release tags from 4.4.0 to 10.5.2 in the history clone have the one addListener(new HandleRefresh()), no removeListener, the unconditional 'searchingGen = refreshStartGen' and the MAX write in close(). Two eras: 4.4.0-8.5.2, later refreshes write back the same stale generation, so the wait never ends however often the manager is refreshed [exec]; 8.6.0-main (LUCENE-9304), the next refresh that covers the target releases it [exec]. Not fixed on main: the minimal test fails on main 645d4fe14a20 with -ea and -da and on the 10.6.0 release jars (released 2026-10-29) with -ea, its constructor adapted to 10.6.0's double seconds [exec]; the 10.6.0 tag, branch_10_6 7e5aec4370e, branch_11x 603af870375 and upstream main 2f424fd428d carry the same code [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-252.html",
   "repro": "repro/LFV-252/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-364",
   "priority": "low",
   "priority_rank": 769,
   "novelty": "known",
   "withheld": false,
   "area": "util / automaton (RegExp, Operations.repeat; reached from RegexpQuery and the classic and flexible query parsers)",
   "title": "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 '+'",
   "summary": "You build a RegexpQuery for 'ab' followed by n '+' (directly, or by typing /ab+++.../ into the classic or flexible query parser) and expect a tiny automaton, because '+' means one or more occurrences, so the language is just ab+ (3 states, which is what 9.12.3 builds for any n). Instead the automaton doubles with every '+' (2^n+2 states: 16,386 at n=14, 262,146 at n=18), because RegExp turns each '+' into Operations.repeat(a, 1), which is built as a followed by a* and so copies a, and since 10.0 nothing minimizes in between; with a 1 GB heap about 20 '+' (a 22-character regexp) end in OutOfMemoryError while the query is still being constructed. Stacked {1,} and nested ((x)+)+ double the same way; stacked '*' and '?' do not.",
   "impact_class": "crash",
   "introduced_commit": "84e4b85b094ccf2dc248ad90a302307d3618b81e, LUCENE-10010 'don't determinize/minimize in RegExp' (PR #513, by rmuir; JIRA LUCENE-10010 is GitHub issue #11049, still open) [exec]. It removed MinimizationOperations.minimize after every RegExp parsing step and the REGEXP_REPEAT_MIN size pre-check ((numStates - 1) * min > determinizeWorkLimit -> TooComplexToDeterminizeException). The two pieces that now double were already there and stayed harmless while every step was minimized: parseRepeatExp maps '+' to makeRepeat(e, 1) (unchanged since the 2010 import b679816a7001), and Operations.repeat(a, count) concatenates count copies of a with repeat(a) (be3cca1e4440 / ba56e757045b, 2014)",
   "introduced_date": "2021-12-07 (commit date; merged into main 2021-12-08 UTC)",
   "first_affected_version": "10.0.0 [exec] (9.12.3 is the last unaffected release [exec]; the 9.x line split from main on 2021-11-02, five weeks before the commit, and the change, a 10.0 API break, was never backported [read])",
   "affected_versions": "every release from 10.0.0 through 10.5.2, and main ea57360912ed. Executed, affected: 10.0.0, 10.1.0, 10.2.0, 10.2.2, 10.3.2, 10.4.0, 10.5.0, 10.5.2 and main (JUnit or probe), and commit 84e4b85b094; 10.2.1, 10.3.0, 10.3.1 and 10.5.1 were not run but contain the commit (git tag --contains) and no later commit restores the per-step minimize [read]. Executed, not affected: 8.11.4, 9.0.0, 9.12.3 and the parent commit 5a1fdd88650 (3 states for any n). State counts: 3*2^n+1 at the introducing commit, 2^n+n+2 in 10.0.0 and 10.1.0 (after #13714), 2^n+2 from 10.2.0 on. With a 1 GB heap: 10.0.0 builds n=20 (1,048,598 states, 20,971,713 transitions) and then rejects it with TooComplexToDeterminizeException, OutOfMemoryError from n=22; 10.5.2 rejects n=14..18 after building the automaton and runs out of memory from n=20; main accepts n=14..19 (#15939, unreleased, removed RegexpQuery's determinize limit) and runs out of memory from n=20. Not fixed upstream: no commit to RegExp.java (latest 2026-07-31) or Operations.java (latest 2026-06-14) on main or branch_10x addresses repeat(a, 1) [read]. All runs: OpenJDK 25.0.3, Linux aarch64",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/513",
    "https://github.com/apache/lucene/issues/8970",
    "https://issues.apache.org/jira/browse/LUCENE-7921",
    "https://github.com/apache/lucene/issues/7108",
    "https://issues.apache.org/jira/browse/LUCENE-6046",
    "https://github.com/apache/lucene/issues/13714"
   ],
   "doc": "",
   "repro": "repro/LFV-364/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-962",
   "priority": "low",
   "priority_rank": 770,
   "novelty": "known",
   "withheld": false,
   "area": "util / automaton (RegExp, Operations.concatenate; reached from RegexpQuery and the classic and flexible query parsers)",
   "title": "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)",
   "summary": "You build a RegexpQuery, directly or by typing /regexp/ syntax into the classic or flexible query parser, for a regexp with a long run of the same nullable atom, for example 'a' followed by 1,000 copies of '.*' and then 'b', and expect an automaton about as small as its language a.*b (4 states, which is what 10.5.2 keeps and what WildcardQuery builds for a run of '*' since #16382). Instead Operations.concatenate gives every accept state a link to each following piece for as long as those pieces accept the empty string, so the run gets about n^2/2 transitions (502,502 here), and on main, where RegexpQuery no longer determinizes (#15939), the query keeps that automaton: ramBytesUsed 170 MB, about 3 s to build, and OutOfMemoryError under a 1 GB heap from about 4,000 characters. The same happens for x?, x*, [a-z]*, (ab)*, (bc)? and [^x]*; search results are always correct, and released versions pay the quadratic cost only while building (OutOfMemoryError at about 12,000 characters under 1 GB, or a TooComplexToDeterminizeException for 447 'x?' in a row).",
   "impact_class": "crash",
   "introduced_commit": "b679816a7001ba986618f103a9a9c67ececc7ff8 'LUCENE-2370: Reintegrate flex_1458 branch into trunk' (2010-04-06) for the quadratic construction: the first commit in the history with the automaton package (code from LUCENE-1606 = apache/lucene#2680, a dk.brics.automaton port resolved 2009-12-09 on the flex branch, whose own commits are not in the history); BasicOperations.concatenate(List) already re-adds accept states through nullable pieces there [read]. Carried, not caused, by LUCENE-5752 (46132142cc2, 2014-06-20, 4.10.0; 4.9.1 and 4.10.0 both give 500,500 [exec]). Exposed in RegExp.toAutomaton by 84e4b85b094ccf2dc248ad90a302307d3618b81e, apache/lucene#513 'LUCENE-10010: don't determinize/minimize in RegExp' (rmuir, 10.0.0) [exec]. Headline symptom, RegexpQuery keeping the quadratic automaton: 650684e6b440e0b85d3c51b3cf546c1b757975fe, apache/lucene#15939 'remove implicit determinization from RegexpQuery' (rmuir, co-author drempapis; main only, milestone 11.0.0) [read]",
   "introduced_date": "2010-04-06 (root, trunk import; LUCENE-1606 resolved 2009-12-09); 2021-12-08 (#513 merged, RegExp output exposed, 10.0.0); 2026-04-12 (#15939 authored and merged, retention on main)",
   "first_affected_version": "4.0.0-alpha [exec] for the quadratic construction (transient while RegExp minimized, 4.0.0-alpha to 9.12.3; no 3.x release has org.apache.lucene.util.automaton, 3.6.2 executed: compile error); 10.0.0 [exec] for RegExp.toAutomaton() returning the quadratic automaton; no release for the retained RegexpQuery automaton (main 11.0.0-SNAPSHOT only; branch_10_6 4ae946e5a9b not affected [exec])",
   "affected_versions": "Quadratic Operations/BasicOperations.concatenate (1,000 any-string pieces give 500,500 transitions): every release from 4.0.0-alpha to 10.6.0 (branch_10_6 4ae946e5a9b) and main a9779ef3c193; executed on 4.0.0-ALPHA, 4.0.0, 4.9.1, 4.10.0, 5.5.5, 8.11.4, 9.12.3, 10.0.0, 10.5.2, branch_10_6 and main, all 500,500 [exec]; other releases inferred from code (the accumulating loop is unchanged from 4.0.0-alpha to 4.9.1 and the LUCENE-5752 'Keep chaining' loop from 4.10.0 to main) [read]. RegExp.toAutomaton() for a(.*)^1000b: 3 states / 7 transitions on 4.0.0, 8.11.4 and 9.12.3 (minimized), 1,004 / 502,503 on 10.0.0, 1,003 / 502,502 on 10.5.2, branch_10_6 and main [exec]. RegexpQuery and both parsers keep the quadratic automaton on main only (502,502 transitions, ramBytesUsed 170,012,154 bytes; finder's JUnit 7 of 7 fail with -ea and -da) [exec]; 9.12.3, 10.0.0, 10.5.2 and branch_10_6 keep a small query automaton but fail 3 of 7 (concatenate; TooComplexToDeterminizeException for the x? and (bc)? runs) [exec], and run out of a 1 GB heap at a.*^6000b (12,002 characters) on 9.12.3 and 10.5.2 [exec]. 10.6.0 was tagged at 4ae946e5a9b and released on 2026-10-29 (no tag yet when checked on 2026-10-28). Not fixed upstream: the last commits touching RegExp.java, Operations.java and RegexpQuery.java on upstream main are #16371 (2026-07-31), #16255 (2026-06-14) and #15939 (2026-04-12); upstream head 645d4fe14a20 (authored 2026-10-28) is unrelated (re-checked 2026-10-28). All runs on Linux aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16134",
    "https://github.com/apache/lucene/issues/16382",
    "https://github.com/apache/lucene/issues/16384",
    "https://github.com/apache/lucene/issues/16402",
    "https://github.com/apache/lucene/issues/14350",
    "https://github.com/apache/lucene/issues/14389"
   ],
   "doc": "",
   "repro": "repro/LFV-962/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-926",
   "priority": "low",
   "priority_rank": 771,
   "novelty": "known",
   "withheld": false,
   "area": "queryparser / classic (generated JavaCC parser QueryParser.jj and QueryParserBase.parse)",
   "title": "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)",
   "summary": "You parse a valid query with many nested groups, for example \"(\".repeat(d) + \"a\" + \")\".repeat(d), with the classic QueryParser.parse(String), which documents '@throws ParseException if the parsing fails' and already turns the generated lexer's TokenMgrError (a java.lang.Error) and clause-limit hits into ParseException, and you expect the query (here just f:a) or a ParseException. Instead the generated recursive-descent grammar calls Query -> Clause -> Query once per '(' with no depth bound, the thread runs out of stack, and java.lang.StackOverflowError escapes parse. On a cold JVM about 2,650 levels (5,331 chars) are enough at -Xss1m and about 5,900 on the 2 MB aarch64 default stack, while the same 100,000-level input parses to f:a on a 256 MB stack.",
   "impact_class": "wrong error",
   "introduced_commit": "bd3948c539ec1065db8b05b433ea55dbf844ff27 ('Initial revision', 2001-09-18, svn r149570: the import of the pre-existing Lucene CVS tree, committed by Jason van Zyl; the code predates the import; no issue, patch or PR). Both halves are in this first commit: the grammar 'Clause ::= [\"+\", \"-\"] [<TERM> \":\"] ( <TERM> | \"(\" Query \")\" )' generated as Query() -> Clause() -> '<LPAREN> q=Query(field) <RPAREN>' -> Query() with no depth bound, and a parse(String) that catches nothing. The current contract (parse documents and throws only ParseException, converting the lexer's TokenMgrError) took its form in 1a39c55c4c4 (2003-11-13, 'only throw ParseException from parse methods'), after LUCENE-14 (#1092) and 2a96b329a81 (2002-05-06); neither it nor any later commit catches StackOverflowError or bounds the depth. Not a regression. [read]",
   "introduced_date": "2001-09-18 (import commit bd3948c539ec; the code predates it); current parse() contract 2003-11-13 (1a39c55c4c4)",
   "first_affected_version": "1.0.1 [read]; 1.2 is the oldest executed release [exec]; no unaffected release exists",
   "affected_versions": "every release that ships the classic QueryParser, 1.0.1 through 10.5.2 (the last release before 10.6.0), plus 10.6.0 (branch_10_6 4ae946e5a9b9, the RC1 revision) and main a9779ef3c193; not fixed upstream (main c5ab3e57b9ba, 2026-10-28). [exec] the version-history runs's version-independent main() probe (100,000 nested '(' and '+(' groups on the default thread stack; controls 'a', 50 nested groups and '(a' behave) is affected in 48 of 48 runs: 1.2, 1.3-rc1, 1.3, 1.4.3, 1.9.1, 2.0.0, 2.4.1, 2.9.4, 3.0.3, 3.1.0, 3.6.2, 4.0.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main, each with -ea and -da; the finder's JUnit fails 3 of 3 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) and on branch_10_6 (-da); the independent reproduction's JUnit fails 3 of 5 on 9.12.3, 10.5.2 and main (-ea and -da). [read] all 165 release tags in the history clone have the unbounded recursion and no StackOverflowError handling or depth guard. Subclasses: MultiFieldQueryParser (finder's JUnit, 9.1.0 to main), ComplexPhraseQueryParser and ExtendableQueryParser (the independent reproduction's JUnit on 9.12.3, 10.5.2 and main; finder's depth sweep on main). JDK 25.0.3 on Linux aarch64 only, not each release's own JDK; x86_64 not run.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/11687",
    "https://github.com/apache/lucene/issues/16423",
    "https://github.com/apache/lucene/issues/7218",
    "https://github.com/apache/lucene/issues/752",
    "https://github.com/apache/lucene/issues/12462",
    "https://github.com/apache/lucene/issues/11510"
   ],
   "doc": "",
   "repro": "repro/LFV-926/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-924",
   "priority": "low",
   "priority_rank": 772,
   "novelty": "known",
   "withheld": false,
   "area": "queryparser / simple (SimpleQueryParser.parseSubQuery / consumeSubQuery recursion)",
   "title": "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",
   "summary": "You give SimpleQueryParser, the parser meant for raw human-entered text, a query with many balanced nested groups, for example \"(\".repeat(d) + \"a\" + \")\".repeat(d), and expect a Query: its class javadoc says a person can type whatever they want and the parser will do its best to interpret it no matter how poorly composed, parse(String) declares no exception, and at small depths the same input parses to the plain TermQuery f:a. Instead parseSubQuery calls consumeSubQuery for every '(' and consumeSubQuery calls parseSubQuery again on the inner text, one frame pair per level with no depth bound, so a few thousand to about 25,000 levels (about 500 on a 256 KB stack), depending on stack size and JIT state, exhaust the thread stack and java.lang.StackOverflowError escapes parse. The clause limit does not help, because the nested groups collapse to a single clause.",
   "impact_class": "wrong error",
   "introduced_commit": "3c9e753df6477edc0047e6c1951c4bb9e758e007 (trunk, 'LUCENE-5336: add SimpleQueryParser for human-entered queries', svn r1541151; committed by GitHub rmuir, CHANGES credits 'Jack Conradson via Robert Muir' (GitHub jdconrad); issue LUCENE-5336 = apache/lucene#6400; no pull request, pre-GitHub) and its same-day branch_4x backport 64e591e1b7a84223aa2853fa5045ba6741b38909 (svn r1541158, byte-identical SimpleQueryParser.java), which is the commit that reached 4.7.0. Born with the class: the parseSubQuery -> consumeSubQuery -> parseSubQuery(new State(...)) recursion with no depth bound is in the first version [read]; not a regression; no bisect needed (the API and the bug arrive in the same commit)",
   "introduced_date": "2013-11-12 (3c9e753df64 trunk and 64e591e1b7a branch_4x)",
   "first_affected_version": "4.7.0 [exec] (tag 2014-02-25; the first release with SimpleQueryParser); 4.6.1, the last release before it, has no org.apache.lucene.queryparser.simple package [exec], so no unaffected release has the API",
   "affected_versions": "every release that has SimpleQueryParser, 4.7.0 to 10.5.2, plus 10.6.0 (branch_10_6 4ae946e5a9b9, the RC1 revision) and main a9779ef3c193 (unreleased 11.0) [exec]; the other releases by code identity [read]. Not fixed upstream: upstream main c5ab3e57b9ba (author date 2026-10-28) is 5 commits past a9779ef3c193 with no change under lucene/queryparser, the last commit on SimpleQueryParser.java is df6f71a3729 (2026-09-25, formatter), and no open apache/lucene PR touches lucene/queryparser/.../simple/ [read]. Executed on Linux aarch64 with JDK 25 only.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/11687",
    "https://issues.apache.org/jira/browse/LUCENE-10651"
   ],
   "doc": "",
   "repro": "repro/LFV-924/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-965",
   "priority": "low",
   "priority_rank": 773,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / xml (CoreParser, QueryBuilderFactory and SpanQueryBuilderFactory with the compound and span builders, DOMUtils)",
   "title": "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)",
   "summary": "You give the XML query parser a well-formed query whose elements nest a few thousand levels deep, for example <BooleanQuery><Clause occurs=\"must\"> repeated 3,000 times around one <TermQuery> (about 180 KB; enough on a 1 MB thread stack, while the 2 MB aarch64 default needs 5,000 or more levels), which the shipped DTD allows ('queries/filters of an arbitrary depth and complexity') and which parses fine at 40 levels, and you expect a Query or the ParserException that CoreParser.parse(InputStream), getQuery(Element) and getSpanQuery(Element) declare. Instead java.lang.StackOverflowError escapes, because each compound builder (BooleanQuery, DisjunctionMaxQuery, ConstantScoreQuery and the span builders) calls back into QueryBuilderFactory or SpanQueryBuilderFactory once per nesting level and nothing counts the depth or turns the Error into a ParserException. Whether the plain text path fails depends on the JDK, not on Lucene: JDK 21, the minimum for 10.x including the 10.6.0 RC, has no XML element-depth limit by default and overflows, while JDK 25 (main's minimum) rejects more than 100 nested elements with a ParserException; the DOM entries overflow on every JDK.",
   "impact_class": "wrong error",
   "introduced_commit": "87768c51c632a3eefd0e78836d900ced46f0e10e (Subversion r380874, 2006-02-25, 'Added XML-query-parser module for new extensible query parser that handles queries expressed as XML ...', the module's original contribution; the message names no JIRA issue and there is no pull request). The unbounded recursion was born with the parser and is not a regression [read]",
   "introduced_date": "2006-02-25 (author date of 87768c51c632, r380874)",
   "first_affected_version": "1.9.1 [exec] (2006-03-02, the first published artifact of the XML query parser, executed with the nested SpanOr shape); the 1.9 final source tag (2006-02-27) already contains the recursion [read]; 1.9-rc1 has no XML query parser",
   "affected_versions": "Every release from 1.9.1 to 10.6.0 (branch_10_6 head 4ae946e5a9b9, the RC1 commit) and main a9779ef3c193; which entry fails depends on the JDK's XML parser, not on the Lucene version. [exec] the probe of the version-history runs (depth 100,000, -da) on 1.9.1 (SpanOr), 2.1.0, 3.6.2, 4.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (BooleanQuery and SpanOr), the RC and main (BooleanQuery and SpanOr): getQuery(Element) overflows on JDK 25.0.3 and JDK 21.0.10; parse(InputStream) overflows on JDK 21.0.10 and gives ParserException on JDK 25.0.3 (main was run on JDK 25 only). The finder's JUnit fails on main (-ea and -da: DOM leg; with xercesImpl 2.12.2 as the JAXP implementation also the XML leg), on the RC and 10.5.2 (JDK 25 -ea/-da: DOM leg; JDK 21 -ea/-da: both legs) and on 9.12.3 (JDK 25 -da: DOM leg; JDK 17.0.21 and 21.0.10 -da: both legs); the independent reproduction's own JUnit agrees on main, the RC, 10.5.2 and 9.12.3; the intended-behaviour check re-ran main (-ea, -da, and -Djdk.xml.maxElementDepth=0: both legs) and 10.5.2 (JDK 25 -da); the adjudication re-ran main; the registration check re-ran main and the RC (JDK 25 -da). The JDK 21 and 17 legs were run by re-running repro.sh's generated command with only the JDK binaries swapped (repro.sh is pinned to JDK 25). [read] the recursion is unchanged since 87768c51c632; releases not listed were not executed; on 1.9.1-2.0.0 the BooleanQuery shape is not usable as evidence (a separate getElementsByTagName defect, fixed in 6c53bc3c497 for 2.1.0, runs out of heap first), so 1.9.1 was run with SpanOr. Which JDK release first shipped the element-depth default of 100 was not determined. Not fixed upstream: the queryparser/xml directory is unchanged since dbf0d1426f13 (#16056, 2026-05-14) on upstream main 645d4fe14a20 (2026-10-28), branch_10_6 4ae946e5a9b9, branch_10x and branch_11x. All runs on Linux aarch64; x86_64 thresholds not measured.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-965.html",
   "repro": "repro/LFV-965/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-919",
   "priority": "low",
   "priority_rank": 774,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / surround (generated JavaCC parser, QueryParser.jj)",
   "title": "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)",
   "summary": "You call the surround parser's documented entry point QueryParser.parse(String), which declares only ParseException and already turns the lexer's TokenMgrError (an Error) into a ParseException, on a valid query with many nested groups, for example \"(\".repeat(d) + \"a\" + \")\".repeat(d) or a long chain of \"(a OR \" groups, and expect a query or a ParseException. Instead the generated recursive-descent grammar, which spends seven frames per \"(\" (FieldsQuery -> OrQuery -> AndQuery -> NotQuery -> NQuery -> WQuery -> PrimaryQuery -> FieldsQuery) and has no depth bound, runs out of stack and java.lang.StackOverflowError escapes parse, so a caller that handles ParseException gets an undeclared Error. On a 1 MB thread stack as few as about 740 nested groups (1,473 chars) are enough on the first deep parse, and an 800-term chain of parenthesised binary ORs (7,884 chars, under the module's 1024-basic-query limit) fails even after JIT warm-up.",
   "impact_class": "wrong error",
   "introduced_commit": "9d70229506f88d3259ba0d24a824c0dbadc52c8e (trunk, '#34331 - Add Paul Elschot's Surround query language parser', svn r209183, the surround parser's first commit; contribution LUCENE-368 = #1446, no pull request): both halves are already there in their current form, parse2 catching only TokenMgrError and the FieldsQuery ... PrimaryQuery('(' FieldsQuery ')') cycle (plus PrefixOperatorQuery -> FieldsQueryList -> FieldsQuery) with no depth bound [read]; not a regression: the bug is as old as the parser",
   "introduced_date": "2005-07-05 (trunk 9d70229506f); first release 1.9 (2006-02-27)",
   "first_affected_version": "1.9 [read]; 1.9.1 [exec] is the first executed release; 1.4.3 and earlier have no surround parser [read]",
   "affected_versions": "every release that ships the surround parser, 1.9 to 10.5.2, plus 10.6.0 (branch_10_6 4ae946e5a9b9, the RC1 revision) and main a9779ef3c193 (unreleased 11.0) [exec]; the other releases by code identity [read]. Not fixed upstream: upstream main c5ab3e57b9ba (2026-10-28) has no change under lucene/queryparser after a9779ef3c193, and the surround parser directory was last changed on main on 2026-02-01 (whitespace) [read]. Executed on Linux aarch64 with JDK 25 only; x86_64 was not run.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-919.html",
   "repro": "repro/LFV-919/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-949",
   "priority": "low",
   "priority_rank": 775,
   "novelty": "known",
   "withheld": false,
   "area": "core / geo GeoJSON parsing (Polygon.fromGeoJSON, SimpleGeoJSONPolygonParser)",
   "title": "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)",
   "summary": "You call Polygon.fromGeoJSON on a valid GeoJSON Feature whose properties hold an array nested 10,000 levels deep (about 20 KB of text), or on malformed text with thousands of unterminated '[', and expect the polygon back, or the method's declared ParseException for bad or too-deep input. Instead java.lang.StackOverflowError escapes, because SimpleGeoJSONPolygonParser.parseObject and parseArray call each other once per nesting level with no depth limit and nothing turns the Error into a ParseException. The caller has no limit it can set, and a plain length cap does not help, because 20 KB already fails while real polygons are often longer.",
   "impact_class": "wrong error",
   "introduced_commit": "343f374b530fa71dc6102d74725b536f5f1367f3 (main line, 2016-07-15, 'LUCENE-7380: add Polygon.fromGeoJSON', committed by mikemccand after a +1 from rmuir; LUCENE-7380 is apache/lucene#8433; JIRA patch era, no pull request; first shipped in 7.0.0) and its branch_6x backport 573aaf75f52f446c8b7ab915eefd420013c544a1 (same message, shipped in 6.2.0). The unbounded recursion was born with the parser and is not a regression [read]",
   "introduced_date": "2016-07-15 (author and commit date of 343f374b530 and 573aaf75f52, 10:51:08 -0400; JIRA resolved the same day)",
   "first_affected_version": "6.2.0 [exec] (the first release with Polygon.fromGeoJSON and SimpleGeoJSONPolygonParser; 6.1.0 has Polygon but no fromGeoJSON, and 5.5.3-6.0.1 have no org.apache.lucene.geo.Polygon [exec]); first 7.x release 7.0.0 [exec], from the main-line commit",
   "affected_versions": "Every release from 6.2.0 to 10.6.0 (89 releases to 10.5.2, and 10.6.0 run as its release revision, branch_10_6 head 4ae946e5a9b9) and main a9779ef3c193. [exec] the version-portable public-API driver of the version-history runs fails 3 of 3 deep cases (valid Feature with an array property, valid Feature with an object property, unterminated arrays; 50,000 levels on a 1 MiB thread stack, -da, seed 383DEE9) with every shallow control passing on all 89 releases, branch_10_6 and main, and with -ea on 6.2.0, 10.5.2 and main; with the depth-guard fix shadowed into main it passes 3 of 3. The finder's JUnit fails 3 of 3 on main (-ea and -da), branch_10_6, 10.5.2 and 9.12.3 (-da), and the history step re-ran it with -ea on 10.5.2 and 9.12.3 (3 of 3); the independent reproduction's own JUnit fails 3 of 4 (control passes) on main (-ea and -da), 10.5.2 (-ea and -da) and 9.12.3 (-da); the intended-behaviour check re-ran the finder's JUnit on main (-ea and -da) and 10.5.2 (-da); the adjudication on main (-ea and -da); the registration check on main (-da, seed 5EED0383, 3 of 3). On the 2040 KiB default stack, 10,000 levels fail 3 of 3 on 10.5.2 and main, while 6.2.0 fails only the unterminated case at 10,000 and all three at 20,000 (cause of the version difference not investigated). [read] the recursion is unchanged since 343f374b530; 8.8.2-8.11.4 are untagged in the history clone and were covered by execution. Not fixed upstream: upstream main 645d4fe14a20 (2026-10-28) has no commit on SimpleGeoJSONPolygonParser.java after 448c7d8e241 (2026-02-11, a toArray refactor). All runs on Linux aarch64 with JDK 25.0.3; x86 thresholds not measured.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16423",
    "https://github.com/apache/lucene/issues/10007",
    "https://issues.apache.org/jira/browse/LUCENE-8964",
    "https://github.com/apache/lucene/issues/8433",
    "https://issues.apache.org/jira/browse/LUCENE-7380",
    "https://github.com/apache/lucene/issues/11687"
   ],
   "doc": "bugs/LFV-949.html",
   "repro": "repro/LFV-949/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-954",
   "priority": "low",
   "priority_rank": 776,
   "novelty": "known",
   "withheld": false,
   "area": "core / geo WKT parsing (SimpleWKTShapeParser)",
   "title": "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)",
   "summary": "You call SimpleWKTShapeParser.parse on a GEOMETRYCOLLECTION that holds a GEOMETRYCOLLECTION, and so on 10,000 levels deep (about 210 KB of valid WKT), or on the same text left unterminated, and expect the nested Object[] result, or the method's declared ParseException for bad or too-deep input. Instead java.lang.StackOverflowError escapes, because parseGeometry and parseGeometryCollection call each other once per nesting level with no depth limit and nothing turns the Error into a ParseException; the same unterminated text still gives ParseException at 5,000 levels. The caller has no limit it can set, and a plain length cap does not help, because about 42 KB already fails on a 512 KiB stack while real polygons are often longer than 200 KB.",
   "impact_class": "wrong error",
   "introduced_commit": "bd714ca1edc681cd871e6d385bd98a9cb9d7ffe6 (master, 'LUCENE-8538: Add a Simple WKT Shape Parser for creating Lucene Geometries ... from WKT format', by nknize; LUCENE-8538 is apache/lucene#9584; JIRA patch era, no pull request; first shipped in 8.0.0) and its branch_7x twin 5e7858041b87fc9091b0aae7c228445ab6566231 (same message, shipped in 7.6.0 in the lucene-sandbox artifact); moved to lucene-core by LUCENE-8621 (aad849bf87ab on main, bd1bf55b1875 on branch_8x, 2020-01-15; core since 8.5.0). The unbounded recursion was born with the class and is not a regression [read]",
   "introduced_date": "2018-10-22 (author date of bd714ca1edc and 5e7858041b8, 14:25:22 -0500; committed 2018-10-24, 09:27 on master and 09:34 on branch_7x)",
   "first_affected_version": "7.6.0 [exec] (branch_7x commit 5e7858041b8; the class shipped in lucene-sandbox from 7.6.0 to 8.4.1 and in lucene-core since 8.5.0); 7.5.0 has no SimpleWKTShapeParser [exec]; first 8.x release 8.0.0 [exec], from the master commit",
   "affected_versions": "Every release from 7.6.0 to 10.6.0 (7.6.0-8.4.1 in lucene-sandbox, lucene-core since 8.5.0; 10.6.0 run as its release revision, branch_10_6 head 4ae946e5a9b9) and main a9779ef3c193. [exec] a version-neutral public-API repro (1 MiB parse thread, controls at 10 levels pass, verdict at 20,000 levels) overflows for both the nested (420,011 chars) and the unterminated (400,000 chars) input on 7.6.0, 7.7.3, 8.0.0, 8.4.1, 8.5.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 (-da) and main (-ea and -da); 7.5.0 lacks the class. The finder's JUnit fails 2 of 2 on main (-ea and -da), branch_10_6, 10.5.2 and 9.12.3 (-da), and it was re-run with -ea on 9.12.3, 10.0.0 and 10.5.2 (2 of 2 each) and on 9.1.0, where the unterminated half passed in 2 of 3 full-class runs but failed alone and 10 of 10 over --iters 5, and a warm-up probe overflowed 24 of 24 (a JIT-margin effect of the 20,000-level oracle, not a version difference: the 9.1.0 parser differs from 9.12.3 only cosmetically); the independent reproduction's own JUnit fails 2 of 4 (both controls pass) on main (-ea and -da), 10.5.2 (-ea and -da) and 9.12.3 (-da); the intended-behaviour check re-ran the finder's JUnit on main (-ea and -da), 10.5.2 and 9.12.3 (-da); the adjudication on main (-ea and -da); the registration check on main (-da, seed 5EED0384, 2 of 2). [read] the releases in between: git log -L over the recursion shows only the introducing commit and cosmetic edits; 8.9.0-8.11.4 are untagged in the history clone and 8.11.4 was covered by execution. Not fixed upstream: upstream main 645d4fe14a20 (2026-10-28) has no commit on SimpleWKTShapeParser.java after 448c7d8e241 (2026-02-11, a toArray cleanup). All runs on Linux aarch64 with JDK 25.0.3 (versions before 9.0 are outside their supported JDKs, but the parser uses only java.io.StreamTokenizer and plain collections); x86 thresholds not measured.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16423",
    "https://github.com/apache/lucene/issues/9584",
    "https://issues.apache.org/jira/browse/LUCENE-8538",
    "https://github.com/apache/lucene/issues/11687",
    "https://github.com/apache/lucene/issues/1017",
    "https://github.com/apache/lucene/issues/9595"
   ],
   "doc": "",
   "repro": "repro/LFV-954/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-952",
   "priority": "low",
   "priority_rank": 777,
   "novelty": "new",
   "withheld": false,
   "area": "core / geo GeoJSON parsing (Polygon.fromGeoJSON, SimpleGeoJSONPolygonParser)",
   "title": "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)",
   "summary": "You call Polygon.fromGeoJSON on a valid GeoJSON Feature whose properties hold one member with a very long key (about 745,000 chars) above 900 nested arrays, or 1,000 nested objects each under a 1,000-char key (about 1 MB of text), and expect the polygon back. Instead the call fails with OutOfMemoryError: Java heap space in a 512 MiB heap, because SimpleGeoJSONPolygonParser builds a new full key path (path + \".\" + key, path + \".[]\") for every nesting level and each recursive frame keeps its copy alive, so live memory grows with depth times path length, although the parser only ever compares the path with five short constants and a \"crs\" prefix. The same text as a string value, or the same nesting under a short key, parses fine, so neither a size cap nor a usual depth cap protects the caller.",
   "impact_class": "minor",
   "introduced_commit": "343f374b530fa71dc6102d74725b536f5f1367f3 (main line, author date 2016-07-15, 'LUCENE-7380: add Polygon.fromGeoJSON' by Mike McCandless, +1 from Robert Muir; LUCENE-7380 is apache/lucene#8433; JIRA patch era, no pull request; first shipped in 7.0.0) and its branch_6x backport 573aaf75f52f446c8b7ab915eefd420013c544a1 (same author date, shipped in 6.2.0). The per-level path building was born with the parser and is not a regression [read]",
   "introduced_date": "2016-07-15 (author date of 343f374b530 and 573aaf75f52, 14:51:08Z; the backport was committed at 14:51:35Z; JIRA resolved the same day)",
   "first_affected_version": "6.2.0 [exec] (the first release with Polygon.fromGeoJSON and SimpleGeoJSONPolygonParser; 6.1.0 has Polygon but no fromGeoJSON [exec]); first 7.x release 7.0.0 [exec], from the main-line commit",
   "affected_versions": "Every release from 6.2.0 to 10.6.0 (10.6.0 run as its release revision, branch_10_6 head 4ae946e5a9b) and main a9779ef3c193. [exec] the version-portable probe of the version-history runs (900 nested arrays under a long key, 512 MiB heap, three controls) fails with OutOfMemoryError at parseArray's path + \".[]\" (line 291 in 6.2.0-8.11.4, 309 from 9.0.0) while all three controls return the polygon on 6.2.0 (-da, -ea, and -da with SerialGC), 6.2.1, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.2.0, 8.3.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2, branch_10_6 and main (-da, and -da with SerialGC); the candidate JUnit (an old-package copy before 9.1) fails 1 of 1 with -ea on 6.2.0, 8.11.4, 9.0.0, 9.12.3, 10.5.2, branch_10_6 and main, and with -da on main; the finder's repro.sh runs fail on main (-ea and -da), branch_10_6, 10.5.2 and 9.12.3 (-da); the independent reproduction's JUnit fails 1 of 2 (control passes) on main, 10.5.2 and 9.12.3 (-ea and -da); the intended-behaviour check's probe fails 2 of 4 (both controls pass) on main (-ea and -da), 10.5.2 and 9.12.3 (-da); separate checks fail on main (-ea and -da) and 10.5.2 (-da); the adjudication re-ran on main (-ea and -da) and the registration check on main (-da and -ea). [read] the path-building code is unchanged from 343f374b530 to main; the releases not executed are inferred. Not fixed upstream: upstream main 645d4fe14a20 (2026-10-28) has no commit on SimpleGeoJSONPolygonParser.java after 448c7d8e2414 (author date 2026-02-11, a toArray refactor). All runs on Linux aarch64 with JDK 25.0.3; the heap thresholds come from the JVM's String layout and collector, not from the Lucene version; x86 was not measured.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-952.html",
   "repro": "repro/LFV-952/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-030",
   "priority": "low",
   "priority_rank": 778,
   "novelty": "new",
   "withheld": false,
   "area": "util / automaton",
   "title": "CompiledAutomaton.floor never terminates on some infinite languages and runs until OutOfMemoryError",
   "summary": "You call CompiledAutomaton.floor on an infinite language in which the strings below the input have no largest element, for example the language b a* with input bb. You expect the floor term or null. Instead the push-down loop never terminates and grows memory until OutOfMemoryError.",
   "impact_class": "hang",
   "introduced_commit": "LUCENE-3030 (b7846ffaa1f)",
   "introduced_date": "2011-08-20",
   "first_affected_version": "4.0.0-ALPHA [exec] (LUCENE-3030, b7846ffaa1f, 2011; the first GA release is 4.0.0); 3.6.0 and 3.6.2 have no automaton package [exec]",
   "affected_versions": "every release from 4.0.0-ALPHA to 10.6.0 and main 645d4fe14a20 [exec]; [read] no commit has changed the loop's exit since it arrived, so the releases in between are affected too; never fixed",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-030.html",
   "repro": "repro/LFV-030/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-891",
   "priority": "low",
   "priority_rank": 779,
   "novelty": "new",
   "withheld": false,
   "area": "util / automaton",
   "title": "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",
   "summary": "You build a CompiledAutomaton with the documented one-argument constructor, for example from new RegExp(\"m\").toAutomaton() (type SINGLE), Automata.makeEmpty() (NONE), Automata.makeAnyString() (ALL) or, on 10.x, the non-deterministic RegExp(\"(a|ab)c\").toAutomaton() (type NORMAL, run by NFARunAutomaton), and call floor(input, output). You expect what the javadoc promises, the largest accepted term <= input or null: floor(\"x\") = \"m\", null, \"x\", and floor(\"b\") = \"ac\" (the value the determinized form of the same language returns). Instead floor throws NullPointerException ('Cannot invoke ByteRunAutomaton.step(int, int) because this.runAutomaton is null'), because it always walks runAutomaton and the constructor leaves runAutomaton null for these four shapes.",
   "impact_class": "crash",
   "introduced_commit": "b7846ffaa1ff8cd050feaa924e3a6ab12a43549b, LUCENE-3030 'add BlockTreeTermsReader/Writer' (Subversion era, svn r1159905, no PR) [read]. Second shape (NFA-backed NORMAL): c972c6a7754e9ff1f838ed72ff09e7def00be5f8, apache/lucene#225 'LUCENE-10010 Introduce NFARunAutomaton to run NFA directly' (merged 2021-12-20), which moved the other runAutomaton consumers to getByteRunnable()/getTransitionAccessor() but not floor; preceded by #485 (b2e866b7036, 2021-12-03, constructor stopped determinizing and rejected NFAs) and widened by #513 (84e4b85b094, 2021-12-08, RegExp no longer determinizes) [read]. Not a regression for NONE/ALL/SINGLE (born with the method); a 9.x-to-10.0 regression for NFA input (9.12.3 determinizes and returns the right floor [exec]).",
   "introduced_date": "2011-08-20 (b7846ffaa1f, trunk, 19:20:45 UTC); NFA shape 2021-12-20 (#225 merge; first released in 10.0.0)",
   "first_affected_version": "4.0.0 [exec] for NONE, ALL and SINGLE (3.6.2 has no org.apache.lucene.util.automaton package [exec]); 10.0.0 [exec] for the NFA shape (last unaffected: 9.12.3 [exec])",
   "affected_versions": "every release that ships CompiledAutomaton, 4.0.0 through 10.5.2, for NONE/ALL/SINGLE [exec]; the NFA shape in 10.0.0 through 10.5.2 [exec]; plus branch_10_6 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193 [exec], -ea and -da alike. PREFIX (a fourth special type in 4.0.0-5.0.0) failed the same way until LUCENE-6367 removed it in 5.1.0 [exec]. Not fixed on upstream main c5ab3e57b9b (CompiledAutomaton.java byte-identical, 2026-10-28); branch_10x and branch_10_6 heads have the same floor() opening [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-891.html",
   "repro": "repro/LFV-891/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1214",
   "priority": "low",
   "priority_rank": 780,
   "novelty": "new",
   "withheld": false,
   "area": "util / automaton (Automaton.Builder.addEpsilon)",
   "title": "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",
   "summary": "You build an automaton with Automaton.Builder, give a state s one accepting self-loop arc (s -a-> s), and call addEpsilon(s, s). You expect it to return at once: its javadoc says it copies dest's arcs over to source, an epsilon from a state to itself adds nothing, and the sibling Automaton.addEpsilon returns on the same call. Instead the call never returns: its loop re-reads the growing transition count, every copy it appends again leaves s and is copied again, and it runs until OutOfMemoryError: Java heap space.",
   "impact_class": "minor",
   "introduced_commit": "1c2918f66d7 on trunk (svn r1626241) and f147702b5b7 on branch_5x (svn r1626242, how 5.0.0 got it): LUCENE-5963 'more efficient AnalyzingSuggester.replaceSep' (no pull request; the JIRA issue is now #7025; patch by Markus Heiden per CHANGES, committed by Michael McCandless), which created Builder.addEpsilon with its loop bound 'upto < nextTransition' re-read on every iteration; the identical method reached lucene_solr_4_10 in 779d258fc71 (svn r1636762, LUCENE-6046 'add maxDeterminizedStates to determinize', now #7108, which rewrote Operations.repeat(a, min, max) to call builder.addEpsilon), how 4.10.3 got it [read] [exec]",
   "introduced_date": "2014-09-19 (1c2918f66d7 at 15:04:13Z on trunk, f147702b5b7 at 15:05:12Z on branch_5x); 2014-11-04 (779d258fc71 at 22:29:27Z on lucene_solr_4_10)",
   "first_affected_version": "4.10.3 [exec] (tag commit 2014-12-20), the first release that has Builder.addEpsilon at all; 4.10.2 and earlier lack the method [exec]; the first 5.x release, 5.0.0, also fails [exec]",
   "affected_versions": "every release that has the method: 4.10.3 and 4.10.4, 5.0.0-5.5.5, all 6.x, 7.x and 8.x, 9.0.0-9.12.3, 10.0.0-10.6.0 (released 2026-10-29, 4ae946e5a9b), and main 5adff78bb168 (12.0.0-SNAPSHOT). Executed, fail [exec]: 4.10.3 (-ea, -da), 4.10.4, 5.0.0 (-ea, -da), 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2, 10.6.0 (-ea, -da) and main (-ea, -da), always OutOfMemoryError from Builder.addTransition <- Builder.addEpsilon; the 4.10.3-9.0.0 and 10.0.0 runs use the same steps in a main() form, 9.12.3, 10.5.2, 10.6.0 and main use JUnit. [read]: all 101 release tags in the history clone from 4.10.3 on carry the identical loop line; 8.8.2-8.11.3 are not tagged there and lie between executed failing releases. Not affected: 4.10.2 and earlier (no such method). Not new in 10.6 (since 4.10.3). Not fixed upstream: upstream main 1c2072f0284 (2026-11-02) has the same loop (Automaton.java:810), and the newest commit on the file is 86593e51b28 (#15961, author date 2026-04-19, WildcardQuery determinization, unrelated). All runs used JDK 25.0.3 on one aarch64 Linux host.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1214.html",
   "repro": "repro/LFV-1214/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-422",
   "priority": "low",
   "priority_rank": 781,
   "novelty": "known",
   "withheld": false,
   "area": "util / BytesRefHash (initial capacity 1: rehash trigger, linear probe and slot word)",
   "title": "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",
   "summary": "You create new BytesRefHash(pool, 1, new BytesRefHash.DirectBytesStartArray(1)), which the constructor accepts because it rejects only capacities <= 0 and non-powers of two, add the key 'a', then add or look up 'b', expecting id 1 or -1 at once, as with capacity 2. Instead the call never returns: with one slot, hashHalfSize is 0, so add()'s rehash trigger 'count == hashHalfSize' never fires, the single slot stays full, and the linear probe in findHash loops forever looking for an empty slot. Since 10.3.0 (#14720) the same capacity also stores a key whose seeded murmur3 hashcode is exactly -1 as the EMPTY marker, so find() returns -1 for a key that was just added and adding it again gives it a second id.",
   "impact_class": "hang",
   "introduced_commit": "d2d6a45601db87dd928c5f1d7d6d256f6535f6a7 'LUCENE-2662: Refactored TermsHashPerField to utilize ByteRefHash' (trunk, svn/JIRA era, no PR) created BytesRefHash with the public 3-argument constructor (no validation), 'hashHalfSize = hashSize >> 1' and the rehash trigger 'count == hashHalfSize' [read]; it first shipped through the branch_3x copy a52015db05f790613906a9858531ff16e3d78b8a (LUCENE-3233, 2011-07-11) in 3.4.0 [exec]. The hashcode -1 manifestation came with 2f66c8f6668622c0c82b720d47ccd43b57e32edb 'Cache high-order bits of hashcode to speed up BytesRefHash (#14720)' (by GitHub bugmakerrrrrr, approved by GitHub jpountz; branch_10x backport 0386d68349d4083d600de938998566e76aedd0d7), which added highMask = ~hashMask, the stored word e | (hashcode & highMask), and the capacity checks that accept 1 [read]",
   "introduced_date": "2010-10-02 (d2d6a45601d, trunk; the shipped branch_3x copy a52015db05f is 2011-07-11); hashcode -1 manifestation 2025-05-31 (#14720 merged)",
   "first_affected_version": "3.4.0 [exec] (3.3.0 has no util.BytesRefHash, the repro does not compile against it [exec]; on the trunk line the first release is 4.0.0-alpha, 4.0.0 executed); hashcode -1 manifestation 10.3.0 [exec] (10.2.2 shows the hang only [exec])",
   "affected_versions": "Hang: every release that ships BytesRefHash, 3.4.0 through 10.5.2 (the last release before 10.6.0), and main ea57360912ed; not fixed upstream (apache/lucene main, last changed by #16499, still accepts capacity 1; branch_10x last changed by #15779; no open PR among the 411 scanned touches BytesRefHash.java; read-only, 2026-10-26). [exec] follow-up history runs with a public-API main() probe (JDK 25, SHA-1-verified release jars, seed DEADBEEF): 3.4.0 (-ea, -da), 3.6.2, 4.0.0, 4.7.2, 4.8.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3 (-ea, -da), 10.0.0, 10.2.2 (-ea, -da), 10.3.0 (-ea, -da), 10.4.0, 10.5.2 (-ea, -da) and main (-ea, -da) all hang, with the capacity-2 control passing every time; the finder's JUnit fails on 9.1.0, 9.12.3 and 10.2.2 (hang only) and on 10.3.0, 10.5.2 and main (both symptoms); the independent reproduction's JUnit fails on main (-ea, -da), 10.5.2 and 10.3.0 (all 4 capacity-1 tests) and on 10.2.2 and 9.12.3 (3 of 4: the hashcode -1 test passes). [read] all 128 release tags in the history clone that contain util/BytesRefHash.java (3.4.0-8.8.1, 9.0.0-10.5.2) have the trigger and no minimum-capacity check (8.8.2-8.11.4 are not tagged in the clone; 8.11.4 was executed). Hashcode -1 wrong result: 10.3.0 through 10.5.2 and main only.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16858",
    "https://github.com/apache/lucene/issues/16805",
    "https://github.com/apache/lucene/issues/4785",
    "https://issues.apache.org/jira/browse/LUCENE-3711",
    "https://github.com/apache/lucene/issues/14720",
    "https://github.com/apache/lucene/issues/15779"
   ],
   "doc": "",
   "repro": "repro/LFV-422/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-888",
   "priority": "low",
   "priority_rank": 782,
   "novelty": "new",
   "withheld": false,
   "area": "search / query caching policy (UsageTrackingQueryCachingPolicy over util FrequencyTrackingRingBuffer)",
   "title": "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)",
   "summary": "You create new UsageTrackingQueryCachingPolicy(715_827_883) (the same int overflow also breaks every larger size your heap can allocate) and install it on an IndexSearcher with a query cache, expecting it either to track that many recent queries or to reject the size up front with IllegalArgumentException, as FrequencyTrackingRingBuffer already does for sizes below 2. Instead the constructor succeeds (with assertions disabled), the first query is recorded, and the second distinct query loops forever inside onUse while holding the policy's lock, so that search hangs and every other search thread that uses the policy blocks. The cause is that FrequencyTrackingRingBuffer's internal IntBag computes its hash-table size as Math.max(2, maxSize * 3 / 2) in int: above 715,827,882 the product overflows, the table gets only 2 slots (the sentinel takes one, the first query hash the other), and IntBag.add's probe loop has no exit when every slot holds another key.",
   "impact_class": "hang",
   "introduced_commit": "5a9639c3e629d6af02d20acfee58d33d2d35b1a6 (trunk, svn r1646674; branch_5x 9e89cb92ae29fb3c6f94c3daaac66b231c6e8043, svn r1646675), LUCENE-6118 'Improve efficiency of the history structure for filter caching' (JIRA, migrated as apache/lucene#7180; patch by jpountz, +1 by rjernst on JIRA; no PR, pre-GitHub) [read]: it replaced the unreleased LUCENE-6077 history (ArrayDeque plus ConcurrentHashMap, 2014-11-27) with an int[] ring plus the open-addressing IntBag sized Math.max(2, maxSize * 3 / 2) in int, and added maxSize >= 2 as its only size check (the LUCENE-6077 constructor had none); the review discussed only IntBag.remove chain relocation, no size limit. Not a regression: the defect was born with IntBag. Later commits to the file are only a license-header move (813ca77250d, 2016) and a reformat (2d6ad2fee6d, 2020).",
   "introduced_date": "2014-12-19 (author date = commit date: 11:22:13Z trunk, 11:25:30Z branch_5x); first released in 5.0.0",
   "first_affected_version": "5.0.0 [exec] (hang with -da and AssertionError with -ea through the 5.0 public API UsageTrackingFilterCachingPolicy(float, int historySize, int, int, int), and a hang through FrequencyTrackingRingBuffer directly); 4.10.4 has none of the classes [exec], so no earlier release is affected",
   "affected_versions": "every release from 5.0.0 to 10.6.0 and main: [exec] 5.0.0 (-da hang, -ea AssertionError), 5.5.5 (direct FrequencyTrackingRingBuffer probe, -da hang), 6.1.0 and 8.11.4 (-da hang), 9.12.3 and 10.5.2 (-da hang, -ea AssertionError; the intended-behaviour check's searcher-level probe also hangs IndexSearcher.search on 10.5.2), main a9779ef3c193 (-da hang, -ea AssertionError, re-run 2026-10-28 by the registration check), and the minimal test on the 10.6.0 release jars and on main 645d4fe14a20 (-da 30 s timeout in IntBag.add, -ea AssertionError, 2026-10-31); [read] the sizing line is in all 98 release tags 5.0.0-10.5.2 of the history clone (8.8.2-8.11.4 are not tagged there; 8.11.4 was executed), and the 10.6.0 tag 4ae946e5a9b (branch_10_6) has both files identical to main and to upstream main 2f424fd428d [read]. Public trigger by era: UsageTrackingFilterCachingPolicy(..., historySize, ...) in 5.0.x, UsageTrackingQueryCachingPolicy(float, int) / (int, float, int) in 5.1.0-6.0.1, UsageTrackingQueryCachingPolicy(int historySize) since 6.1.0, and FrequencyTrackingRingBuffer(int, int) (public, @lucene.internal) throughout. Not fixed on upstream main c5ab3e57b9ba (2026-10-28) or 2f424fd428d (2026-10-30).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-888.html",
   "repro": "repro/LFV-888/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-056",
   "priority": "low",
   "priority_rank": 783,
   "novelty": "new",
   "withheld": false,
   "area": "search / concurrency",
   "title": "TaskExecutor#invokeAll returns while a task is still running if the caller is interrupted",
   "summary": "You run a concurrent search and the calling thread is interrupted. You expect invokeAll to wait for its tasks or to propagate their failures. Instead it returns while a task still runs: with assertions on an AssertionError fires, and with assertions off the task's exception is lost and the task may keep reading a reader the caller has released.",
   "impact_class": "wrong error",
   "introduced_commit": "#12523 (73714934787) made invokeAll record an interrupt and continue without retrying get() [read]",
   "introduced_date": "2023-10-05",
   "first_affected_version": "9.9.0 [read]",
   "affected_versions": "9.9.0-10.5.2 [read]; 10.1.0, 10.5.2 and main [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-056.html",
   "repro": "repro/LFV-056/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-636",
   "priority": "low",
   "priority_rank": 784,
   "novelty": "new",
   "withheld": false,
   "area": "facet / DrillSideways concurrent mode (ExecutorService constructor, searchConcurrently)",
   "title": "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)",
   "summary": "You construct DrillSideways with an ExecutorService so that its drill-down and drill-sideways searches run concurrently, and one of those searches fails, for example because the base query has more clauses than IndexSearcher's clause limit, an ExitableDirectoryReader timeout fires, or a query or collector throws IOException. You expect the exception the sequential DrillSideways throws for the same search: the class javadoc presents the two modes as alternative implementations that differ in speed and duplicate work, every search overload declares IOException, and IndexSearcher has rethrown task failures as-is since 9.8.0 (GITHUB#12516) precisely so that sequential and concurrent searches throw the same exceptions. Instead DrillSideways.searchConcurrently catches the ExecutionException from Future.get and throws new RuntimeException(e), so the caller receives RuntimeException -> ExecutionException -> the original exception, and catch blocks for TooManyClauses, ExitingReaderException or IOException do not fire.",
   "impact_class": "wrong error",
   "introduced_commit": "b4a002f7d88a2383852e2bfd95b39bf7f6e33f2f (master, first released in 7.0.0) and its branch_6x twin 5b6401b212da883188f45709d1f68addbbdf2c98 (first released in 6.4.0), both 'LUCENE-7588: DrillSideways can now run its queries concurrently' (JIRA LUCENE-7588, migrated as apache/lucene#8639 'A parallel DrillSideways implementation'; a JIRA-era patch committed by GitHub mikemccand, no PR). The commit created the concurrent mode (the ExecutorService constructor and search(DrillDownQuery, CollectorManager)), and its first version of the concurrent search method already had 'catch (ExecutionException e) { throw new RuntimeException(e); }' (6.4.0 DrillSideways.java:436-437) [read] [exec]",
   "introduced_date": "2017-01-03 (both commits); first release 6.4.0, tagged 2017-01-17",
   "first_affected_version": "6.4.0 [exec]; 6.3.0 is not affected because the concurrent mode does not exist there (no ExecutorService constructor) [exec]",
   "affected_versions": "every release from 6.4.0 through 10.6.0, and main a9779ef3c193 and 645d4fe14a20; never fixed. [exec] the minimal test fails on the 10.6.0 release jars and on main 645d4fe14a20, -ea and -da (2026-10-31); the follow-up's version-portable history probe (clause limit and fired query timeout, sequential versus ExecutorService, plain IndexSearcher, 11 segments, a non-failing control that passes everywhere) is affected on 6.4.0 (-ea and -da), 6.4.1, 6.5.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.8.2, 8.11.4, 9.0.0, 9.7.0, 9.8.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da), and passes on main with the fix shadowed; the finder's JUnit fails 2 of 2 on 9.1.0, 9.7.0, 9.8.0, 9.12.3, 10.0.0, 10.5.2 and main; the independent reproduction's JUnit fails 4 of 4 on 9.12.3, 10.5.2 and main; the intended-behaviour check's probe shows the wrapping on 9.7.0, 9.8.0 and main. [read] all 77 release tags from 6.4.0 to 10.5.2 in the git history contain the unchanged catch line (8.9.0-8.11.3, released from the old combined repository, are inferred from the 8.8.2 and 8.11.4 runs), and so do upstream main a95c754ee00, branch_10x 1309534296e and branch_10_6 2763db11b0a (refs fetched 2026-10-26). By version: from 6.4.0 to 9.7.0 IndexSearcher with an executor wrapped in-slice failures the same way, so the mismatch then was against sequential DrillSideways (the intended-behaviour check probe on 9.7.0: three of four executor paths wrap); since 9.8.0 (GITHUB#12516) concurrent DrillSideways is the only one of these paths that still wraps [exec]. Not checked: x86; on old versions only search(DrillDownQuery, int) was executed (the other overloads reach the same catch [read])",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-636.html",
   "repro": "repro/LFV-636/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-631",
   "priority": "low",
   "priority_rank": 785,
   "novelty": "new",
   "withheld": false,
   "area": "index / CheckIndex concurrent segment check",
   "title": "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",
   "summary": "You run CheckIndex with more than one thread (the default checkIndex() on a multi-core machine, or checkIndex(onlySegments, executor)) and your application interrupts the checking thread while it waits for a segment's result, for example to cancel the check. You expect either the outcome the code's own handler is written for (it logs 'ERROR: Interrupted exception occurred when getting segment check result for segment ...' and goes on) or an interrupt-type exception such as ThreadInterruptedException, the convention IndexWriter documents. Instead the handler logs and then passes the still-null segment status to processSegmentInfoStatusResult, which throws NullPointerException ('Cannot read field \"error\" because \"segmentInfoStatus\" is null'), with the interrupt flag cleared and, on a caller-owned pool, the remaining segment checks still running.",
   "impact_class": "wrong error",
   "introduced_commit": "424192e1704664dc0ebc55109feaad5990b945cb (LUCENE-9662 'CheckIndex should be concurrent - parallelizing index check across segments', apache/lucene#128 by zacharymorn; parent 9c7f0d45eef) on main, backported to 8.x as apache/lucene-solr#2567 (commit 965b54ce3fd, branch_8x) [exec]. Born with the feature: before it, CheckIndex checked segments sequentially on the caller thread with no Future.get. Later changes to the block: 56f49257ed6 (#637, 9.1.0, made the logging in the same catch null-safe and left the null status) and 64cf54a4bff (#12979, charset cleanup)",
   "introduced_date": "2021-09-01 (merged to main; commit dated 2021-08-31 19:24 -0700); 8.x backport 2021-09-10",
   "first_affected_version": "8.11.0 [exec] (first release with concurrent CheckIndex, through the 8.x backport); first 9.x release 9.0.0 [exec]; 8.10.1 is not affected [exec]",
   "affected_versions": "every release from 8.11.0 through 10.5.2, and main a9779ef3c193; never fixed. [exec] 8.11.0 (-ea and -da), 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da), plus the introducing commit (follow-up history runs with the finder's and the independent reproduction's tests); the independent reproduction and the intended-behaviour check also executed 10.5.2 and 9.12.3 with their own tests. [read] the catch block and processSegmentInfoStatusResult have the same logic at every tag 9.0.0-10.5.2 and on main; branch_8_11 has no CheckIndex.java commit after the backport. Symptom by version: from 9.1.0 on every route gives the null-status NPE; in 8.11.x, 9.0.0 and the introducing commit the null-status NPE is executed with an infoStream set (the independent reproduction executor route), while with no infoStream (the CheckIndex default) an unguarded infoStream print in the same code throws an NPE first, the defect #637 fixed in 9.1.0 (per the prior-art read of the 9.0.0 source and the 8.11.0 bytecode, that unguarded print also breaks the uninterrupted concurrent path there). Not affected: 8.10.1 and earlier (no concurrent CheckIndex).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-631.html",
   "repro": "repro/LFV-631/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-564",
   "priority": "low",
   "priority_rank": 786,
   "novelty": "known",
   "withheld": false,
   "area": "core / search TaskExecutor (concurrent task failure path; util IOUtils.useOrSuppress)",
   "title": "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",
   "summary": "You run a concurrent search (an IndexSearcher with an executor, or TaskExecutor.invokeAll directly) and two of its tasks fail with the same exception object, for example because the JVM reuses one preallocated NullPointerException at a hot code site. You expect what the invokeAll javadoc promises: it waits for all tasks to complete and throws the first failure, with later ones added as suppressed exceptions. Instead IOUtils.useOrSuppress calls exc.addSuppressed(exc), the JDK rejects that with IllegalArgumentException('Self-suppression not permitted'), and that exception escapes TaskExecutor.collectResults before the remaining tasks are awaited, so the caller gets the wrong exception type and invokeAll can return while another started task is still running.",
   "impact_class": "wrong error",
   "introduced_commit": "7371493478790facb1d46e2e516a99089c2ebfa8 (main) and the branch_9x backport 50f9a6731c2a0b4952c87410d3e3d836643830c7, both 2023-10-05: GITHUB#12523 'TaskExecutor waits for all tasks to complete before returning' (by GitHub quux00), which replaced 'rethrow the first failure at once' with a loop over the futures that collects every failure and calls exc.addSuppressed(e.getCause()) with no identity check [read]. Later refactors kept the defect: #12689 (1200ecce3a2, loop moved into TaskGroup.invokeAll, 9.9.0), #13472 (main 62e08f5f4b7, branch_9x e78f23738f4: the call became exc = IOUtils.useOrSuppress(exc, e.getCause()); useOrSuppress itself dates from LUCENE-8212, 916ed60eea2, 2018-03-15, released in 7.4.0, and has never had an identity guard), #13861 (7757d43f4c9, loop moved into the static collectResults).",
   "introduced_date": "2023-10-05",
   "first_affected_version": "9.9.0 [exec]; not affected: 9.8.0 [exec] (it rethrew the first failure at once, the older early-return behaviour that #12523 fixed, a different defect; TaskExecutor was package-private there) and 9.7.0 [exec]",
   "affected_versions": "Every release from 9.9.0 through 10.6.0 (10.6.0 by reading), plus main ea57360912ed. [exec] the independent reproduction's public-API JUnit (3 tests) fails 3 of 3 on 9.9.0, 9.10.0, 9.12.3, 10.5.2 and main (-ea and -da; 60 of 60 over 20 iterations on main); the history sweep, with the same tests, fails 3 of 3 on 9.9.0, 9.11.1, 9.12.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the finder's JUnit fails on main (-ea and -da) and 10.5.2 (2 of 2) and on 9.12.3 (its TaskExecutor test; its 9.10.0 run was a harness artifact, per the independent reproduction); the cross-model review step's main() variant fails on main (-ea and -da), 10.5.2 and 9.9.0. The defect is inline (exc.addSuppressed(e.getCause())) in TaskExecutor on 9.9.0-9.11.1 and in IOUtils.useOrSuppress from 9.12.0 on. [read] the other release tags (9.9.1, 9.9.2, 9.11.0, 9.12.1, 9.12.2, 10.1.0-10.4.0, 10.5.0, 10.5.1) have the same code. Not fixed upstream: useOrSuppress and collectResults are unchanged on upstream main a95c754ee003 (2026-10-26), branch_10x, branch_10_6 and branch_9_12, and no open PR changes useOrSuppress.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/997",
    "https://lists.apache.org/thread/tzbk5317j80xtyds0gq51q3kqnww3fob",
    "https://github.com/apache/lucene/issues/12523",
    "https://github.com/apache/lucene/issues/13472",
    "https://issues.apache.org/jira/browse/LUCENE-8212",
    "https://github.com/apache/lucene/issues/16778"
   ],
   "doc": "",
   "repro": "repro/LFV-564/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1224",
   "priority": "low",
   "priority_rank": 787,
   "novelty": "new",
   "withheld": false,
   "area": "core / util (IOUtils failure-path cleanup helper closeWhileSuppressingExceptions; reached from StandardDirectoryReader.open, the IndexWriter constructor and codec readers and writers)",
   "title": "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",
   "summary": "After a failure, Lucene calls IOUtils.closeWhileSuppressingExceptions(ex, closeables...) to close what it had opened and attach any close failures to ex, for example when opening a DirectoryReader fails. If one close() throws the very object ex (the JVM reuses one OutOfMemoryError object once memory is exhausted), you expect what the method documents: every closeable is closed and, for an Error, that same Error is rethrown. Instead ex.addSuppressed(ex) throws IllegalArgumentException 'Self-suppression not permitted', which escapes the loop, so the remaining closeables are never closed and the caller sees the IllegalArgumentException instead of the original failure (kept only as its cause).",
   "impact_class": "minor",
   "introduced_commit": "7d3c7bb6c7cef2e7d130162ff8c990407c3a8750 (main, #14633 by thecoop, 'Catch and re-throw Throwable rather than using a success boolean'), which added closeWhileSuppressingExceptions with the unguarded firstError = ex / ex.addSuppressed(e) in its first version; on the 10.x line c5a4d07e5540d0c8adce0af390275c8fd731b52a (#15445 by BryceKan3, the branch_10x PR of #15428), which copied the method unchanged and shipped first [read]",
   "introduced_date": "main 2025-05-13 (author date = commit date); branch_10x 2025-11-22 (author date = commit date)",
   "first_affected_version": "10.4.0 [exec] (tagged 2026-02-20; contains c5a4d07e554; the first release with the method). The main commit is in no release (there is no 11.x release). Releases before 10.4.0 do not have the method (10.3.2 and 9.12.3: compile error, API absent [exec]).",
   "affected_versions": "10.4.0, 10.5.0, 10.5.1, 10.5.2, 10.6.0 (4ae946e5a9b, released 2026-10-29) and main from 7d3c7bb6c7c (2025-05-13) to 5adff78bb168 (12.0.0-SNAPSHOT); not fixed upstream (upstream main 1c2072f0284, branch_11x and branch_10_6 have the identical method body, and upstream main still has the unguarded calls at IOUtils.java:127 and :129, check 2026-11-03). [exec] fail: 10.4.0 (-ea, -da), 10.5.2 (-ea by the independent reproduction, -da), 10.6.0 (-ea, -da), main 5adff78bb168 (-ea, -da), and the IOUtils.java of 7d3c7bb6c7c over the main jars (-da, mixed build); [read] 10.5.0 and 10.5.1 (byte-identical method body). Not affected [exec]: 10.3.2 and 9.12.3 (method absent). Not new in 10.6 (10.4.0 and 10.5.2 fail). In-tree reach grew per release [read]: 10.4.0 one non-test caller (StandardDirectoryReader.open), 10.6.0 six non-sandbox caller files, main 72 non-sandbox caller files (the IndexWriter constructor and the write-lock leak route are main-only). All runs used JDK 25.0.3 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1224.html",
   "repro": "repro/LFV-1224/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1222",
   "priority": "low",
   "priority_rank": 788,
   "novelty": "new",
   "withheld": false,
   "area": "core / search: disjunction scoring (DisjunctionScoreBlockBoundaryPropagator, built by DisjunctionMaxScorer and LogOddsFusionScorer for top-k searches)",
   "title": "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)",
   "summary": "You run a top-k search, IndexSearcher.search(q, 10), of a DisjunctionMaxQuery with tie-breaker 0.1 whose second clause is your own query whose Scorer.getMaxScore throws IOException, and expect that IOException: Scorer.getMaxScore and IndexSearcher.search both declare it, and the same failure on a later, identical getMaxScore call does surface as IOException. Instead the search throws java.lang.RuntimeException wrapping it, from DisjunctionScoreBlockBoundaryPropagator.java:40, because the propagator sorts the clauses with a Comparator whose key extractor calls getMaxScore(NO_MORE_DOCS) and turns the IOException into a RuntimeException (a lambda cannot throw a checked exception). LogOddsFusionQuery builds the same propagator and behaves the same; a search that does not prune (COMPLETE score mode) is unaffected.",
   "impact_class": "minor",
   "introduced_commit": "1ea8419336a6806463fd9dc83dc77e41a5475649 (master, 'LUCENE-8922: Better impacts for DisjunctionMaxQuery. (#791)', by Adrien Grand (jpountz), apache/lucene-solr#791, issue LUCENE-8922 = apache/lucene#9965); the 8.x code that shipped is the branch_8x cherry-pick 967e1c82be9 plus 8df37aaf2c5 ('LUCENE-8922: 8.x adjustments.', which does not touch the comparator). The commit created DisjunctionScoreBlockBoundaryPropagator with MAX_SCORE_COMPARATOR, whose key extractor calls getMaxScore(NO_MORE_DOCS) and does 'catch (IOException e) { throw new RuntimeException(e); }', and made DisjunctionMaxScorer build the propagator in TOP_SCORES mode [read] [exec]. Neither the PR review nor the issue comments mention the wrap.",
   "introduced_date": "2019-07-24 (author date = commit date, 15:12:57+02:00; PR merged 13:12:58Z); first release 8.3.0 (tagged 2019-10-24, LUCENE-8922 listed under 8.3.0 Optimizations)",
   "first_affected_version": "8.3.0 [exec] (8.2.0 has no DisjunctionScoreBlockBoundaryPropagator, and the same program gets the IOException there, thrown via DisjunctionMaxScorer.getMaxScore [exec]: a change of behaviour that first shipped in 8.3.0)",
   "affected_versions": "every release from 8.3.0 through 10.6.0 (4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT) through DisjunctionMaxQuery, and through LogOddsFusionQuery from its first release, 10.5.0 [read]. Executed and failing with RuntimeException(IOException) at DisjunctionScoreBlockBoundaryPropagator.java:40: 8.3.0, 8.11.4, 9.0.0 and 9.12.3 with a copy of the test written against the pre-10.0 Scorer(Weight) API (main() mode, -ea), 10.0.0 and 10.6.0 with the finder's JUnit test, 10.6.0, 10.5.2 and 9.12.3 with the independent reproduction's own test, main with -ea and -da (finder, the independent reproduction, the intended-behaviour check, adjudication, registration check) and the released 10.6.0 jars with -da (registration check) [exec]. By git tag --contains, the branch_8x commit is in all 14 releases/lucene-solr tags 8.3.0..8.8.1 of the history clone and 1ea8419336a in all 34 releases/lucene tags 9.0.0..10.6.0 [read]; 8.8.2..8.11.3 have no tag there, the fix site is unchanged since 2019 apart from a reformat and two cosmetic edits to the secondary cost comparator, and 8.11.4 fails [exec]. Upstream main 1c2072f0284 (2026-11-02) has the same file blob (ba9827d20cc) [read]. Not affected: 8.2.0 and earlier (8.2.0 executed: pass). Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1222.html",
   "repro": "repro/LFV-1222/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-124",
   "priority": "low",
   "priority_rank": 789,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter addIndexes(Directory...) and the writer-wide field registry (FieldInfos.FieldNumbers)",
   "title": "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",
   "summary": "You call IndexWriter#addIndexes(Directory...) with an index whose first field a_new is new to the destination and whose field z_conflict clashes with the destination's schema; the call correctly throws IllegalArgumentException and adds no segment, as its javadoc promises ('either no indexes will have been added or they all will have been'). You expect the writer to be as it was before the call, so that a later document can use a_new with any schema, as it can after the writer is reopened and after the same failure in addIndexes(CodecReader...). Instead the writer keeps a_new registered with the incoming schema, because addIndexes(Directory...) registers each incoming FieldInfo in the writer-wide FieldNumbers map while it iterates and its failure path only deletes the copied files: getFieldNames() lists a_new although no segment has it, and a document with NumericDocValuesField('a_new') is rejected ('cannot change field \"a_new\" from index options=DOCS to inconsistent index options=NONE') until the writer is reopened.",
   "impact_class": "crash",
   "introduced_commit": "041ff1140f3f ('make DV strongly typed; fix solr', by mikemccand on the lucene4547 development branch, svn r1412906), which gave FieldInfos.FieldNumbers a per-name doc-values type and added the loop in addIndexes(Directory...) that calls globalFieldNumberMap.addOrGet for every incoming FieldInfo before copySegmentAsIs, with a failure path that only deletes the copied files; it reached trunk as a181dc073539 and branch_4x as 5cbaddcbc7ff (both 'LUCENE-4547: DocValues improvements'); no PR (Subversion era), and LUCENE-4547 (GitHub #5613) does not discuss addIndexes or failure handling; d03662c48bfc (LUCENE-9334, PR #11) later changed the call to addOrGet(fi) with the comment 'This will throw exceptions if any of the incoming fields has an illegal schema change' and widened the trigger to every per-field attribute, and 0a4a76f0a869 (#14668) replaced the success flag with catch (Throwable) and still only deletes files [read]",
   "introduced_date": "2012-11-23 (041ff1140f3f, lucene4547 branch); landed on trunk 2013-02-07 (a181dc073539) and branch_4x 2013-02-08 (5cbaddcbc7ff); 4.2.0 tagged 2013-03-11",
   "first_affected_version": "4.2.0 [exec]",
   "affected_versions": "every release from 4.2.0 through 10.6.0 and main ea57360912ed and 645d4fe14a20 (unreleased 11.0.0) [exec]; the hunt repro's exact trigger (an indexed StringField against a doc-values-only field) needs LUCENE-9334 and exists from 9.0.0 on (on 8.11.4 that input is not a conflict) [exec]; the getFieldNames() symptom exists from 6.5.0 (LUCENE-7659) [read]; the point-dimension (6.0+), index-sort and IOException triggers on old releases are from code reading only; 4.1.0 and earlier are not affected: addIndexes(Directory...) neither validated nor registered incoming fields [exec]; not fixed upstream: the loop is unchanged on main, branch_10x, branch_10_6, branch_10_5 and branch_9_12 [read], IndexWriter.java is byte-identical at 645d4fe14a20 and upstream main 2f424fd428da [read], and no open PR changes it",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-124.html",
   "repro": "repro/LFV-124/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1081",
   "priority": "low",
   "priority_rank": 790,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter addIndexes(CodecReader...) merge (SegmentMerger) and the writer-wide field registry (FieldInfos.FieldNumbers)",
   "title": "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",
   "summary": "You import an index with IndexWriter.addIndexes(CodecReader...) and the call fails with an IOException (for example a full disk) while the merged segment is written; as its javadoc promises, no documents are added, and the writer stays open. You expect the writer to behave as if the call had never happened, so that a later document may use an imported field name with any schema, as it may on a fresh or reopened writer and after a validation-time failure of the same call. Instead the merge has already registered every incoming field in the writer-wide field schema before it failed, and nothing undoes that: a later document with NumericDocValuesField(\"f\") is rejected ('cannot change field \"f\" from index options=DOCS to inconsistent index options=NONE') although no document with \"f\" was ever indexed into this writer, until the writer is reopened. No I/O error is needed: on a writer with an index sort, when the incoming indexes contain document blocks without a parent field, or with a merge policy that returns one merge per incoming reader, two incoming indexes that use a field differently make the call fail with IllegalArgumentException and leave the first index's schema registered in the same way, so a later document, or an import of only the second index, is rejected; before 9.9.0 every conflicting two-reader import did so.",
   "impact_class": "minor",
   "introduced_commit": "041ff1140f3f207ab0a3571c92a738b328142e95 (author Michael McCandless, 'make DV strongly typed; fix solr', on the LUCENE-4547 development branch; LUCENE-4547 = apache/lucene#5613; svn era, no pull request), which gave FieldInfos.FieldNumbers a per-field doc-values type that addOrGet enforces; it reached trunk as a181dc07353 (2013-02-07) and branch_4x as 5cbaddcbc7f (2013-02-08), both 'LUCENE-4547: DocValues improvements'. Precondition: 54d3be3ad36 (LUCENE-2881 = apache/lucene#3955, Simon Willnauer, 2011-03-22, first in 4.0.0) made the addIndexes merger number its fields through the writer-wide globalFieldNumberMap instead of a private clone, so a failed merge already left the incoming names registered, with no visible effect while the map held only name-to-number. The CodecReader overload inherited the path when addIndexes(IndexReader...) was renamed by LUCENE-6158 (e2b348cef08) and LUCENE-6165 (1a394ff3950), both before 5.0.0; LUCENE-9334 (d03662c48bf, apache/lucene#10374, 9.0.0) widened the enforced schema to every per-field attribute; LUCENE-10216 (698f40ad51a, PR #633, 9.4.0) added the non-mutating up-front verifyFieldInfo but kept the merge over globalFieldNumberMap [read]",
   "introduced_date": "2012-11-23 (author date of 041ff1140f3 on the LUCENE-4547 branch); landed on trunk 2013-02-07 (a181dc07353) and branch_4x 2013-02-08 (5cbaddcbc7f); 4.2.0 released 2013-03",
   "first_affected_version": "4.2.0 [exec]; addIndexes(CodecReader...) itself from 5.0.0, its first release [exec]; fault-free conflicting-import trigger: with the default configuration on every executed release up to 9.8.0 (8.11.4 in its doc-values-type form, 9.0.0 and 9.8.0 [exec]); from 9.9.0 (#12622 added the wrap) only on index-sorted writers or with a per-reader merge policy, and from 9.11.0 (#13128) also with incoming blocks without a parent field [exec]",
   "affected_versions": "every release from 4.2.0 (as addIndexes(IndexReader...)) and from 5.0.0 (addIndexes(CodecReader...)) through 10.6.0 (4ae946e5a9b), and main e1faeba08bde (unreleased) [exec]; the JUnit's exact trigger (an indexed StringField against a doc-values-only field) is a conflict only from 9.0.0 (LUCENE-9334) on, and on 8.11.4 that input passes while the doc-values-type form fails [exec]; not fixed upstream: upstream main head is still e1faeba08bde (checked 2026-11-02) and no open PR changes the registration or the addIndexes failure path [read]; fault-free trigger (2026-11-02, -da unless stated): the one-test JUnit TestRejectedAddIndexesConflictingReadersSchema (blocks without a parent field) fails on main e1faeba08bd with -ea and -da and on 10.6.0 and 10.5.2; a four-leg probe (plain, index-sorted, blocks, per-reader merges) leaves residue on the sorted, blocks and per-reader legs with a clean plain leg on main (-ea and -da), 10.6.0, 10.5.2 and 9.12.3, sorted and per-reader residue with clean plain and blocks legs on 9.10.0, and residue on all four legs on 9.8.0; the plain default-config port fails on 8.11.4, 9.0.0 and 9.8.0 and passes on 9.9.0 and main",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16937",
    "https://github.com/apache/lucene/issues/16357",
    "https://github.com/apache/lucene/issues/9738",
    "https://issues.apache.org/jira/browse/LUCENE-8692",
    "https://github.com/apache/lucene/issues/633",
    "https://github.com/apache/lucene/issues/13353"
   ],
   "doc": "",
   "repro": "repro/LFV-1081/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-134",
   "priority": "low",
   "priority_rank": 791,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter doc-values updates and the writer-wide field registry (FieldInfos.FieldNumbers)",
   "title": "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",
   "summary": "You call IndexWriter#updateDocValues (or softUpdateDocument(s) / tryUpdateDocValue) with a field that no document has used yet, and the call is correctly rejected with IllegalArgumentException, for example because the field is part of the index sort or because SORTED and SORTED_SET doc values cannot be updated. You expect the rejected call to leave the writer unchanged, so that the first real document with that field defines its schema, as on a fresh writer and as the document path does when it rejects a document for its index-sort doc-values type. Instead buildDocValuesUpdate has already registered the field as doc-values-only in the writer-wide FieldNumbers map before those checks run, and nothing undoes it: for the rest of the writer session a legal document such as LongField('price') or StringField('tag') plus SortedDocValuesField('tag') is refused ('cannot change field \"price\" from points dimensionCount=0 ... to inconsistent dimensionCount=1'), and getFieldNames() lists a field that no segment or accepted operation has.",
   "impact_class": "wrong error",
   "introduced_commit": "0c3628920afd (LUCENE-8316 'Allow DV updates for not existing fields', by s1monw, a JIRA patch with no PR, migrated issue #9363; branch_7x backport fa00c9e55c16 plus compile fix 6b4daf8590b0), which replaced the read-only globalFieldNumberMap.contains() check (it threw 'can only update existing docvalues fields!' and left nothing behind) with a registering addOrGet placed before the LUCENE-7581 index-sort guard (4efbde4e7627, 2016) and before the unsupported-type branch; its message motivates creating the field for an update that is applied and says nothing about rejected calls; widened by d03662c48bfc (LUCENE-9334, PR #11, by mayya-sharipova, first released in 9.0.0), which turned the call into verifyOrCreateDvOnlyField(name, dvType, false), registering a complete doc-values-only FieldInfo, and made FieldNumbers check the whole per-field schema, so the leftover entry also rejects points and postings [read]",
   "introduced_date": "2018-05-16 (0c3628920afd, LUCENE-8316); widened 2021-04-14 (d03662c48bfc, LUCENE-9334)",
   "first_affected_version": "7.4.0 [exec] (narrow form: the rejected call fixes only the field's doc-values type); 9.0.0 [exec] for the full form",
   "affected_versions": "7.4.0-7.7.3 and 8.0.0-8.11.4, narrow form [exec]; 9.0.0-9.12.3, 10.0.0-10.5.2 and main ea57360912ed (unreleased 11.0.0), full form [exec]; other releases in these ranges are inferred from unchanged code [read]; not affected: 7.0.0 and 7.3.1 [exec] (updateDocValues required an existing field and registered nothing); all four callers of buildDocValuesUpdate exist from 7.4.0 on, softUpdateDocuments was executed on 9.8.0 and later only and tryUpdateDocValue was read, not executed; not fixed upstream: the order is unchanged on main, branch_10x, branch_10_6 and branch_9_12 [read], and open PR #16810, the only open PR that edits this guard, keeps it",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-134.html",
   "repro": "repro/LFV-134/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-436",
   "priority": "low",
   "priority_rank": 792,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter addIndexes(CodecReader...) failure path (AddIndexesMergeSource queue, SerialMergeScheduler)",
   "title": "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",
   "summary": "You call addIndexes(CodecReader...) with a merge policy that turns the readers into several merges and with SerialMergeScheduler, and the first merge fails (for example disk full); the call throws, adds nothing, and the writer stays open and not tragic. You expect that failed call to be over, so you close its readers and later call addIndexes with other, valid readers, which should merge exactly those readers. Instead the failed call's unstarted merges are still in the writer's shared addIndexes queue, so the next call runs them first and throws AlreadyClosedException 'this IndexReader is closed', leaving its own merge queued in turn, so later calls keep failing this way until rollback() or close(); if you kept the old readers open, the next call silently runs the stale merge and writes a segment that is never used.",
   "impact_class": "crash",
   "introduced_commit": "698f40ad51af on main (branch_9x backport 5dd8e9bdc5ae, PR #1051), PR #633 'LUCENE-10216: Use MergeScheduler and MergePolicy to run addIndexes(CodecReader[]) merges.' (vigyasharma; GitHub #11253): it added the writer-wide AddIndexesMergeSource queue (pendingAddIndexesMerges), registered every merge of the findMerges(CodecReader...) spec in it before calling the merge scheduler, and gave the failure path a finally block that deletes files of merges with merge info but never dequeues unstarted merges [read]",
   "introduced_date": "2022-07-06 on main (698f40ad51af); 2022-08-01 on branch_9x (5dd8e9bdc5ae)",
   "first_affected_version": "9.4.0 [exec]; 9.3.0 and older do not have the code: addIndexes(CodecReader...) merged all readers inline without a merge scheduler or queue [exec]",
   "affected_versions": "Every release from 9.4.0 to 10.5.2 and main [exec]; the other releases 9.4.1-9.12.2 and 10.1.0-10.5.1 [read]. Not affected: 9.3.0 and older [exec]. 10.6.0 (released 2026-10-29) not tested. Not fixed upstream: no main or branch_10x commit up to 2026-10-26 and no open PR changes the failure path [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9738",
    "https://issues.apache.org/jira/browse/LUCENE-8692",
    "https://github.com/apache/lucene/issues/633",
    "https://github.com/apache/lucene/issues/11253",
    "https://issues.apache.org/jira/browse/LUCENE-10216",
    "https://github.com/apache/lucene/issues/15863"
   ],
   "doc": "",
   "repro": "repro/LFV-436/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-629",
   "priority": "low",
   "priority_rank": 793,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter addIndexes(CodecReader...) (writer-wide AddIndexesMergeSource queue, SerialMergeScheduler)",
   "title": "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",
   "summary": "Two threads call addIndexes(CodecReader...) on one IndexWriter configured with SerialMergeScheduler; call A's source is corrupt (or hits a read error) and call B's source is valid. You expect A to fail with its own exception and B to add its documents, as happens in either serial order and with the default ConcurrentMergeScheduler, because IndexWriter is documented as safe for concurrent calls to any method and each addIndexes call already rethrows the failures of its own merges. Instead B, which holds the scheduler, runs A's queued merge on its own thread after finishing its own, receives A's exception (for example CorruptIndexException 'checksum failed (hardware problem?)' naming A's source file), deletes its own completed merge and adds nothing, while A throws the same exception.",
   "impact_class": "crash",
   "introduced_commit": "698f40ad51af0c42b0a4a8321ab89968e8d0860b on main ('LUCENE-10216: Use MergeScheduler and MergePolicy to run addIndexes(CodecReader[]) merges. (#633)', by vigyasharma, merged by mikemccand; issue #11253) and its branch_9x backport 5dd8e9bdc5ae72fc726a98a64bfce5119c77b558 (#1051). It added the writer-wide AddIndexesMergeSource queue, the per-call registerMerge plus mergeScheduler.merge (IndexWriter.java:3311-3312 on a9779ef3c193) with the finally block that deletes the call's own merged files on failure (:3316-3324), and AddIndexesMergeSource.merge routing failures to handleMergeException (:3472-3473), whose older rethrow (:5056, from e52d86099493, 2017) delivers them to whichever thread runs the merge; SerialMergeScheduler's synchronized drain loop (SerialMergeScheduler.java:31-40) is older and unchanged in every 9.x/10.x release [read]",
   "introduced_date": "2022-07-06 on main (698f40ad51af); 2022-08-01 on branch_9x (5dd8e9bdc5ae)",
   "first_affected_version": "9.4.0 [exec]; 9.3.0 and older are not affected [exec]",
   "affected_versions": "every release from 9.4.0 through 10.6.0 and main a9779ef3c193 and 645d4fe14a20; not fixed upstream. [exec] the minimal test fails on the 10.6.0 release jars and on main 645d4fe14a20, -ea and -da (2026-10-31); the follow-up's version-neutral public-API history test fails on 9.4.0, 9.12.3, 10.0.0, 10.5.2 and main under -ea and -da (its both-valid control passes everywhere); the independent reproduction's test fails on 10.5.2 (-ea and -da), 9.12.3 and 9.4.0; the intended-behaviour check's natural-trigger probe fails on 10.5.2 and 9.4.0; the finder's repro fails on 9.4.0, 9.12.3, 10.0.0 and 10.5.2; the security probe reproduces the defect on 10.5.2. [read] the releases in between (9.4.1-9.12.2, 10.1.0-10.5.1) by git tag --contains and a static scan of every tag (shared queue present, merge() calls handleMergeException, handleMergeException rethrows, SerialMergeScheduler.java identical); branch_10_6 (10.6.0, released 2026-10-29) and the unreleased branch_10x carry the same code; no commit on upstream main (head a95c754ee003, 2026-10-26) or branch_10x after a9779ef3c193 touches IndexWriter.java or SerialMergeScheduler.java. Not affected: 9.3.0 and older [exec].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-629.html",
   "repro": "repro/LFV-629/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-632",
   "priority": "low",
   "priority_rank": 794,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter addIndexes(CodecReader...) entry check vs deleteAll (abortMerges)",
   "title": "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",
   "summary": "One thread calls deleteAll() on an IndexWriter while a merge is running, and another thread calls addIndexes(CodecReader...) on the same writer. You expect the overlapping call either to succeed or to fail with MergePolicy.MergeAbortedException, as deleteAll's javadoc says for concurrent addIndexes(CodecReader[]) callers and as most such overlaps do. Instead, when the call reaches its entry check while deleteAll is waiting for the running merge to abort, it throws AlreadyClosedException 'this IndexWriter is closed. Cannot execute addIndexes(CodecReaders...) API' although the writer is open: isOpen() is true, deleteAll returns normally and the next addIndexes call on the same writer succeeds.",
   "impact_class": "wrong error",
   "introduced_commit": "698f40ad51af0c42b0a4a8321ab89968e8d0860b on main ('LUCENE-10216: Use MergeScheduler and MergePolicy to run addIndexes(CodecReader[]) merges. (#633)', by vigyasharma, merged by mikemccand; issue #11253), released through the branch_9x backport 5dd8e9bdc5ae72fc726a98a64bfce5119c77b558 (#1051). It replaced 'ensureOpen(); assert merges.areEnabled();' at this spot with 'ensureOpen(); if (merges.areEnabled() == false) throw new AlreadyClosedException(\"this IndexWriter is closed. Cannot execute addIndexes(CodecReaders...) API\")' [read]. The reachable state (an open writer whose merges are disabled during deleteAll's abort wait) is older: LUCENE-9473 (8480329213b on master, a07da4a3193 on branch_8x, 2020-08-24, first released in 8.7.0) made abortMerges() disable merges for deleteAll too, and from 8.7.0 to 9.3.0 the same interleaving only trips the internal 'assert merges.areEnabled()' under -ea and has no effect under -da [exec]",
   "introduced_date": "2022-07-06 on main (698f40ad51a); 2022-08-01 on branch_9x (5dd8e9bdc5a)",
   "first_affected_version": "9.4.0 [exec]; 9.3.0 is the last release without the AlreadyClosedException [exec]",
   "affected_versions": "every release from 9.4.0 through 10.6.0 and main a9779ef3c193 and 645d4fe14a20 [exec]. Not affected [exec]: 9.1.0, 9.2.0, 9.3.0 (canonical repro) and 8.5.2, 8.6.3, 8.7.0, 8.11.4, 9.0.0 (history variant); from 8.7.0 to 9.3.0 the overlap trips an internal AssertionError under -ea only. Not fixed upstream [read]: upstream main head a95c754ee003, branch_10x, branch_10_6 and branch_9_12 still have the check, and no open PR changes it.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-632.html",
   "repro": "repro/LFV-632/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-321",
   "priority": "low",
   "priority_rank": 795,
   "novelty": "new",
   "withheld": false,
   "area": "core / search: TermInSetQuery equality (MultiTermQuery rewrite methods); consequence in index / IndexWriter delete-by-query buffering",
   "title": "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",
   "summary": "Since 9.6.0 TermInSetQuery is a MultiTermQuery whose rewrite method decides which documents it matches and how it scores, but its equals/hashCode still compare only the field and terms: new TermInSetQuery(\"f\", [a]) equals SortedSetDocValuesField.newSlowSetQuery(\"f\", [a]) although on a field with only doc values they match 0 and 1 documents, and on an ordinary field new TermInSetQuery(\"f\", [a, b]) equals its TopTermsScoringBooleanQueryRewrite(1) variant although they match 2 and 1 documents. You expect queries that match different documents to be unequal, as PrefixQuery, AutomatonQuery, FuzzyQuery and TermRangeQuery are when only the rewrite method differs. Instead anything keyed on the un-rewritten query treats the two as one: IndexWriter.deleteDocuments with both queries in one flush window applies only the first, so a doc-values delete silently does not happen, or a document added in between is deleted although no call matched it.",
   "impact_class": "data corruption",
   "introduced_commit": "3809106602a9675f4fd217b1090af4505d4ec2a7 on main and its 9.x backport fa1d050df1d40f80f9dd17aeed1614bd05fbac83, apache/lucene#12156 by gsmiller, 'Remove custom TermInSetQuery implementation in favor of extending MultiTermQuery' [read]. The doc-values trigger comes from #12175 (main 569533bd76a, 9.x 5ff8ea4952a), which made SortedSetDocValuesField.newSlowSetQuery return new TermInSetQuery(DOC_VALUES_REWRITE, ...) [read]",
   "introduced_date": "2023-03-01 (commit dates of 3809106602a, fa1d050df1d and the #12175 commits; the 9.6.0 tag commit is dated 2023-05-03)",
   "first_affected_version": "9.6.0 [exec] (9.5.0 is not affected: TermInSetQuery extends Query and has no rewrite method there; the finder repro does not compile and the history probe reports the API absent [exec])",
   "affected_versions": "9.6.0 to 9.12.3, 10.0.0 to 10.6.0 and main ea57360912ed and 645d4fe14a20. [exec] the minimal test fails on main 645d4fe14a20 (-ea and -da) and on the 10.6.0, 10.5.2, 10.0.0, 9.12.3 and 9.10.0 release jars (-ea), 2026-10-31; the finder's JUnit fails 2 of 3 on main (-ea and -da), 10.5.2, 10.0.0, 9.12.3 and 9.6.0, and so does the version-portable history probe; the independent reproduction's independent JUnit fails 3 of 5 on main (-ea and -da), 10.5.2, 9.12.3 and 9.6.0; the intended-behaviour check's doc-values control fails 2 of 2 on main (-ea and -da) and 10.5.2; the delete-by-query probe fails 3 of 8 on main (-ea and -da) and 10.5.2, and its default-IndexWriterConfig variant 3 of 3 on main (-ea and -da) and 10.5.2 (not run on 9.x, whose newSlowSetQuery has no Collection overload). [read] 9.7.0 to 9.12.2 and 10.1.0 to 10.5.1: equals/equalsTo/hashCode are identical in every release tag and never read the rewrite method; on 9.x the deprecated MultiTermQuery#setRewriteMethod is a second way to change it. Not fixed: unchanged on upstream main, branch_10x, branch_10_6 and branch_9_12 (2026-10-26) [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-321.html",
   "repro": "repro/LFV-321/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-946",
   "priority": "low",
   "priority_rank": 796,
   "novelty": "known",
   "withheld": false,
   "area": "queries / spans: SpanMultiTermQueryWrapper equality (span rewrite methods); consequence in index / IndexWriter delete-by-query buffering",
   "title": "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",
   "summary": "You build new SpanMultiTermQueryWrapper(new PrefixQuery(f:aa)) twice and call setRewriteMethod(new TopTermsSpanBooleanQueryRewrite(1)) on one of them, so on a 6-document index one wrapper matches all 6 documents and the other matches 1, and you expect the two to be unequal, as two PrefixQuery objects that differ only in their rewrite method are. Instead equals and hashCode compare only the wrapped PrefixQuery, so the wrappers are equal with equal hash codes. IndexWriter buffers delete-by-query calls in a HashMap keyed by the query, so deleteDocuments(top1) followed by deleteDocuments(all) in one flush window keeps only the first and commits with 5 of the 6 matching documents still live, and in the other order a document added between the two calls is deleted although no delete issued after it matches it.",
   "impact_class": "data corruption",
   "introduced_commit": "e5de90bbf1288e88f83e039f09797e9493da2be9 on trunk (SVN r1725719, 'LUCENE-6984: SpanMultiTermQueryWrapper no longer modifies its wrapped query', by romseygeek; issue #8041 = LUCENE-6984 'MultiTermQuery mutability can cause assertion failures in BooleanQuery', an SVN-era JIRA patch with no GitHub PR) and its branch_5x backport d3040ac17c70f46c13c3b77bd11987a39e62f23c (r1725724), which put it into 5.5.0: the change moved the span rewrite method out of the wrapped MultiTermQuery (whose equals compares it) into a new mutable wrapper field and left equals/hashCode comparing only the wrapped query [exec]. The API itself dates from 3.1 (LUCENE-2754), when setRewriteMethod stored the method in the wrapped query, so equality covered it.",
   "introduced_date": "2016-01-20 (author dates of e5de90bbf12, 13:36:56Z, and of the backport d3040ac17c7, 14:10:11Z)",
   "first_affected_version": "5.5.0 [exec] (the version-portable probe fails on 5.5.0 and passes on 5.4.1, 5.4.0 and 4.10.4 [exec]; 6.0.0 is the first trunk release with the commit)",
   "affected_versions": "Every release from 5.5.0 to 10.5.2 (5.5.x, 6.x, 7.x, 8.x, 9.x, 10.0 to 10.5), 10.6.0 (released 2026-10-29) and main. [exec] the version-portable probe fails (equals true, numDocs 5 instead of 0) on 5.5.0, 5.5.5, 6.0.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2, the branch_10_6 head 4ae946e5a9b and main a9779ef3c193; the finder's 4-test JUnit fails 4 of 4 on main (-ea and -da, seed DEADBEEF), branch_10_6 4ae946e5a9b, 10.5.2 and 9.12.3; its FrequentTermsSpanBooleanQueryRewrite variant fails 3 of 3 on main (-ea and -da) and branch_10_6; the independent reproduction's own JUnit fails 5 of 7 on main (-ea and -da), 10.5.2 (-ea and -da), 9.12.3 and branch_10_6, its 2 controls pass; the intended-behaviour check re-ran the finder's JUnit on main (-ea and -da), 10.5.2 (-da) and branch_10_6 (-da), 4 of 4 each; the adjudication re-ran the independent reproduction's (seed 5EED7A0D, -ea and -da, 5 of 7) and the finder's (-ea, 4 of 4); the registration check re-ran the finder's (-da, seed 5EED3770, 4 of 4). [read] the releases not executed: equals/hashCode are semantically unchanged from 5.5.0 to main. 10.6.0 widens the trigger without being a regression: TopTerms(1) and FrequentTerms(1) select disjoint documents, so either delete order loses a delete. Not fixed upstream: SpanMultiTermQueryWrapper.java last changed on main by 156fb97fd33 (#16484, 2026-08-18) and on branch_10_6 by f6fce7e42c5 (#16592, build backport, 2026-09-05); upstream main head 645d4fe14a20 (2026-10-28). All runs on Linux aarch64 with JDK 25.0.3; the branch_10_6 runs used a snapshot jar directory whose third-party dependency graph came from an older main checkout.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/7571",
    "https://issues.apache.org/jira/browse/LUCENE-6513",
    "https://github.com/apache/lucene/issues/16484",
    "https://github.com/apache/lucene/issues/8041",
    "https://github.com/apache/lucene/issues/11467",
    "https://github.com/apache/lucene/issues/722"
   ],
   "doc": "",
   "repro": "repro/LFV-946/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-295",
   "priority": "low",
   "priority_rank": 797,
   "novelty": "new",
   "withheld": false,
   "area": "queries / intervals (PayloadFilteredTermIntervalsSource equality; IntervalQuery dedup and cache keys)",
   "title": "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",
   "summary": "You index a field with a payload at each position and build two sources on the same term with different payload filters, for example a@0 = Intervals.term(\"a\", payload is 'pos: 0') and a@1 = Intervals.term(\"a\", payload is 'pos: 1'), which on their own match different documents. You expect Intervals.or(a@0, a@1) to match both sets, ordered(a@0, a@1) to match the document 'a a', FILTER a@0 + FILTER a@1 to match only that document, and a query cache to keep the two queries apart. Instead PayloadFilteredTermIntervalsSource.equals/hashCode compare only the term, so the two sources are equal: or() keeps one of them, ordered() and unordered() become 'a@0 twice' and match nothing, the two FILTER clauses collapse into one (extra hits), MUST a@0 + MUST_NOT a@1 is rewritten to MatchNoDocsQuery, and a cached searcher returns the first filter's hits for the second, all with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "4991e3a1f47b (main; branch_9x backport 96bc866dfed, the commit in 9.9.0), apache/lucene#12827 'Fix PayloadFilteredTermIntervalsSource equals' by eumus (merged by mikemccand, 2023-11-21): it fixed a ClassCastException in equals (a cast to TermIntervalsSource) by changing only the cast, which made the existing term-only equality reachable and added testPayloadFilteredTermIntervalsSourceEquals (two separately written always-true filters must be equal) [exec]; latent since 5ca25249274 (main) / 13aac3becde (branch_8x), LUCENE-8694 'Payload-filtered term intervals' (now apache/lucene#9740, committed by romseygeek 2019-03-18), which wrote hashCode = Objects.hash(term) and a term-only equals copied from TermIntervalsSource with the wrong cast, so before 9.9.0 equals of two distinct instances threw instead of returning true [read]",
   "introduced_date": "2023-11-21 (#12827 merged; 9.9.0 tagged 2023-12-04); latent equality code since 2019-03-18 (LUCENE-8694, 8.1.0)",
   "first_affected_version": "9.9.0 [exec]; 9.8.0 is the last release without wrong results: the same calls throw ClassCastException from equals there [exec], as in every release from 8.1.0 [exec]; 8.0.0 has no payload-filter overload of Intervals.term [exec]",
   "affected_versions": "every release from 9.9.0 through 10.6.0 and main ea57360912ed and 645d4fe14a20 [exec]; 8.1.0-9.8.0 have the crash form instead (ClassCastException from the same equals, fixed by #12827) [exec]; 8.1.x shipped the class in the sandbox module, the queries module has it from 8.2.0; not affected: 8.0.0 and earlier (API absent) [exec]; branch_10x and branch_10_6 have the same equals/hashCode [read]; not fixed upstream [read]; all runs on aarch64 with JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-295.html",
   "repro": "repro/LFV-295/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-464",
   "priority": "low",
   "priority_rank": 798,
   "novelty": "new",
   "withheld": false,
   "area": "queries / intervals (PayloadFilteredTermIntervalsSource Matches API; Weight#matches consumers)",
   "title": "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",
   "summary": "You index text with payloads, for example 'big|adj dog|noun' (doc 0) and 'big|adj dog|verb' (doc 1) through DelimitedPayloadTokenFilter, and query IntervalQuery(f, Intervals.term(\"dog\", payload is 'noun')), which correctly hits only doc 0. You expect Weight#matches to be null for doc 1, which the query does not match, and non-null for doc 1 as a hit of +f:big -<that query>. Instead the payload-filtered source returns an empty but non-null MatchesIterator for every document that contains 'dog' at all, so Weight#matches reports a match for the non-hit and the BooleanQuery returns null Matches for its real hit (the default UnifiedHighlighter then leaves that hit unhighlighted, and Lucene monitor's HighlightsMatch matcher reports the non-hit as a match), while hits, counts and scores stay correct.",
   "impact_class": "silent wrong results",
   "introduced_commit": "5ca25249274bd4232b0faa049814d2b3b192abdb (main; branch_8x backport 13aac3becde7770c8c4e6b33102432f7dee99a10), LUCENE-8694 'IntervalsSource that filters by payload' (now GitHub issue #9740) by romseygeek, committed from the JIRA patch (no GitHub PR): it added PayloadFilteredTermIntervalsSource with a private matches(TermsEnum, int) that returns null only when pe.advance(doc) != doc and applies the payload filter lazily in next(), a shape copied from TermIntervalsSource.matches (LUCENE-8422, 1acfca5ebcc), where it is correct because every position of the term is an interval; IntervalQuery's Weight#matches already handed any non-null iterator to MatchesUtils.forField as a hit, so the wrong result existed from the first commit [read]; later commits to the file (f1782d0dd11 LUCENE-8477, 114db75abc4 / 46cc24d77ec LUCENE-8856 module move, 7c1ba1aebee LUCENE-9099, 8ef6a0da568 LUCENE-9570 reformat, 4991e3a1f47 #12827 equals) leave the emptiness logic unchanged [read]",
   "introduced_date": "2019-03-18 (commit date on main and branch_8x; author date 2019-02-15)",
   "first_affected_version": "8.1.0 [exec] (sandbox module, package org.apache.lucene.search.intervals; queries module from 8.2.0 [exec], LUCENE-8856); 8.0.0 has no Intervals.term(term, payloadFilter) [exec]",
   "affected_versions": "every release from 8.1.0 through 10.5.2 (all 59 releases) and main ea57360912ed [exec]; not affected: 8.0.0 and earlier (API absent) [exec]; not fixed upstream: on upstream main 49483e82b357 and on branch_10x and branch_10_6 the file was last changed by #12827 (2023-11-21) [read], and 10.6.0 (released 2026-10-29) fails too [exec]; all runs on aarch64 with JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-464.html",
   "repro": "repro/LFV-464/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-292",
   "priority": "low",
   "priority_rank": 799,
   "novelty": "new",
   "withheld": false,
   "area": "queries / intervals (IntervalQuery equality, consumed by BooleanQuery and DisjunctionMaxQuery duplicate-clause handling)",
   "title": "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",
   "summary": "You build two IntervalQuery objects on the same field and term that differ only in their scoring pivot, new IntervalQuery(\"f\", Intervals.term(\"a\"), 1f) and the same with 100f, and combine them as SHOULD clauses of a BooleanQuery. You expect the document 'a b a c a' to score the sum of the two clause scores, 0.75 + 0.0291 = 0.7791, because the javadoc documents pivot and exp as parameters that change the score. Instead IntervalQuery.equals/hashCode compare only the field and the intervals source, so the two queries are equal, BooleanQuery.rewrite merges them into the single clause (f:a)^2.0 that keeps only the first clause's pivot, and the document scores 1.5; with the clauses swapped it scores 2 x 0.0291 = 0.0583, so the score also depends on clause order.",
   "impact_class": "silent wrong results",
   "introduced_commit": "a8266492416dbc2fcf665983d1cac141e50fa9eb on master and its branch_8x twin 18c3986cc4bdb38949fae14bd771621345d41776 (the commit in the 8.0.0 release tag), 'LUCENE-8633: Remove term weighting from IntervalQuery scores' (romseygeek; JIRA patch on LUCENE-8633, now apache/lucene#9679, reviewed by jimczi; no PR): it added the scoreFunction field, the public (field, source, pivot) and (field, source, pivot, exp) constructors and IntervalScoreFunction with its own value-based equals/hashCode, but left IntervalQuery.equals/hashCode as written in LUCENE-8196 (00eab54f9d6, 2018-04-03), when field and intervalsSource were the only state [read]. The merge that exposes it, BooleanQuery's duplicate-clause collapse (LUCENE-7925, ab793e7ab56, 7.1.0), is older.",
   "introduced_date": "2019-01-16",
   "first_affected_version": "8.0.0 [exec] (lucene-sandbox, package org.apache.lucene.search.intervals); 7.7.1 and 7.7.3 are not affected [exec], so 7.x (IntervalQuery since 7.4.0) has no scoring state for equals to miss",
   "affected_versions": "every release from 8.0.0 through 10.6.0 and main ea57360912ed. [exec] the one-test repro fails on the 10.6.0 jars with -ea and -da (2026-10-31); the follow-up history sweep ran the finder's JUnit (package/import-only variants for 8.0-8.1 and 8.2-9.0) on SHA-1-verified release jars: 8.0.0, 8.1.1, 8.2.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main all fail 2 of 2 with identical numbers (-ea; main also -da); the independent reproduction's JUnit fails 4 of 5 on main (-ea, -da), 10.5.2, 9.12.3 and 8.11.4; the intended-behaviour check re-ran 10.5.2; the security probe ran on 9.12.3, 10.5.2 and main. [read] no commit since LUCENE-8633 changed the compared fields; equals/hashCode on main and branch_10x (fetched 2026-10-26) still omit scoreFunction. Module: lucene-sandbox 8.0-8.1, lucene-queries (org.apache.lucene.queries.intervals) from 8.2.0 (LUCENE-8856). Intermediate releases not listed were not executed. Not fixed upstream. All runs on aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-292.html",
   "repro": "repro/LFV-292/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-403",
   "priority": "low",
   "priority_rank": 800,
   "novelty": "known",
   "withheld": false,
   "area": "join / JoinUtil numeric score join (PointInSetIncludingScoreQuery equals/hashCode)",
   "title": "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",
   "summary": "You build two numeric score joins with JoinUtil.createJoinQuery(\"fromId\", false, \"toId\", Integer.class, fromQuery, searcher, ScoreMode.Max), one over from-index A and one over from-index B; both collect the join value 7 and score the to-document 0.3648 and 0.4311, and you expect DisjunctionMaxQuery([qa, qb], 0) to give the maximum 0.4311, as the string-key joins over the same data do. Instead qa.equals(qb) is true with equal hash codes, because PointInSetIncludingScoreQuery's equals/hashCode compare the score mode, to field, from query and collected join values but not the per-value scores (aggregatedJoinScores) or multipleValuesPerDocument, so DisjunctionMaxQuery keeps one of the two equal disjuncts (it rewrites to '(toId:{7} | toId:{7})') and scores 0.3648. The same happens with one from searcher and two from fields whose value sets coincide, where the result then depends on clause order, and BooleanQuery SHOULD(qa) SHOULD(qb) is folded into one boosted clause that loses the second join's scores.",
   "impact_class": "silent wrong results",
   "introduced_commit": "2babaf8c3d1710280ef53da3d7ba286615e7293e (LUCENE-7095 'Add point values support to the numeric field query time join', by martijnvg; JIRA patch era, migrated as apache/lucene#8151, no PR; backports e26a4431942 on branch_6x and 5733f05c70d on branch_6_0) created PointInSetIncludingScoreQuery with an equals/hashCode that omit aggregatedJoinScores and multipleValuesPerDocument [read]. Later edits of these lines changed no compared field: e44509f2dfc (LUCENE-7277, sameClassAs/classHash), 85c1319c767 (LUCENE-7810, adds scoreMode, 6.6.0), 7f8b7ffbcad (LUCENE-9570, formatting). Wrong scores became observable through two later core changes that rely on query equality [exec]: LUCENE-7925 (apache/lucene#8974; 325263a9398 on branch_7x, ab793e7ab56 on master, 7.1.0) folds equal BooleanQuery SHOULD/MUST clauses into one boosted clause, and LUCENE-9940 (apache/lucene#10979, PR apache/lucene#110, f7a3587091f, 9.0.0) keeps DisjunctionMaxQuery disjuncts in a Multiset. Not a regression: the omission is original to the class",
   "introduced_date": "2016-03-25 (2babaf8c3d1, the equality defect); 2017-08-21 (LUCENE-7925, the BooleanQuery manifestation); 2021-04-29 (LUCENE-9940, the DisjunctionMaxQuery manifestation)",
   "first_affected_version": "6.0.0 [exec] (2016, the first release with the class: joins with different scores compare equal with equal hash codes, but scores are still correct); wrong scores first in 7.1.0 [exec] (BooleanQuery SHOULD and DisjunctionMaxQuery with tie-breaker 1.0) and in 9.0.0 [exec] (DisjunctionMaxQuery with tie-breaker below 1, the finder's repro); 5.5.5 has no such API [exec]",
   "affected_versions": "every release from 6.0.0 through 10.5.2 and main ea57360912ed has the defect [read] [exec] [exec]. Releases between the executed ones were checked by source only. All runs used JDK 25.0.3",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/8861",
    "https://issues.apache.org/jira/browse/LUCENE-7810",
    "https://github.com/apache/lucene/issues/7413",
    "https://issues.apache.org/jira/browse/LUCENE-6352",
    "https://github.com/apache/lucene/issues/5769",
    "https://github.com/apache/lucene/issues/5115"
   ],
   "doc": "",
   "repro": "repro/LFV-403/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-302",
   "priority": "low",
   "priority_rank": 801,
   "novelty": "new",
   "withheld": false,
   "area": "spatial-extras / value sources (ShapeAreaValueSource equality, consumed by FunctionScoreQuery, area filters and BooleanQuery duplicate-clause handling)",
   "title": "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",
   "summary": "You index one rectangle with BBoxStrategy (planar area 800) and score it with two FunctionScoreQuery SHOULD clauses whose sources differ only in the multiplier, new ShapeAreaValueSource(strategy.makeShapeValueSource(), ctx, false, 1.0) and the same with 3.0, expecting the sum 800 + 2400 = 3200. Instead ShapeAreaValueSource equals/hashCode compare only geoArea and the shape source, so the two clauses are equal, BooleanQuery.rewrite merges them into one clause with boost 2 that keeps only the first multiplier, and the document scores 1600 (4800 with the clauses swapped). Area filters built on such sources are de-duplicated the same way, so a FILTER or MUST_NOT area clause can be silently dropped and the hit set changes (2550 hits expected, 3800 returned).",
   "impact_class": "silent wrong results",
   "introduced_commit": "8fd247cc0e5fded62a5b349ba82966a0c86bd61e (trunk, svn r1649243) and its branch_5x twin c2b1b11a72fb08a508a6f0f6d0d0dd75e7db5ea1 (svn r1649245, same day, byte-identical file; 5.0.0 gets the bug from it), 'SOLR-6797: spatial distanceUnits=degrees|kilometers|miles units=degrees is now deprecated.' (dsmiley; JIRA SOLR-6797 'Add score=degrees|kilometers|miles for AbstractSpatialFieldType', no GitHub PR): it added the non-final multiplier field, the fourth constructor parameter and '* multiplier' in the value, but did not touch equals, hashCode or toString, which still compare only geoArea and shapeValueSource as written in 7e0aff8dabc (LUCENE-5714/LUCENE-5779, 2014-07-08), when the only other field was ctx, which the class comment places outside identity [read]. The merge that turns it into wrong scores, BooleanQuery's duplicate SHOULD/MUST collapse (LUCENE-7925, ab793e7ab56 / branch_7x 325263a9398, 2017-08-21, first released in 7.1.0), came later.",
   "introduced_date": "2015-01-03",
   "first_affected_version": "5.0.0 [exec] for the equality violation (values 800 and 2400, yet the two sources and the FunctionQuery objects built on them compare equal with the same hashCode); 4.10.4 is not affected [exec]. Wrong scores from a plain BooleanQuery start in 7.1.0 [exec]; 7.0.1 still keeps both clauses and scores 3200 correctly [exec].",
   "affected_versions": "every release from 5.0.0 through 10.6.0 and main ea57360912ed has the equality violation; wrong BooleanQuery scores from 7.1.0 on; the one-test repro fails on the 10.6.0 jars with -ea (2026-10-31) [exec]. [exec] the follow-up history sweep (main() repros with -da on SHA-1-verified release jars; API-adapted variants for 4.x, 5.x, 6.x and 7.0+): equality fails on 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.1, 7.1.0, 8.8.2, 8.9.0, 8.10.0, 8.10.1, 8.11.0, 8.11.1, 8.11.2, 8.11.3, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main; the disjunction scores 1600 instead of 3200 on 7.1.0, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main, and correctly on 7.0.1; 4.10.4 not affected (API absent). The finder's JUnit and the independent reproduction's JUnit fail on main (-ea, -da), 10.5.2 and 9.12.3; the intended-behaviour check's on main (-ea, -da) and 10.5.2; the security probe (filter and cache paths) on main (-ea, -da) and 10.5.2. [read] a scan of every release tag in the history clone finds the multiplier present and absent from equals/hashCode in every tag from 5.0.0 to 10.5.2; the equals/hashCode bodies are unchanged since 2014. Releases between 5.0.0 and 7.0.1 were checked for the equality violation only, and the wrong-hit paths (filter de-duplication, query cache) only on 10.5.2 and main. Not fixed upstream. All runs on aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-302.html",
   "repro": "repro/LFV-302/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-216",
   "priority": "low",
   "priority_rank": 802,
   "novelty": "new",
   "withheld": false,
   "area": "expressions / ExpressionValueSource equality (cache keys of FunctionMatchQuery and facet DoubleRange drill-down queries built on expressions)",
   "title": "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",
   "summary": "You compile the same expression text 'f(x)' twice with custom function maps that bind f to different functions (Math.abs in one, negation in the other), wrap each in a FunctionMatchQuery with the same 'v > 0' predicate, and expect two different queries, because on documents with x = -3, -2, -1, 1, 2 the first matches 5 documents and the second 3. Instead the two value sources, and therefore the two queries, compare equal with equal hash codes: ExpressionValueSource.equals/hashCode look only at the source text, the bound variables and needsScores, not at the functions the text was compiled with. A query cache then answers the second query with the first query's cached matches, so count returns 5 instead of 3, with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "b01e6023e1cd (b01e6023e1cd3c62260b38c05c8d145ba143a2ac on master; the same change is a41643285e8e on branch_7x, the commit contained in 7.3.0), LUCENE-8099 'Deprecate CustomScoreQuery, BoostedQuery, BoostingQuery' = apache/lucene#9147, by romseygeek, no PR (pre-GitHub-PR era, patch attached to the JIRA issue): it changed ExpressionValueSource.hashCode from expression.hashCode() to expression.sourceText.hashCode() and equals from expression.equals(other.expression) (object identity, since Expression has never overridden equals) to expression.sourceText.equals(other.expression.sourceText); neither the commit message, the CHANGES entry nor the issue mentions the equality change [read] [exec]",
   "introduced_date": "2017-12-18 (committed on master and branch_7x; author date 2017-12-14)",
   "first_affected_version": "7.3.0 [exec]; 7.2.1 is the last unaffected release [exec] (custom function maps exist since 4.6.0, but up to 7.2.1 two separate compilations never compared equal)",
   "affected_versions": "7.3.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2 (the last release before 10.6.0), 10.6.0 [exec] and main ea57360912ed. [exec] the follow-up's two-stage version probe (equality of 'f(x)' with f = Math.abs vs f = negate, then FunctionMatchQuery counts through LRUQueryCache(1000, 32 MB) with an always-cache policy on a 20000-doc segment) fails on 7.3.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-da; 7.3.0, 10.5.2 and main also -ea: equal, same hash, cached 20000 instead of 10000) and passes on 6.6.6, 7.0.0 and 7.2.1; the independent reproduction's JUnit fails on main, 10.5.2 and 9.12.3 (-ea and -da); with stock IndexSearcher defaults it reproduces on 10.5.2 (the independent reproduction, the cross-model review, the intended-behaviour check) but not on main, where the query cache is off by default. [read] the equality lines are present at tags 7.7.3, 8.0.0, 8.8.1, 9.0.0, 9.12.3, 10.0.0 and 10.5.2, and git log -L shows no logic change after b01e6023e1c; intermediate releases (7.3.1-7.6.0, 8.1.0-8.11.3, 9.1.0-9.12.2, 10.1.0-10.5.1) were not executed; branch_10x and branch_10_6 carry the same code (finder read; the last commit touching ExpressionValueSource.java on main, branch_10x and branch_10_6 is 43c0d72b94c, 2023-09-16, javadoc only). Not fixed upstream.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-216.html",
   "repro": "repro/LFV-216/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-506",
   "priority": "low",
   "priority_rank": 803,
   "novelty": "known",
   "withheld": false,
   "area": "analysis / CharArraySet and CharArrayMap (stop-word, keyword and stem-override sets and maps)",
   "title": "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",
   "summary": "You build a CharArrayMap with put(\"foo\", 1) and put(\"bar\", 2), or a CharArraySet {foo, bar} such as an analyzer's stop set, and call hashCode() twice, or add it to a HashSet or HashMap and look it up again. You expect what Object.hashCode and Set/Map.hashCode require: the same value on every call to an unchanged object and equal hash codes for equal objects, so the lookup finds it. Instead every call returns a different value (for example -1124182418, then -1901051422), two equal sets hash differently, and HashSet.contains or HashMap.get with the very same instance returns false or null, because the inherited AbstractMap/AbstractSet hashCode sums the identity hash codes of a new map entry and a new char[] copy of each key that every iteration creates.",
   "impact_class": "minor",
   "introduced_commit": "924d7faa6843255986f765219ca4b7f5b93f3649 (SVN r906032, 2010-02-03), LUCENE-2247 = GitHub issue #3323 'Add a CharArrayMap<V> for performance improvements in some stemmers and synonym filters' (patch by uschindler, +1 from rmuir; an SVN commit, no pull request): it created CharArrayMap with EntryIterator.next() returning a new MapEntry (no equals/hashCode) and MapEntry.getKey() returning keys[pos].clone(), and switched CharArraySet.iterator() from new Strings (a stable content hash) to map.originalKeySet().iterator() for matchVersion >= LUCENE_31 [read]. Widened by a58c26978f5c7a0dbbbe535c627ef5388fad550b (LUCENE-2781 = #3855 'drop deprecations from trunk', rmuir, 2010-11-30, first released in 4.0.0), which removed the String-iterator branch, so CharArraySet is affected for every matchVersion from 4.0.0 [read]. A 3.1 regression for CharArraySet; CharArrayMap has been affected since it was added",
   "introduced_date": "2010-02-03 (924d7faa6843, LUCENE-2247); 2010-11-30 for the widening to every matchVersion (a58c26978f5c, LUCENE-2781)",
   "first_affected_version": "3.1.0 [exec] (tag releases/lucene-solr/3.1, 2011-03-30). 3.0.3, the last release without the commit, is not affected [exec]. In 3.1.0 to 3.6.2 CharArraySet is affected only for matchVersion >= LUCENE_31 [exec]; from 4.0.0 for every matchVersion",
   "affected_versions": "every release from 3.1.0 to 10.6.0 (10.6.0 by reading) and main ea57360912ed (131 release tags contain 924d7faa6843); never fixed: no revision of either class has ever declared hashCode() or equals(Object) (git log --all -G) [read]. [exec] the follow-up's reflection-based history probe fails on 3.1.0, 3.6.2, 4.0.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.0.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main and passes on 3.0.3; the finder's JUnit fails 4 of 4 on main (-ea, -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 6 of 7 (the empty-set control passes) on main (-ea, -da), 10.5.2 (-ea, -da) and 9.12.3; the intended-behaviour check's JUnit fails 6 of 8 (2 controls pass) on main (-ea, -da), 10.5.2 and 9.12.3. Other releases by unchanged line history [read]. Upstream main, branch_10x and branch_10_6 have not touched hashCode, equals, MapEntry or entrySet; open PR #16261 would fix only the CharArraySet half. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16261",
    "https://github.com/apache/lucene/issues/16381",
    "https://issues.apache.org/jira/browse/LUCENE-1502",
    "https://issues.apache.org/jira/browse/LUCENE-2094",
    "https://issues.apache.org/jira/browse/LUCENE-1163",
    "https://github.com/apache/lucene/issues/16911"
   ],
   "doc": "",
   "repro": "repro/LFV-506/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1079",
   "priority": "low",
   "priority_rank": 804,
   "novelty": "new",
   "withheld": false,
   "area": "queries / function queries: valuesource.VectorSimilarityFunction equality (base of Float/Byte/Float16VectorSimilarityFunction, and so of the FunctionQuery, FunctionRangeQuery and FunctionScoreQuery that wrap them)",
   "title": "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",
   "summary": "You build two function-query value sources over the same vector field and the same query vector, one with EUCLIDEAN and one with COSINE (new FloatVectorSimilarityFunction(EUCLIDEAN, field, target) and the same with COSINE), and expect them to be unequal because they compute different scores; the class itself treats the function as part of its identity, since hashCode() and description() include it. Instead equals() compares only the two vector sources and returns true, while hashCode() returns different values, which breaks the java.lang.Object rule that equal objects have equal hash codes. The Byte and Float16 subclasses share this equals, and FunctionQuery and the other wrappers pass the false equality on.",
   "impact_class": "minor",
   "introduced_commit": "14c18d86245 (apache/lucene#12253 'GITHUB-12252: Add function queries for computing similarity scores between knn vectors', author eliaporciani, co-author and merger alessandrobenedetti; author date 2023-06-14T14:49Z, the same instant as the PR merge; branch_9x backport 433aa49b2ec the same day): it added the classes with this equals [read]. Inside the squash-merged PR, commit 7219987d52 ('Addressing review', 2023-06-13) rewrote equals with the getClass() and null checks that uschindler had asked for and dropped the similarityFunction term that the previous PR commit 901febe400 still compared; hashCode kept the field (bc504291cc made it Objects.hash(similarityFunction, vector1, vector2)) [read]. The only later commit to the file, 05af6514226 (#15329, author date 2025-10-12, doubleVal), does not touch equals or hashCode.",
   "introduced_date": "2023-06-14",
   "first_affected_version": "9.7.0 [exec]; there is no release in which this equals was correct",
   "affected_versions": "every release from 9.7.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main e1faeba08bde (12.0.0-SNAPSHOT); never fixed (upstream main head was e1faeba08bd at the 2026-11-02 search, and the last commit to the file, 05af6514226 of 2025-10-12, does not touch equals or hashCode; re-checked 2026-11-02). [exec] the one-test repro fails 1 of 1 on main with -ea and -da (seeds DEADBEEF, 5EED0497, 5EED1101 and 5EED1102), on the 10.6.0 release jars with -ea and -da, and on 10.5.2, 10.0.0, 9.12.3 and 9.7.0; the independent reproduction's own Byte-subclass test fails on main (-ea and -da), 10.6.0, 10.5.2, 9.12.3 and 9.7.0; 9.6.0 does not compile it (classes absent). [read] the equals block is byte-identical, and hashCode is Objects.hash(similarityFunction, vector1, vector2), at every releases/lucene tag from 9.7.0 to 10.6.0. The Float16VectorSimilarityFunction subclass (#16383, CHANGES 11.0.0) inherits the same equals on main and branch_11x (both unreleased). Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1079.html",
   "repro": "repro/LFV-1079/",
   "triage_status": "fix_in_progress",
   "triage_by": "sjs004 (PR #16974)",
   "triage_date": "2026-11-03",
   "triage_link": "https://github.com/apache/lucene/pull/16974",
   "triage_note": "PR #16974 references this bug.",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-448",
   "priority": "low",
   "priority_rank": 805,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-opennlp / model cache (OpenNLPOpsFactory and the OpenNLP factories' inform/create)",
   "title": "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)",
   "summary": "You build two analyzers with CustomAnalyzer.builder(configDir) from two configuration directories, each with its own OpenNLP model under the same file name (for example sent.bin and tok.bin, or a lemma dictionary), and expect each analyzer to use its own directory's files, as builder(Path) says it 'loads all resources from the given file system base directory'. Instead the OpenNLP factories keep one static, JVM-wide cache per model type keyed only by the file name, so the second analyzer silently gets the model the first directory loaded: with two valid, different tokenizer models, configB's analyzer produces configA's tokens [Hello, world, ., This, is, a, test, .] instead of its own [Hello, world., This, is, a, test.], and a directory with no such file at all still builds. The name-keyed cache is intended (LUCENE-2899), but nothing documents that file names are shared by every configuration in the JVM.",
   "impact_class": "minor",
   "introduced_commit": "3e2f9e62d772 (LUCENE-2899 'Add OpenNLP Analysis capabilities as a module', GitHub issue #3973, committed by sarowe on master, first released in 8.0.0) and its branch_7x twin b720e1ee3a52 (same message, timestamp and code; released in 7.3.0); no PR, the code came as JIRA patch attachments [read]; not a regression: the static name-keyed maps and the get-or-load-from-loader pattern are in the module's first version, and no later commit changed the key (LUCENE-8188, LUCENE-8778, LUCENE-9281, LUCENE-9317, LUCENE-9570, LUCENE-10171 #380, #14228, #15573)",
   "introduced_date": "2017-12-15 (both commits; LUCENE-2899 closed 2017-12-19)",
   "first_affected_version": "7.3.0 [exec] (released 2018-04-04; 7.2.1, the last release before, has no OpenNLP module [exec])",
   "affected_versions": "7.3.0 through 10.6.0 and main ea57360912ed [exec]; not applicable to 7.2.1 and earlier (module absent) [exec]; branch_10x and branch_10_6 not checked (code identical on main) [read]; not fixed anywhere: the last commit to OpenNLPOpsFactory.java on upstream main (ce50d3a135dc, #14228, 2025-02-24) kept the name-only key, and no open PR changes it [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-448.html",
   "repro": "repro/LFV-448/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1089",
   "priority": "low",
   "priority_rank": 806,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / FST completion (FSTCompletion.lookup empty result)",
   "title": "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",
   "summary": "You build two FSTCompletion instances from different inputs ('apple' and 'zebra'), call lookup(\"\", 5) on the first and add a fallback suggestion to the empty list it returns, and expect the second instance's lookup(\"\", 5) to still return no suggestions. Instead it returns [apple/1], with no error: lookup hands out the same private static mutable ArrayList (EMPTY_RESULT) for every empty key and for every instance with no entries, so the change shows up in every FSTCompletion in the JVM. Since 10.0.0 non-empty results are unmodifiable, so only the empty result accepts the change silently.",
   "impact_class": "minor",
   "introduced_commit": "92de7e884868f91b42689aa344c51b1b8aa8fdbb (trunk, svn r1209265) and its branch_3x backport d3e380f824a59857c3cd72e7f789e6f5682e7853 (svn r1232289; the backport shipped first, in 3.6.0), SOLR-2888 'FSTSuggester refactoring: utf8 storage, external sorts (OOM prevention), code cleanups' (svn era, no pull request). The commit created FSTCompletion with 'private static final ArrayList<Completion> EMPTY_RESULT = new ArrayList<Completion>()' (field javadoc: keep it an ArrayList so all returned lists have one type, 'monomorphic calls') and 'return EMPTY_RESULT' for an empty key or a null automaton, replacing the released predecessor FSTLookup's unmodifiable Collections.emptyList(); both lines are still the blamed ones on main apart from cosmetic edits (LUCENE-5512 diamond, LUCENE-9570 reformat) [read]. #12978 (78b4f75a2c6, author date 2023-12-30, first in 10.0.0) made non-empty results unmodifiable and left EMPTY_RESULT unchanged [read].",
   "introduced_date": "2011-12-01 (trunk 92de7e88486, author date = commit date); 2012-01-17 (branch_3x backport d3e380f824a)",
   "first_affected_version": "3.6.0 [exec], the first release that contains FSTCompletion (3.5.0 has no such class [exec]); the class it replaced, FSTLookup (released 3.3.0-3.6.2), returns an unmodifiable Collections.emptyList() [exec], so the bug came with the SOLR-2888 rewrite and no release of FSTCompletion was ever free of it",
   "affected_versions": "every release that ships FSTCompletion: 3.6.0-3.6.2 and 4.0.0-alpha through 10.6.0 (released 2026-10-29, 4ae946e5a9b), plus main e1faeba08bde (12.0.0-SNAPSHOT). Executed, all failing with 'expected:<[]> but was:<[apple/1]>': the repro JUnit on main (-ea and -da), 10.6.0 (-ea and -da), 10.5.2, 10.0.0, 9.12.3 and 9.1.0 (-da); a version-neutral main() history probe with the same steps (it passes on main with the fix) on 3.6.0, 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.6.0 and main [exec]; the other releases by a source check of all 127 release tags that contain FSTCompletion.java (8.8.2-8.11.3 are not in the local tag set; 8.8.1 [read] and 8.11.4 [exec] on either side are affected) [read]. On 9.x and earlier every result was a mutable list the caller could change, but only the empty one was shared; since 10.0.0 (#12978) the empty result is the only mutable one. Not new in 10.6 (10.5.2 fails the same test). Not fixed upstream: FSTCompletion.java on upstream main (checked 2026-11-02) is blob be9a4281f4b8, identical to e1faeba08bde, last changed by #16056 (2026-05-14), which does not touch EMPTY_RESULT [read]. Executed on Linux aarch64 with JDK 25.0.3 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1089.html",
   "repro": "repro/LFV-1089/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-198",
   "priority": "low",
   "priority_rank": 807,
   "novelty": "new",
   "withheld": false,
   "area": "search / MultiCollectorManager (composition of CollectorManagers)",
   "title": "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",
   "summary": "You wrap one collector manager in a MultiCollectorManager, for example new MultiCollectorManager(new MultiCollectorManager(top1, top5)) from code that builds the manager list dynamically, and expect the same results as searching with the inner manager directly. Instead, because MultiCollector.wrap returns a single collector unwrapped, the outer manager's reduce takes the inner manager's own MultiCollector for its wrapper and unwraps it, so the inner manager's second child is reduced over the first child's collectors. In the finder's test the top-5 list comes back with 0 hits instead of 5, and with a top-k child next to a hit-count child the count manager's reduce throws ClassCastException (TopScoreDocCollector cannot be cast to TotalHitCountCollector).",
   "impact_class": "silent wrong results",
   "introduced_commit": "ad7746d6e31b (apache/lucene#196 'LUCENE-10000: Make MultiCollectorManager consistent with MultiCollector' by gsmiller, approved by jpountz; issue #11039 = LUCENE-10000, fix version 9.0) [read]",
   "introduced_date": "2021-07-23 (merged 2021-07-23T02:02:15Z; commit timestamp 2021-07-22; PR opened 2021-06-29)",
   "first_affected_version": "9.0.0 [exec] (tag 2021-12-06); 8.11.4 is the last unaffected release [exec]: the 8.x line never received #196, so 8.10.0-8.11.4, although released after the merge, keep the old design",
   "affected_versions": "every release from 9.0.0 to 10.5.2 (all 33: 9.0.0, 9.1.0-9.4.2, 9.5.0-9.12.3, 10.0.0-10.5.2), branch_10_6 (10.6.0-SNAPSHOT at d04ee731772; 10.6.0 [exec], MultiCollectorManager.java and MultiCollector.java unchanged through 4ae946e5a9b) and main ea57360912ed. [exec] the follow-up's version-neutral test (MultiCollectorManager(MultiCollectorManager(A, B)); B must reduce its own collectors) fails 1 of 1 on each of them with -ea, and also with -da on 9.0.0, 9.12.3, 10.5.2 and main; the finder's 3-test repro, which compiles only on 10.0.0+, fails 2 of 3 on 10.0.0, 10.5.2, branch_10_6 and main (-da too on main); the independent reproduction's JUnit fails 5 of 7 on main (-ea, -da), 10.5.2, 10.0.0 and 9.12.3, and its core-only main() fails on main and 9.0.0; the intended-behaviour check's probe fails on main (-ea, -da), 9.0.0 and 10.5.2, and its LUCENE-10244-pattern probe on main, 9.1.0 and 10.5.2. Not affected [exec]: 8.0.0, 8.8.2, 8.9.0, 8.10.0, 8.10.1 and 8.11.0-8.11.4 (follow-up; 8.11.4 also -da); 8.8.1 and 8.11.4 in other checks. [read] 6.4.0-7.7.3 have the old, unaffected design (class lists of the 6.4.0, 7.0.0 and 7.7.3 jars; not executed because the test uses ScoreMode from 8.0); 6.3.0 and earlier have no MultiCollectorManager; upstream main and branch_10x still have the same reduce. Not executed: x86.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-198.html",
   "repro": "repro/LFV-198/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-834",
   "priority": "low",
   "priority_rank": 808,
   "novelty": "new",
   "withheld": false,
   "area": "queries / payloads (PayloadScoreQuery.PayloadSpanWeight SimScorer source; SpanScorer null-SimScorer early return)",
   "title": "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)",
   "summary": "Wrap a PayloadScoreQuery in another one, for example PayloadScoreQuery(PayloadScoreQuery(SpanTermQuery(f:x), Sum, FLOAT_DECODER, false), Max, FLOAT_DECODER, false), over two documents whose token x carries the payloads 3 and 5. You expect the outer payload function to see those payloads and score the documents 3.0 and 5.0, as PayloadScoreQuery(SpanTermQuery(f:x), Max, FLOAT_DECODER, false) does, because a PayloadScoreQuery's spans are those of the query it wraps. Instead both hits score 1.0, the function's value for 'no payloads seen', and the same query built with the 3-argument constructor (includeSpanScore=true) makes IndexSearcher.search throw an AssertionError ('PayloadSpanScorer has a null docScorer!') with -ea or a NullPointerException with -da.",
   "impact_class": "silent wrong results",
   "introduced_commit": "8914ec5f75079d07233e4dbb4f93df7ac5c6f403 [read] (trunk, svn r1693921; branch_5x backport eeae87518e3e48b9ffa9d082ffad574b636bb5a7, svn r1693924, the commit that shipped in 5.3.0), 'LUCENE-6706: Add PayloadScoreQuery' (now apache/lucene#7764; author Alan Woodward, GitHub romseygeek; JIRA/SVN era, no pull request): PayloadSpanWeight called super(PayloadScoreQuery.this, searcher, null), so it has no SimScorer, and its scorer took innerWeight.getSimScorer(context); the same commit put the payload-collecting doCurrentSpans() hook after SpanScorer's older 'scores not required' early return (LUCENE-6466). Later commits only touched those lines (LUCENE-7368 5def78ba101 appended the boost argument; #13957 a3a00f3f58f dropped the context argument). The silent includeSpanScore=false form arrived with LUCENE-6844 (0b305f9279a trunk, f04f42207ed branch_5x). [exec]",
   "introduced_date": "2015-08-03 (LUCENE-6706, both commits); silent form 2015-10-19 (LUCENE-6844)",
   "first_affected_version": "5.3.0 [exec] (first release with PayloadScoreQuery; 5.3.0-5.3.2 have no includeSpanScore option, so every nested search throws NullPointerException with -ea and -da); the silent 1.0-score form from 5.4.0 [exec]. Not a regression: 5.2.1 and earlier have no PayloadScoreQuery [exec]",
   "affected_versions": "every release from 5.3.0 to 10.6.0 and main a9779ef3c193 [exec]; every release blob of PayloadScoreQuery.java from 5.3.0 to 10.5.2 keeps both defect lines [read]; upstream main 20ced71c1e6, branch_10x and branch_10_6 have the same lines [read], so the released 10.6.0 has it too. Not fixed upstream.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-834.html",
   "repro": "repro/LFV-834/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-181",
   "priority": "low",
   "priority_rank": 809,
   "novelty": "new",
   "withheld": false,
   "area": "expressions / JavascriptCompiler code generation (boolean operators on long-typed operands: bitwise and shift results, hex and octal literals)",
   "title": "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",
   "summary": "You compile a Lucene expression that tests a high bit of a long field, such as '(flags & 0x100000000) ? 10 : 1' over a NumericDocValuesField with flags = 2^32 + 1, and expect 10, because 'flags & 0x100000000' evaluates to 4294967296 and '(flags & 0x100000000) != 0' is 1. Instead you get 1: the compiler asks for the operand of !, &&, || and ?: as a 32-bit int and narrows a long-typed operand (the result of & | ^ ~ << >> >>>, or a hex/octal literal) by keeping only its low 32 bits, so every non-zero value whose low 32 bits are zero counts as false. The same number is true when written as the decimal literal 4294967296, as a variable or as '((1 << 32) + 0)', but false as '0x100000000' or '(1 << 32)'.",
   "impact_class": "silent wrong results",
   "introduced_commit": "c73f175c71ee (c73f175c71ee02d057819037105b4e55d4099567, 'LUCENE-5207: initial patch from ryan' on the lucene5207 feature branch, svn r1522767, committed by rmuir from a patch by rjernst): the first JavascriptCompiler already compiled the operands of !, &&, || and ?: with expected type INT followed by IFEQ/IFNE, converted long results to int with L2I and pushed int-position hex/octal literals as (int); it reached trunk as eecd78f37a12 (svn r1523462) and branch_4x as 08df432f8ba2 (svn r1523470), both 'LUCENE-5207: lucene expressions module'; issue LUCENE-5207 = apache/lucene#6271, no PR (SVN era) [read] [exec]; every later refactor of the code generator kept the rule (ANTLR 4, LUCENE-6417 7c9d78a2c45, 5.4.0; DoubleValues API, LUCENE-7609 8b055382d6c, 6.4.0; Java 17, GITHUB#12873 880d0ba1a8b, 10.0.0; ClassFile API, GITHUB#14597 1b5c25f3d48, main only), which is where plain git blame points [read]",
   "introduced_date": "2013-09-13 (feature-branch commit); 2013-09-15 on trunk and branch_4x",
   "first_affected_version": "4.6.0 [exec], the first release of the expressions module; 4.5.1 and earlier have no expressions module (no lucene-expressions 4.5.1 artifact on Maven Central, executed), so no release was ever unaffected",
   "affected_versions": "every lucene-expressions release on Maven Central (121 versions, 4.6.0 through 10.5.2), 10.6.0 [exec] and main ea57360912ed. [exec] the follow-up's version probe (6 expressions over flags = 2^32 + 1: 'flags & 0x100000000' = 4294967296 and '(flags & 0x100000000) != 0' = 1 are correct, the ?:, !, && and || forms are wrong) fails 4 of 6 on 4.6.0 (-ea and -da), 4.10.4, 5.5.5, 6.3.0, 6.4.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-da), and on 4.6.0-6.3.0 also shows '0x100000000 ? 1 : 0' = 0 and '(1 << 32) ? 1 : 0' = 0; the independent reproduction's 10-test JUnit fails 9 of 10 on main, 10.5.2, 9.12.3 and 8.11.4. [read] every release tag in the history clone (4.6.0-8.8.1, 9.0.0-10.5.2) requests an int operand for the four boolean operators, converts long results to int and pushes int-position literals as (int); 8.8.2-8.11.3 have no tag in the clone and are inferred from 8.8.1 [read] and 8.11.4 [exec]; branch_10x, branch_10_6 and branch_9_12 hold the same code [read]. Not a regression; not fixed upstream (JavascriptCompiler.java on upstream main is byte-identical to the tested file). Old releases were run on JDK 25 on aarch64 only (l2i and IFEQ/IFNE are fixed by the JVM specification).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-181.html",
   "repro": "repro/LFV-181/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-327",
   "priority": "low",
   "priority_rank": 810,
   "novelty": "new",
   "withheld": false,
   "area": "util / MathUtil inverse hyperbolic functions (asinh, acosh, atanh), reached through the expressions module's default functions asinh, acosh and atanh",
   "title": "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",
   "summary": "You call MathUtil.asinh(1e200), or evaluate the expression asinh(x) for a document whose x is 1e200, and expect about 461.21, because the inverse hyperbolic sine of a finite number is finite (at most about 710.5). Instead you get Infinity, because the code computes log(sqrt(x*x + 1) + x) and x*x overflows for every |x| >= 2^512; acosh does the same, asinh(1e-17) and atanh(1e-17) return 0 instead of 1e-17 because 1 + x*x (or (1+x)/(1-x)) rounds to exactly 1, and acosh(-1e8) returns -Infinity (acosh(-1e200) +Infinity) although its javadoc says that any argument below 1 gives NaN.",
   "impact_class": "silent wrong results",
   "introduced_commit": "c73f175c71ee02d057819037105b4e55d4099567 ('LUCENE-5207: initial patch from ryan', committed by rmuir, patch by rjernst, on the SVN feature branch lucene5207, r1522767), landed on trunk as eecd78f37a128dac326294ebf550eae0bbb04434 (r1523462, lineage of 6.0.0 and later) and on branch_4x as 08df432f8ba20370ed18b8933603ceba4007437b (r1523470, lineage of 4.6.0-5.5.5), MathUtil.java identical in all three; JIRA LUCENE-5207 'lucene expressions module' (migrated as apache/lucene#6271), SVN era, no pull request. It added asinh/acosh/atanh together with the expressions module and bound them as expression functions. [read]; not a regression: the values have been wrong since the API was added",
   "introduced_date": "2013-09-13 (c73f175c71ee; trunk merge and branch_4x backport 2013-09-15)",
   "first_affected_version": "4.6.0 [exec] (released 2013-11-22; 4.5.1 has no MathUtil.asinh/acosh/atanh and no expressions module, compile error [exec])",
   "affected_versions": "every release from 4.6.0 through 10.5.2 (the latest 9.x 9.12.3 and the latest 10.x before 10.6.0, 10.5.2) and main ea57360912ed; not fixed upstream (upstream main e1c4184cb983, branch_10x, branch_10_6 and branch_9_12 still have the unguarded formulas, read 2026-10-26). [exec] the version-neutral main() MathUtilHyperbolicMain fails with identical values on 4.6.0 (-ea and -da), 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main (-ea and -da); the expressions path fails on 4.6.0 (4.x Expression API) and main; the acosh negative-argument probe fails on 4.6.0, 9.12.3, 10.5.2 and main; the independent reproduction's JUnit fails 10 of 12 on main, 10.5.2 and 9.12.3 (-ea and -da). [read] blame and pickaxe show no change to the formula lines since c73f175c71ee, so the releases between the executed ones are covered by reading only; 10.6.0 (released 2026-10-29) fails too [exec]. All runs on JDK 25.0.3, aarch64 Linux, not each release's own JDK.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-327.html",
   "repro": "repro/LFV-327/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-141",
   "priority": "low",
   "priority_rank": 811,
   "novelty": "new",
   "withheld": false,
   "area": "document / range-field doc-values queries (Int/Long/Float/DoubleRangeSlowRangeQuery)",
   "title": "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",
   "summary": "You build a doc-values range query with, for example, IntRangeDocValuesField.newSlowIntersectsQuery(field, min, max), then write new values into the same min and max arrays and build a second query, as a loop that ORs several ranges through one scratch array pair does. You expect two queries that match different ranges to be different queries, as they are with the points factory IntRange.newIntersectsQuery. Instead each query matches the bounds it encoded when it was built but compares equal to (and prints) whatever the arrays hold now, so BooleanQuery de-duplicates the 'equal' clauses and a query cache can hand one query's result to the other: an OR of [0,3] and [5,6] built this way finds 0 hits on a document with range [5,10] instead of 1.",
   "impact_class": "silent wrong results",
   "introduced_commit": "f84afab0083f (master, later 9.0) and its branch_8x backport d2ff7ffafcd0 (released in 8.2.0), both 'LUCENE-8362: Introduce DocValues Fields and Range Queries for native Range Field Types', authored by atris and committed by jpountz; contributed as patches on JIRA LUCENE-8362 (migrated issue #9409), no GitHub PR. The defect came with the API: the four *RangeSlowRangeQuery constructors (this.min = min; this.max = max) and their equals/hashCode are unchanged since that commit [read]",
   "introduced_date": "2019-06-10 (commit date on master and branch_8x; author date 2019-05-27)",
   "first_affected_version": "8.2.0 [exec]",
   "affected_versions": "8.2.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.6.0 and main ea57360912ed (unreleased 11.0) [exec]; the other releases in these ranges are inferred from the four classes being present with unchanged code in every SHA-1-verified lucene-core jar from 8.2.0 to 10.5.2 [read]; not affected: 8.1.1 and earlier, where the API does not exist (the repro does not compile on 8.1.1 [exec]; the classes are absent from the 7.7.0-8.1.1 jars [read]); not fixed on main [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-141.html",
   "repro": "repro/LFV-141/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-955",
   "priority": "low",
   "priority_rank": 812,
   "novelty": "new",
   "withheld": false,
   "area": "search / kNN query execution (DocAndScoreQuery public factory, new in 11.0 via #16686; Weight#count and DocIdSetIterator contracts)",
   "title": "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)",
   "summary": "You build a query with the public DocAndScoreQuery.createDocAndScoreQuery from a TopDocs that lists some document twice, for example the concatenated, score-sorted results of two KnnFloatVectorQuery searches that both found it, and you expect what the javadoc promises, a query that 'matches exactly the documents in topK', so each document is counted and returned once. Instead every entry is kept: for 4 documents found through both fields IndexSearcher#count and totalHits are 8, each hit comes back twice and the leaf iterator returns 1 1 2 2 3 3 4 4. When the repeated document is the first document of a segment (docs [64, 64, 65] with segment 1 starting at 64), Arrays.binarySearch in findSegmentStarts can land on the later copy, so segment 0's iterator returns doc 64, which equals its maxDoc: a plain search then throws ArrayIndexOutOfBoundsException from the live docs when segment 0 has deletions, a doc-values sort throws or sorts the document by another document's value, and when segment 0 has no deletions the document is returned even if it is deleted or excluded by a MUST_NOT clause.",
   "impact_class": "silent wrong results",
   "introduced_commit": "c857eeebe7ea60d7952c77784d84dea7ed8755de (apache/lucene#16686 'Make DocAndScoreQuery public', mccullocht; main only, milestone 11.0.0): it made the class and both factory overloads public and added the 'matches exactly the documents in topK' javadoc, with no uniqueness precondition or check and no change to the factory body [exec]. The mechanism itself (copy every entry after the doc-id sort; Arrays.binarySearch at each docBase in findSegmentStarts) dates from 624560a3d70 (LUCENE-9614, msokolov, 2021-08-13, first released in 9.0.0) [read] and was harmless while only Lucene's duplicate-free internal callers could reach it.",
   "introduced_date": "2026-09-29 (author date of c857eeebe7e, 20:07:30Z; merged 20:07:31Z); latent mechanism 2021-08-13 (624560a3d70)",
   "first_affected_version": "unreleased (main / 11.0.0-SNAPSHOT only: CHANGES lists GITHUB#16686 under 11.0.0 API Changes and branch_11x f85446cb1af carries the identical file [read]; branch_10_6, branch_10x and every release up to 10.6.0 keep the class and factory package-private [exec])",
   "affected_versions": "main from c857eeebe7e (2026-09-29) to at least the upstream head 645d4fe14a20 (2026-10-28; no later commit touches DocAndScoreQuery.java) [exec]; branch_11x f85446cb1af [read]. Not affected through the public API: 9.0.0 to 10.6.0 (branch_10_6 4ae946e5a9b) and branch_10x (package-private class) [exec]. In 9.9.0 to 10.6.0 the same factory code is reachable only through a subclass that overrides the protected @lucene.experimental KnnFloatVectorQuery#mergeLeafResults to add a repeated entry [exec]; that route is judged contrived. All runs on Linux aarch64 with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-955.html",
   "repro": "repro/LFV-955/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-123",
   "priority": "low",
   "priority_rank": 813,
   "novelty": "new",
   "withheld": false,
   "area": "search / kNN query rewrite (AbstractKnnVectorQuery#mergeLeafResults extension point, optimistic re-entry pass) and DocAndScoreQuery max score",
   "title": "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",
   "summary": "You subclass KnnFloatVectorQuery and override mergeLeafResults, whose javadoc says it returns 'index-level kNN results (no constraint on their ordering)' and is 'useful for reading and / or modifying the final results', so that it returns exactly the default merge's hits in another order (same documents, same scores). You expect the same search results as the stock query. Instead rewrite() takes the k-th score from the last entry and DocAndScoreQuery the max score from the first, so with doc-id order a top-1 search for the kNN query OR a 0.5-boosted term returns doc 0 (score 0.51) instead of the exact match, doc 200000 (score 1.0), and on a 10-segment index the k = 50 query re-enters no segment and returns farther documents (first differing doc 16000 instead of 19950).",
   "impact_class": "silent wrong results",
   "introduced_commit": "2474940bffe on main (branch_9x backport b85aeb3a4fa), PR #12590 'Allow implementers of AbstractKnnVectorQuery to access final topK results' (kaivalnp; closes #12575): it added the protected @lucene.experimental mergeLeafResults with the javadoc '@return index-level kNN results (no constraint on their ordering)' and routed rewrite() through it, while createRewrittenQuery kept reading the max score from scoreDocs[0] [read]; the order-dependent reads it exposed: 8340b01c3cc (#12146 'Simplify max score for kNN vector queries', jtibshirani, max score from the first entry, correct when written because the merge could not be overridden; reached 9.x only through 16b9a8725ea, #14858, benwtrent, on branch_9_12), d279af1961f (#14226 'OptimisticKnnVectorQuery', msokolov; branch_10x backport 61424c489e6: minTopKScore from the last entry for the re-entry pass) and 4b982fffe24 (#16271, slow-J: the no-match explainer, new in 10.6.0 (released 2026-10-29); executed on main by a probe of the 2026-10-31 fact check) [read]; exec: 9.12.2 passes and 9.12.3 fails, and swapping only AbstractKnnVectorQuery.java between them flips the result in both directions; the re-entry half first fails on 10.3.0 (10.2.2 passes that test), attributed by code presence; Lucene was not built at the commits themselves",
   "introduced_date": "2023-10-05 (#12590 merged on main; commit timestamp 2023-10-06 +0530); the order-dependent reads: 2023-02-16 (#12146, first entry, on main), 2025-06-30 (#14858 merged on branch_9_12), 2025-05-05 (#14226, last entry, on main), 2026-07-09 (#16271, explainer, on main)",
   "first_affected_version": "10.0.0 [exec] on the main line and 9.12.3 [exec] on the 9.x line for the max-score half; 10.3.0 [exec] for the re-entry half (10.2.0 and 10.2.2 pass that test [exec]); 9.9.0-9.12.2 have the hook but compute the max score by scanning and are not affected [exec]",
   "affected_versions": "max-score half: 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.2.2, 10.3.0, 10.4.0, 10.5.2 and main ea57360912ed [exec], and 10.2.1, 10.3.1, 10.3.2, 10.5.0 and 10.5.1 by the code present at each tag [read]; re-entry half: 10.3.0, 10.4.0, 10.5.2 and main [exec], 10.3.1, 10.3.2, 10.5.0 and 10.5.1 [read]; the no-match explainer's last-entry read: main, branch_10_6 and branch_10x only [read]. Not affected: 9.9.0 and 9.12.2 [exec]; 9.8.0 and earlier lack the hook [exec]. 10.6.0 (released 2026-10-29) fails [exec]; branch_10_6 and the unreleased branch_10x carry the same code [read]. Not fixed upstream at main 645d4fe14a2 [exec], and no open PR changes the assumptions [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-123.html",
   "repro": "repro/LFV-123/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-460",
   "priority": "low",
   "priority_rank": 814,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter statistics (soft deletes)",
   "title": "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",
   "summary": "You configure a soft-deletes field, soft-delete a document (softUpdateDocument, or updateDocValues on that field), commit, close, and open a new IndexWriter on the index; you expect hasDeletions() to return true, because its javadoc says 'Returns true if this index has deletions', IndexWriterConfig#setSoftDeletesField says a soft-deleted document 'is treated as if it has been hard-deleted through the IndexWriter API', and the same writer's getDocStats() counts the deleted document (maxDoc 2 and numDocs 1 in the repro). Instead it returns false, with -ea and -da, until DirectoryReader.open(writer) puts the segment into the reader pool; after that the same call on the unchanged index returns true. The loop over committed segments uses SegmentCommitInfo#hasDeletions() (delGen != -1, hard deletes only), while the buffered and pooled branches of the same method count soft deletes; the one-line fix is info.getDelCount(softDeletesEnabled) > 0.",
   "impact_class": "minor",
   "introduced_commit": "ecc17f9023309ca2c46eaf65fd031e4af0ef5a25 (LUCENE-8233 'Add support for soft deletes to IndexWriter delete accounting', now GitHub issue #9280; a JIRA-era patch with no apache pull request, reviewed on the author's fork; branch_7x backport 02fa5a0b059353ae5607e91211cea24974257980), which made soft deletes count as deletes inside the writer without touching hasDeletions. Missed fix: fe83838ec3768f25964a04510cd10772cf034d34 (LUCENE-8341 'Record soft deletes in SegmentCommitInfo', #9388; branch_7x 21f03a49532d), which made the pooled branch (anyPendingDeletes() -> anyDeletions()) and numDeletedDocs(info) soft-aware but left the 'if (info.hasDeletions())' loop, which dates from 2011 (LUCENE-3084, 4fb8aa0d4e7; SegmentCommitInfo#hasDeletions from 2012, LUCENE-4055, 7262b340ba9) and was correct until soft deletes existed [read]",
   "introduced_date": "2018-04-04 (LUCENE-8233); missed fix LUCENE-8341 authored 2018-05-26, committed 2018-06-04",
   "first_affected_version": "7.4.0 [exec] (the first release with IndexWriterConfig#setSoftDeletesField); 7.3.1 is not affected [exec]. Not a regression.",
   "affected_versions": "every release from 7.4.0 through 10.6.0 and main ea57360912ed [exec] [read]; unchanged on upstream main 49483e82b357, branch_10x and branch_10_6 (the prior-report record, 2026-10-26), and the same at the 10.6.0 release commit 4ae946e5a9b [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-460.html",
   "repro": "repro/LFV-460/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-288",
   "priority": "low",
   "priority_rank": 815,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / UnifiedHighlighter builder and highlight flags (UnifiedHighlighter.evaluateFlags(Builder) never reads Builder.flags)",
   "title": "UnifiedHighlighter.Builder#withFlags is silently ignored: the highlighter always takes its flags from the four boolean builder options",
   "summary": "You build a UnifiedHighlighter with Builder#withFlags(EnumSet.of(MULTI_TERM_QUERY)), whose javadoc says the set 'will override' the four boolean builder options, and expect it to behave like the same flags chosen through those options: for a PhraseQuery 'alpha beta' on 'alpha beta. alpha gamma.' that gives '<b>alpha</b> <b>beta</b>. <b>alpha</b> gamma.'. Instead the constructor's evaluateFlags(Builder) tests the highlighter's own flags field, which is still null at that point, rather than the builder's, so the set passed to withFlags is never read: getFlags returns the defaults [PHRASES, MULTI_TERM_QUERY, PASSAGE_RELEVANCY_OVER_SPEED, WEIGHT_MATCHES] and the phrase is highlighted strictly as '<b>alpha beta</b>. alpha gamma.'. Every set is ignored the same way, including the empty set (a PrefixQuery is still highlighted), with or without assertions.",
   "impact_class": "minor",
   "introduced_commit": "b1b1a890d0890e7e35bb401cc8d851a45cc155f1 on main and its 9.x back-port a9f812c1cf90b0c35af8a82b8c76d826601684c7 (both 2021-12-19, 'LUCENE-10197: UnifiedHighlighter now has a Builder (#412)', author apanimesh061, the back-port committed by dsmiley; issue #11234 / LUCENE-10197) [read]. The defect arose inside PR #412: at revision d65ee8ab42 (2021-12-05) evaluateFlags() was a Builder method, so its 'if (Objects.nonNull(flags)) return flags;' read Builder.flags; revision a6f70412c9 (2021-12-18, 'Attempt at making UH with builder back-portable to v9.x') moved it into UnifiedHighlighter as evaluateFlags(Builder uhBuilder) without changing the guard, so 'flags' now names the highlighter's own field [read]. withFlags shipped broken with the API, so this is not a regression of behaviour that ever worked in a release",
   "introduced_date": "2021-12-19",
   "first_affected_version": "9.1.0 [exec] (first release with UnifiedHighlighter.Builder and withFlags, from 9.x commit a9f812c1cf9; 10.0.0 is the first release of the main-line commit and is affected [exec]); 9.0.0 has no Builder [exec]",
   "affected_versions": "every release with UnifiedHighlighter.Builder: the 20 releases 9.1.0 to 9.12.3, the 12 releases 10.0.0 to 10.5.2, 10.6.0 (released 2026-10-29) and main ea57360912ed [exec]; not affected: 9.0.0 and earlier, which have no Builder (9.0.0 executed); unreleased maintenance branches not checked",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-288.html",
   "repro": "repro/LFV-288/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-341",
   "priority": "low",
   "priority_rank": 816,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / kuromoji (KatakanaRomanizer in org.apache.lucene.analysis.ja.completion, the romaji helper of JapaneseCompletionFilter)",
   "title": "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)",
   "summary": "You call KatakanaRomanizer.getInstance().romanize(...) with a CharsRef that is a slice of a larger array, for example CharsRef.subSequence(2, 6) of 'ハシヤキュウ' (the slice 'ヤキュウ' at offset 2), and expect the romaji of the slice, [yakyuu], because CharsRef is documented as 'a slice (offset + length) into an existing char[]' and the same text at offset 0 gives [yakyuu]. Instead romanize reads chars[0, length), here 'ハシヤキ', and returns [hasiyaki, hashiyaki]; a slice at offset 1 of 'アトウキョウ' gives [atoukyo] instead of [toukyou], and one at offset 1 of 'xトウキョウt' gives [] instead of [toukyout]. There is no exception, with or without assertions, and Lucene's own JapaneseCompletionFilter is not affected because it always passes offset 0.",
   "impact_class": "minor",
   "introduced_commit": "4e86df96c0385a7b552434d7e2a9bee69f18bd77 (LUCENE-10102 / apache/lucene#297 'Add JapaneseCompletionFilter for Input Method-aware auto-completion', by mocobeta, co-authored by rmuir, squash-merged to main 2021-09-17), the commit that created KatakanaRomanizer [read]. Within the PR, the keystroke lookup without the offset is in the first commit dff3942eed5 (2021-09-13), and the remnant copy took its current form in ea337a2fb89 (2021-09-17), which kept the omission of an earlier loop. No commit-level A/B is possible: the parent de45b68c909 has no ja/completion package.",
   "introduced_date": "2021-09-17 (PR #297 merged; the pattern first appears on the PR branch on 2021-09-13)",
   "first_affected_version": "9.0.0 [exec] (the first release that has KatakanaRomanizer at all; on 8.10.1 and 8.11.4, the last 8.x release, the probe does not compile because package org.apache.lucene.analysis.ja.completion does not exist [exec])",
   "affected_versions": "every release from 9.0.0 through 10.5.2 (all 33: 21 on 9.x, 12 on 10.x), 10.6.0 [exec] and main ea57360912ed; not fixed on upstream main as of 2026-10-26 [exec]. Not affected: 8.x and earlier, which do not have the class.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-341.html",
   "repro": "repro/LFV-341/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-896",
   "priority": "low",
   "priority_rank": 817,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-common / util OpenStringBuilder (public char-buffer helper; in-tree users KStemmer and HTMLStripCharFilter)",
   "title": "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",
   "summary": "You append one OpenStringBuilder to another with dst.write(src) and expect dst to grow by src's contents, as it does with dst.append(src) and with every other write overload of the class. Instead the method copies dst's own length worth of chars out of src's buffer: an empty dst gets nothing (writing \"lucene\" gives \"\"), \"hello\" plus \"ab\" gives \"helloab\" followed by 3 NUL chars, a src that was reset and refilled with \"q\" leaks its earlier content (\"1234\" becomes \"1234qECR\"), and a dst longer than src's backing array throws ArrayIndexOutOfBoundsException. The cause is one token: write(OpenStringBuilder arr) calls write(arr.buf, 0, len) (OpenStringBuilder.java:140), where len is the receiver's field, not arr.len.",
   "impact_class": "silent wrong results",
   "introduced_commit": "b7277878e801 (LUCENE-152 'add KStem', migrated as apache/lucene#1230; committed by rmuir, svn trunk r1130527, Subversion era with no GitHub PR; branch_3x backport afc87ef2e535, r1130532) [read]",
   "introduced_date": "2011-06-02 (trunk 12:58:22Z, branch_3x backport 13:09:39Z; author date = commit date for both)",
   "first_affected_version": "3.3 [exec] (branch_3x, release commit 2011-06-30; 3.2.0 [exec] has no OpenStringBuilder, so there is no earlier unaffected release with the API; on the trunk line 4.0.0-alpha, 2012-06-29)",
   "affected_versions": "every release from 3.3 to 10.5.2 (138 releases), 10.6.0 (branch_10_6 4ae946e5a9b9 [exec], below) and the heads of branch_10_5, branch_10_6, branch_10x and main; not fixed upstream. [read] all 129 release tags in the full-history clone that contain OpenStringBuilder.java carry the identical line write(arr.buf, 0, len) (8.8.2-8.11.4 are not tagged there and were executed from release jars); upstream main c5ab3e57b9ba, branch_10x 1309534296e3, branch_10_6 2763db11b0a7 and branch_10_5 e85bb7b2c86d hold the same blob feca305f5b1b as a9779ef3c193 (fetched 2026-10-28). [exec] the follow-up's version-portable main() probe shows the same three deviations (empty result, an extra NUL, ArrayIndexOutOfBoundsException) with both controls passing on 20 releases from 3.3.0 to 10.5.2 (3.3.0, 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.8.2, 8.9.0, 8.10.0, 8.10.1, 8.11.0-8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2) and on main, -ea and -da on 3.3.0, 10.5.2 and main; the finder's JUnit fails 3 of 3 on main (-ea and -da), branch_10_6 4ae946e5a9b9, 10.5.2 and 9.12.3 (it does not compile on 8.11.4, which predates the tests.* test-framework package); the independent reproduction's JUnit fails 4 of 6 on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's fails 3 of 5 on main (-ea and -da), 10.5.2 and 9.12.3; the cross-model adversarial review's fails 3 of 4 on the previous main ea57360912ed (identical file), 10.5.2 and 9.12.3.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/203",
    "https://github.com/apache/lucene/issues/1230",
    "https://issues.apache.org/jira/browse/LUCENE-152",
    "https://github.com/apache/lucene/issues/206",
    "https://github.com/apache/lucene/issues/16911"
   ],
   "doc": "",
   "repro": "repro/LFV-896/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1117",
   "priority": "low",
   "priority_rank": 818,
   "novelty": "new",
   "withheld": false,
   "area": "core / util.graph (GraphTokenStreamFiniteStrings.getFiniteStrings: per-path TokenStreams over FiniteStringsIterator's reused IntsRef)",
   "title": "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)",
   "summary": "You build a GraphTokenStreamFiniteStrings over the tokens new, ny (a synonym spanning both positions) and york, whose paths are [new, york] and [ny], collect both TokenStreams from getFiniteStrings() into a list, and then read them. You expect each stream to replay its own path, as the original 6.4 API (which copied each path) did. You get [ny, york] and [ny], with no error: every stream reads the iterator's one reused IntsRef, which hasNext() overwrites with the next path, so the first stream mixes the second path's first token with its own leftover second token.",
   "impact_class": "minor",
   "introduced_commit": "5386116e9a3b54db4674b21e39a41cc4d43553f8 (branch_6x, the copy that shipped first, in 6.5.0) and main-line commit e764d3e0590e998676a18f2b11364cecced4a8ad (first released in 7.0.0), both 'LUCENE-7638: Query parsers now analyze the token graph for articulation points (or cut vertices) ...' (issue 'Optimize graph query produced by QueryBuilder', migrated as apache/lucene#8689; a JIRA patch, no GitHub PR; author Jim Ferenczi, GitHub jimczi). It replaced the static getTokenStreams(TokenStream), which built every stream from IntsRef.deepCopyOf(ids) (LUCENE-7603, Matt Weber, GitHub mattweber: 0a5300af6cf on branch_6x, released in 6.4.0, and a81ebce8049 on the main line, first released in 7.0.0), with the lazy getFiniteStrings() iterator, whose next() wraps FiniteStringsIterator's reused IntsRef without that copy; unchanged since [read]",
   "introduced_date": "2017-02-07 (author date 11:27:59 +0100 of both e764d3e0590 and 5386116e9a3; committed the same day)",
   "first_affected_version": "6.5.0 [exec], so this is a regression of LUCENE-7638",
   "affected_versions": "every release from 6.5.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT). Executed, all failing with the same wrong output: the one-test JUnit on main (-ea and -da), 10.6.0, 10.5.2 and 9.12.3 (-ea), the finder's test on 10.6.0 (-ea and -da) and 9.12.3 (-ea), and a core-only main() form with the same graph and oracle on 10.0.0, 9.0.0, 8.11.4, 7.7.3, 7.0.0, 6.6.6 and 6.5.0 (-ea); 6.4.2 passes [exec]. By code identity, the 75 release tags from 6.5.0 to 10.6.0 in the history clone have the uncopied next() (the clone has no 8.9-8.11 tags; 8.11.4 was executed) [read]. Not new in 10.6 (10.5.2 fails). Not fixed upstream: the newest commit on GraphTokenStreamFiniteStrings.java is f394c9418e1 (author date 2024-05-27), already in 5adff78bb168, and the only open PR that touches the file (#16239) changes articulationPoints only [read]. Executed on Linux aarch64 with JDK 25.0.3 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1117.html",
   "repro": "repro/LFV-1117/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1146",
   "priority": "low",
   "priority_rank": 819,
   "novelty": "new",
   "withheld": false,
   "area": "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)",
   "title": "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",
   "summary": "You reuse a LongRangeDocValuesField the way Field's javadoc suggests: you build it for the range [1, 2] and later call setBytesValue with the encoding of [10, 20], so the field now indexes [10, 20] and you expect getMin(0) to return 10 and getMax(0) to return 20. Instead they still return 1 and 2, because the class answers from the arrays it kept from its constructor and does not override setBytesValue. Int/Float/DoubleRangeDocValuesField behave the same, and LatLon/XYShapeDocValuesField likewise keep the old shape's centroid, bounding box, term count and dimension type.",
   "impact_class": "minor",
   "introduced_commit": "f84afab0083f61675498b685b8c26fca9a37c043 ('LUCENE-8362: Introduce DocValues Fields and Range Queries for native Range Field Types', Atri Sharma, committed by Adrien Grand; migrated issue #9409; reviewed as JIRA patches, no GitHub PR; branch_8x copy d2ff7ffafcd) for the four range doc-values fields, and d7fd48c9502c ('LUCENE-10654: Add new ShapeDocValuesField for LatLonShape and XYShape', #1017, Nick Knize; branch_9x copy ddf0d0acf4e, #1064) for the shape doc-values fields [read]. Not a regression: the stale getters are there from the start in both families.",
   "introduced_date": "2019-05-27 (author date of f84afab0083; committed 2019-06-10); shape doc-values fields 2022-08-09 (d7fd48c9502 and ddf0d0acf4e)",
   "first_affected_version": "8.2.0 [exec] for the range doc-values fields (the shipped repro fails there with -ea and -da; on 8.1.1 it does not compile, LongRangeDocValuesField is absent); 9.4.0 [exec] for the shape doc-values fields (on 9.3.0 the probe does not compile, LatLonShapeDocValuesField is absent)",
   "affected_versions": "Range doc-values fields: every release from 8.2.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT); not fixed upstream. [exec] the shipped one-test repro fails with 'expected:<10> but was:<1>' on 8.2.0 (-ea and -da), 8.11.4, 9.0.0, 9.12.3, 10.0.0 and 10.6.0 (-da) and on main (-ea and -da, also in the re-run); the 8.x and 9.0.0 runs use the same test with only the older LuceneTestCase import; the independent reproduction's test fails on main (-ea, -da), 10.6.0, 10.5.2 and 9.12.3. Shape doc-values fields: every release from 9.4.0 on and main; [exec] a shape probe (a point field given a 3-point line's bytes, then getHighestDimensionType) fails with 'expected:<LINE> but was:<POINT>' on 9.4.0 and 10.6.0, and the independent reproduction's shape test fails on main, 10.6.0, 10.5.2 and 9.12.3. [read] the releases in between were not run, but blame shows the lines unchanged since the introducing commits, and upstream main 1c2072f02843 (2026-11-02) has no newer commit on these files. Not new in 10.6. All runs JDK 25.0.3 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1146.html",
   "repro": "repro/LFV-1146/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-674",
   "priority": "low",
   "priority_rank": 820,
   "novelty": "new",
   "withheld": false,
   "area": "spatial-extras / spatial4j bridge to spatial3d (Geo3dDistanceCalculator.within, the default DistanceCalculator that Geo3dSpatialContextFactory installs)",
   "title": "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",
   "summary": "You create a spatial context with Geo3dSpatialContextFactory and ask its distance calculator whether the point (1, 0) is within 10 degrees of (0, 0), with ctx.getDistCalc().within(from, 1, 0, 10), and expect true: distance() returns 1.0 degree, and the spatial4j DistanceCalculator contract says within() is true when the distance is <= the limit. Instead it returns false, and within(from, 50, 0, 10) returns true although the distance is 50 degrees. The method body is 'return (distance < distance(from, toX, toY));', the exact negation of the contract, so every answer with a finite distance is inverted, including within(p, p, 0).",
   "impact_class": "minor",
   "introduced_commit": "035523ba7a86773500c053129f65c9a6dc4fd384 (main) and its branch_7x cherry-pick 85491401d54c59e1593a5c9f13dca7bfcdda31a2 (the commit that shipped in 7.1.0): LUCENE-7951 'Spatial4j implementations using Geo3d' (issue apache/lucene#9000), code from apache/lucene-solr#246 by GitHub iverase (closed unmerged 2017-09-29, committed as a patch by GitHub dsmiley) [read]. Not a regression: no release ever had a correct within() in this class. Later commits to the file (d66d9549d7c LUCENE-8086, 2cbf261032d LUCENE-9570, dfd536186fe #15889) do not touch within().",
   "introduced_date": "2017-09-20 (2017-09-21T03:09:46Z; main and branch_7x the same day); first release 7.1.0",
   "first_affected_version": "7.1.0 [exec]; 6.6.6, 7.0.0 and 7.0.1 have no such API [exec]",
   "affected_versions": "Every release from 7.1.0 to 10.6.0 and main a9779ef3c193; not fixed upstream. [exec] the one-test repro fails on the 10.6.0 jars (2026-10-31); the finder's JUnit fails 1 of 1 on all 72 releases from 7.1.0 to 10.5.2 (12 in 7.x, 27 in 8.x, 21 in 9.x, 12 in 10.x) and on main with -ea and -da; the independent reproduction's and the intended-behaviour check's own tests also fail on 10.5.2 and 9.12.3. [read] the line is unchanged on upstream main a95c754ee003 (2026-10-26), branch_10x, branch_10_6 and branch_10_5; the only open PR that touches the file (#12295) changes only the two distance() methods.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-674.html",
   "repro": "repro/LFV-674/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-740",
   "priority": "low",
   "priority_rank": 821,
   "novelty": "new",
   "withheld": false,
   "area": "spatial3d / geom distance styles (Vector.normalDistance[Squared]; DistanceStyle.NORMAL and NORMAL_SQUARED point-to-point distances in GeoCircle and GeoPath)",
   "title": "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",
   "summary": "You build a geo3d circle or path on PlanetModel.WGS84 (or call Vector.normalDistance or DistanceStyle.NORMAL.computeDistance on two GeoPoints) and ask for the NORMAL or NORMAL_SQUARED distance, which Vector's javadoc defines as 'the normal (perpendicular) distance to a vector described by a vector taken from the origin', and expect 0 for a point and itself and about 7.85e-6 planet units for a point 50 m from a circle's centre. Instead both come out as 0.00165 (about 10.5 km) at latitude 0.3 rad, because Vector.normalDistanceSquared projects onto the receiver with t = dotProduct(v) and never divides by |this|^2, which is exact only for unit vectors, while WGS84 surface points have lengths between about 0.998 and 1.0011. The same offset enters every NORMAL and NORMAL_SQUARED circle and path distance on non-spherical planet models, with no error; on SPHERE the values are exact.",
   "impact_class": "minor",
   "introduced_commit": "8c3e6b0ed3219e3cd39ad750bfa7a9a6a94b6dbe (branch_5x, svn r1683102) and 77de0ed1cf8 (trunk, svn r1683100), both 2015-06-02: LUCENE-6487 'Geo3D with WGS84 option' (now apache/lucene#7546; patch by Karl Wright, committed by David Smiley; branch work 560f3a1a010 on svn branch lucene6487, 2015-05-27; svn era, no pull request). It added PlanetModel and WGS84, so surface points stopped being unit vectors, and made GeoPoint.arcDistance divide by both magnitudes, but left Vector.normalDistance[Squared] unchanged. The unit-length formula itself dates from the sphere-only first geo3d check-in bde056c7632 (LUCENE-6196, #7258, 2015-04-13; evaluate renamed to dotProduct in c561d376bc4, 2015-05-01), where every point the library built was a unit vector; the public DistanceStyle.NORMAL / NORMAL_SQUARED came with LUCENE-6578 (#7636; 688c67f8ff2 trunk, 780e4040238 branch_5x, 2015-07-01). [read]",
   "introduced_date": "2015-06-02 (trunk and branch_5x; branch work 2015-05-27; formula 2015-04-13; public NORMAL style 2015-07-01)",
   "first_affected_version": "5.3.0 [exec] (tagged 2015-08-20; the first release with the WGS84 model and with DistanceStyle.NORMAL / NORMAL_SQUARED; it fails with -ea and -da); 5.2.0 and 5.2.1, the releases before, are sphere-only and pass [exec]. If hand-built non-unit Vector receivers count as legal input, the formula is already wrong in 5.2.0 (a raw-Vector run on 5.2.1 fails; informational)",
   "affected_versions": "every release from 5.3.0 through 10.6.0 and main a9779ef3c193 (unreleased 11.0); never fixed. [exec] The minimal test and the value probe fail on the 10.6.0 jars (2026-10-31). The follow-up's version-portable main() check (normalDistance(p, p) and DistanceStyle.NORMAL.computeDistance(p, p) on WGS84, a WGS84 circle point 50 m from the centre, SPHERE controls) fails on 5.3.0 (-ea and -da), 5.3.2, 5.4.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.9.0, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main (-ea and -da), and at the introducing commit 8c3e6b0ed32 (commit-level shadow run); the finder's JUnit fails 2 of 3 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the finder's earlier self-distance main() also fails on 9.4.2; every SPHERE control passes. [read] The method body is identical (whitespace-normalised) at every release tag from 5.2.0 to 10.5.2, on main, upstream main a95c754ee00, branch_10x, branch_10_6 and branch_10_5; releases not executed are affected by that code identity and git tag --contains. Not affected: 5.2.0 and 5.2.1 (sphere-only geo3d, executed); geo3d does not exist before 5.2.0. All runs with JDK 25 on aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-740.html",
   "repro": "repro/LFV-740/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-271",
   "priority": "low",
   "priority_rank": 822,
   "novelty": "new",
   "withheld": false,
   "area": "spatial3d / geom path distances (GeoStandardPath component tree: PathSegment, BaseSegmentEndpoint, PathNode; DistanceStyle aggregation forms)",
   "title": "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)",
   "summary": "You build a path with GeoPathFactory.makeGeoPath and a width > 0 and call computeDistance with DistanceStyle.LINEAR_SQUARED (or NORMAL_SQUARED), expecting the square of the LINEAR (or NORMAL) path distance, which is what DistanceStyle's 'convert to aggregation form, aggregate, convert back' contract gives and what end-cap points, the zero-width path and Lucene 9.4.2 return. For a point inside a path segment you get the square of that value instead: 0.00803 rather than 0.0896 for a point whose LINEAR distance is 0.299, so the value jumps about 6x across a segment's end cutoff plane and can rank a farther point ahead of a nearer one. The cause is a leftover conversion from the 2022 path refactor: PathSegment.distance already converts its result back from aggregation form, and GeoStandardPath.distance converts the component tree's result back a second time.",
   "impact_class": "minor",
   "introduced_commit": "c9c27c755a469256f64845dc7653b31b32ea6916 ('Make sure use of aggregation form is consistent throughout, and fix segment endpoint computations of nearestDistance.', DaddyWri (git author Karl David Wright), 2022-11-22; parent ae5179986c2), one commit of the hierarchical GeoStandardPath refactor series f3b4b057fa8 .. 839dfb5a2dc (2022-11-18 .. 2022-11-23), pushed directly with no pull request and tracked afterwards as apache/lucene#11965. It added fromAggregationForm around rootComponent.distance(...) in GeoStandardPath.distance and removed it from BaseSegmentEndpoint.distance, but left the one in PathSegment.distance (from 20fcd0b757c, main-side copy fc7ce768514). It reached main through the merge 49c8a759176 (2022-11-23) and 9.x through the branch_9x backport ec97f1da35c (2022-11-23, same patch: git patch-id 2f3bc8634ac1). [exec]",
   "introduced_date": "2022-11-22 (c9c27c755a4; main merge 49c8a759176 and branch_9x backport ec97f1da35c on 2022-11-23)",
   "first_affected_version": "9.5.0 [exec] (tag 2023-01-30, through the branch_9x backport ec97f1da35c; fails with -ea and -da); on the 10.x line 10.0.0 [exec]; 9.4.2 (tag 2022-11-21), the last release before the commit, passes [exec]",
   "affected_versions": "every release from 9.5.0 through 9.12.3 (14 releases) and from 10.0.0 through 10.5.2 (12 releases; 10.5.2 is the last before 10.6.0) [exec], and main from c9c27c755a4 through ea57360912ed [exec]; branch_10_6 (the branch of 10.6.0, released 2026-10-29) and the unreleased branch_10x and branch_9_12 have the same four distance() bodies [read], and 10.6.0 fails [exec]. Not affected: 9.1.0 through 9.4.2 [exec] and 9.0.0, 8.11.4 and 7.7.3 [exec]; 7.1.0 .. 7.7.2 and 8.0.0 .. 8.11.3 were not executed (the same one-conversion loop is read at 7.7.3 and 8.0.0); releases before 7.1.0 predate the aggregation forms (LUCENE-7942). Not fixed upstream. All runs on JDK 25.0.3, aarch64 Linux; plain double arithmetic, no vector code, x86 not checked.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-271.html",
   "repro": "repro/LFV-271/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-741",
   "priority": "low",
   "priority_rank": 823,
   "novelty": "new",
   "withheld": false,
   "area": "spatial3d / geom path distances (GeoDegeneratePath, the zero-width path; DistanceStyle aggregation forms)",
   "title": "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)",
   "summary": "You build a zero-width path with GeoPathFactory.makeGeoPath(planetModel, 0, points) and call computePathCenterDistance or computeOutsideDistance with DistanceStyle.LINEAR_SQUARED (or NORMAL_SQUARED), expecting the square of the LINEAR (or NORMAL) distance, which is what DistanceStyle's 'convert to aggregation form, aggregate, convert back' contract gives, what the same path with width 1e-6 returns and what Lucene 9.4.2 returned. Instead, for a point 0.01 rad beside the path, computePathCenterDistance returns about 0.01 (the unsquared distance) and computeOutsideDistance returns about 1e-8 (the fourth power) where about 1e-4 is expected. The cause is an incomplete edit in the 2022 path refactor: GeoDegeneratePath's components now return the square root (the aggregation form of the squared styles), but computePathCenterDistance never squares the minimum back, and PathSegment.outsideDistance still returns the plain square, which outsideDistance then squares a second time.",
   "impact_class": "minor",
   "introduced_commit": "839dfb5a2dc46c4b2d16d9db5ea9f31ca1e8d907 ('More refactoring work, and fix a distance calculation.', GitHub kwrightapache (git author Karl David Wright), 2022-11-24T04:36:15Z; parent 5e4623af1fd), one commit of the #11965 spatial3d refactoring series, pushed directly to main with no pull request; the same patch went to branch_9x as cherry-pick f69fb6ed99b (identical git patch-id; parent cab1802308d). It wrapped SegmentEndpoint.pathCenterDistance, SegmentEndpoint.outsideDistance and PathSegment.pathCenterDistance in toAggregationForm and GeoDegeneratePath.outsideDistance's result in fromAggregationForm, but left computePathCenterDistance's return (unchanged since 8cb64ed926d, 2017) and PathSegment.outsideDistance unconverted. [exec]",
   "introduced_date": "2022-11-24 (839dfb5a2dc at 04:36:15Z, 2022-11-23 23:36 in the author's UTC-5 time zone; the branch_9x cherry-pick f69fb6ed99b committed at 04:46:56Z)",
   "first_affected_version": "9.5.0 [exec] (tag 2023-01-30, through the branch_9x cherry-pick f69fb6ed99b; the candidate JUnit and a version-portable main() both fail); on the 10.x line 10.0.0 [exec]; 9.4.2 (tag 2022-11-21), the last release before the commit, passes [exec]",
   "affected_versions": "every release from 9.5.0 through 9.12.3 (14 releases) and from 10.0.0 through 10.5.2 (12 releases) and 10.6.0, and main through a9779ef3c193 (not fixed) [exec]; branch_10_6 (10.6.0, released 2026-10-29), the unreleased branch_10x and upstream main a95c754ee003 have the same code [read]. Not affected: 7.1.0 through 9.4.2, where the API exists and returns d^2 [exec]; releases before 7.1.0 lack the API (zero-width paths, LUCENE-7955; computePathCenterDistance, LUCENE-7962; aggregation forms, LUCENE-7942; none exists in 7.0.1). All runs on JDK 25.0.3, aarch64 Linux; plain double arithmetic, x86 not checked.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-741.html",
   "repro": "repro/LFV-741/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-802",
   "priority": "low",
   "priority_rank": 824,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter tryUpdateDocValue (tryModifyDocument doc-id validation, doc-values update buffer)",
   "title": "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",
   "summary": "You call IndexWriter#tryUpdateDocValue with an NRT reader and a doc id outside [0, reader.maxDoc()), for example 8 or 9 on an 8-document reader, 12 on a 10-document reader, or -1 on a 4-document leaf reader. You expect the call to be rejected, as the same reader rejects such an id ('docID must be >= 0 and < maxDoc', IllegalArgumentException), or at least to leave every other document alone. Instead, with assertions disabled (and for the negative leaf-reader id even with them enabled) it returns a sequence number > 0, which the javadoc says means the update succeeded, and writes the value to or soft-deletes a different live document (8 -> doc 0, 9 -> doc 1, -1 -> doc 3), or commits a doc-values entry for nonexistent doc 12 that CheckIndex accepts and that forceMerge turns into every document of the next segment carrying its predecessor's value (b0=777, b1=1000, ..., b9=1008; 1009 is lost).",
   "impact_class": "data corruption",
   "introduced_commit": "48a2138e899 (branch_7x, released in 7.4.0); the same change on master is b0b32931b28 (released from 8.0.0), identical core patch-id: LUCENE-8297 = apache/lucene#9344 (s1monw), 'Add IW#tryUpdateDocValues(Reader, int, Fields...)', which put tryUpdateDocValue on top of tryModifyDocument and created the first public path from a caller's doc id into the doc-values update buffer, with no range check [exec]. Pre-existing ingredients [read]: tryModifyDocument's assert-only check on the composite branch and the unchecked leaf-reader branch date from LUCENE-4203 (21e7728e573, 2012-08-02); the buffer's bitsRequired(maxDoc - 1) entry width from LUCENE-5248 (fc6f94f57e1, 2013); its only guard, 'assert doc < maxDoc', from LUCENE-7868 (58105a203a1, 2017), when only Lucene's own in-range ids reached that buffer",
   "introduced_date": "2018-05-07 (committer date of both LUCENE-8297 commits; author date 2018-05-05)",
   "first_affected_version": "7.4.0 [exec] (7.3.1 and earlier have no tryUpdateDocValue; 7.3.1 executed: the repro does not compile)",
   "affected_versions": "all 67 releases from 7.4.0 through 10.5.2 on Maven Central [exec], the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) and main a9779ef3c193 [exec]; the independent reproduction's test fails 7 of 7 with assertions off and 2 of 7 with assertions on (the leaf-reader id -1 cases) on 7.4.0, 7.7.3, 8.11.4, 9.12.3, 10.5.2, branch_10_6 and main, and 7 of 7 with assertions off on 10.0.0 [exec]; 102 executed history runs plus commit-level runs at LUCENE-8297. Not fixed upstream (2026-10-27): upstream main is 4 commits ahead of a9779ef3c193 and none touches IndexWriter or the doc-values update classes; the main, branch_10x and branch_10_6 heads still have only the two asserts [read]; open PR #16847 rewrites tryModifyDocument but keeps an assert-only range check. The tryDeleteDocument variant (secondary, not claimed) dates from LUCENE-4203 (4.0) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-802.html",
   "repro": "repro/LFV-802/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-098",
   "priority": "low",
   "priority_rank": 825,
   "novelty": "new",
   "withheld": false,
   "area": "index / columnar addBatch (column pass: DictionaryColumn, SORTED_NUMERIC and SORTED_SET doc-values writers)",
   "title": "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)",
   "summary": "You add a batch with IndexWriter#addBatch whose doc-values-only DictionaryColumn (SORTED or SORTED_SET) has a tuple cursor that returns a batch doc-id equal to numDocs or -1, or whose SORTED_NUMERIC or SORTED_SET column returns doc-ids in decreasing order, for example (1, v) then (0, v'). You expect an IllegalArgumentException with the writer still open and no other document touched, which is what the same addBatch call does for LongColumn, BinaryColumn, vector and stored or indexed (row-pass) columns that break the same documented contract. Instead the out-of-range value is silently attached to the document indexed just before or just after the batch (it survives commit, and CheckIndex reports a clean index), and the out-of-order tuples either throw an AssertionError that closes the writer (-ea) or are accepted (-da), after which a later valid addDocument is rejected with 'Out of order doc ids: last=1, next=0', another later document reads a value from the batch, and the next commit can fail and close the writer.",
   "impact_class": "data corruption",
   "introduced_commit": "Two commits by Tim-Brooks, both first released in 10.5.0. Part (b), order on SORTED_NUMERIC LongColumn and SORTED_SET BinaryColumn: 3d895681557 (#15990 'Add experimental columnar indexing api', main; branch_10x backport 3ec3bff01b1, #16066), which started passing caller tuple doc-ids to SortedNumericDocValuesWriter.addValue and SortedSetDocValuesWriter.addValue, whose only order check is 'assert docID >= currentDoc' from d50cf97617c (LUCENE-7474, 2016, written for the per-document path where the writer assigns the ids), and added only the range check (checkDocID) on those loops. Part (a), range, plus the SORTED_SET DictionaryColumn order case: e79c6780627 (#16101 'Add DictionaryColumn for SORTED / SORTED_SET dvs', main; branch_10x cherry-pick 8a9e55f254d), whose processDictionaryColumn never calls checkDocID and whose SortedSetDocValuesWriter.addOrdinalTuples has only the assert [read]; not a regression of any release",
   "introduced_date": "2026-05-14 (part b, #15990 merged) / 2026-05-26 (part a, #16101 merged)",
   "first_affected_version": "10.5.0 [exec]",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2 and main ea57360912ed [exec]; the heads of branch_10_5 (2026-10-04), branch_10_6 and branch_10x (2026-10-24) have the same code [read], and 10.6.0 (released 2026-10-29) fails [exec]; not applicable: 10.4.0 and every earlier release, including 9.12.3 (no org.apache.lucene.document.column package and no IndexWriter#addBatch; the repro does not compile) [exec]; not fixed upstream as of main ea57360912ed [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-098.html",
   "repro": "repro/LFV-098/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1125",
   "priority": "low",
   "priority_rank": 826,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / per-field postings format (PerFieldPostingsFormat field-to-group mapping)",
   "title": "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",
   "summary": "You give a per-field postings codec two SPI-registered postings formats with different names whose equals() compares only a setting, map field a to the second format with setting 2, field x to the first format with setting 1 and field y to the second format with setting 1, index one document and commit. You expect either the IllegalStateException 'no suffix for format name' that Lucene already throws when only x and y exist, or a segment in which every field's terms can be found. Instead the commit succeeds: y's postings are written into x's group while y's recorded format attributes point to a's group, so a TermQuery on y finds 0 documents and CheckIndex reports the index clean.",
   "impact_class": "minor",
   "introduced_commit": "8963cf411bdfb645e022a19a5a3cae5408a6024d on trunk and its branch_4x copy ad7ddcc600abe16832684bdf5c4521f37f36338a, both 'LUCENE-4090: PerFieldPostingsFormat cannot use name as suffix' (now apache/lucene#5162; an svn-era JIRA patch by Robert Muir, no pull request): the per-field group map changed from an IdentityHashMap to a HashMap keyed by PostingsFormat.equals, the SUFFIX attribute came from the matched group while the FORMAT attribute stayed format.getName(), and a group hit was guarded only by 'assert suffixes.containsKey(formatName)'. LUCENE-5969 (#7031; 98e9122375c, 2014-09-27, on the lucene5969 feature branch, merged to trunk as 35160fd56ac and to branch_5x as 33bdf278cba on 2014-10-05; first released in 5.0.0) turned that assert into the always-on IllegalStateException 'no suffix for format name' with the same condition, which has not changed since [read]. Not a regression: before LUCENE-4090 the identity-keyed code was never released",
   "introduced_date": "2012-05-30 (author dates: trunk 8963cf411bd 20:15:58Z, branch_4x ad7ddcc600a 20:26:15Z)",
   "first_affected_version": "4.0.0-ALPHA (pre-release, tag dated 2012-06-29) [exec]; first GA release 4.0.0 (2012-10-11) [exec]; 3.x has no codec API (3.6.2: compile error, package org.apache.lucene.codecs does not exist) [exec]",
   "affected_versions": "every release from 4.0.0-ALPHA through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT). [exec] The history repro fails (commit succeeds, docFreq(y:vy) = 0) on 4.0.0-ALPHA, 4.0.0, 4.10.4, 5.0.0, 6.6.6, 7.7.3, 8.8.2, 8.9.0, 8.10.0, 8.10.1, 8.11.0 to 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.6.0 and main with -ea, and also with -da on 4.0.0-ALPHA, 4.0.0, 9.12.3, 10.6.0 and main; the independent reproduction's test fails on main (-ea, -da), 10.6.0, 10.5.2 and 9.12.3 (-ea); the finder's test fails on main (-ea, -da) and 10.6.0 (-ea); the intended-lens cross-model review's own test fails on 10.6.0 (-ea). [read] All 124 release tags 4.0.0-alpha to 10.6.0 in the history clone contain the equals-keyed lookup and the name-only guard. Not new in 10.6. Not fixed upstream: the last commit on PerFieldPostingsFormat.java is b6ca26f1212 (author date 2026-06-30, unrelated), with upstream main at 1c2072f0284 (author date 2026-11-02) [check through the GitHub API, 2026-11-02]. Executed on Linux aarch64 with JDK 25.0.3 only (release jars on JDK 25, not each release's original JDK).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1125.html",
   "repro": "repro/LFV-1125/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1226",
   "priority": "low",
   "priority_rank": 827,
   "novelty": "new",
   "withheld": false,
   "area": "core / document: BinaryPoint range query factory (n-dimensional BinaryPoint.newRangeQuery, PointRangeQuery constructor checks)",
   "title": "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)",
   "summary": "You call BinaryPoint.newRangeQuery(\"f\", lower, upper) with a lower bound of two 2-byte dimensions and an upper bound of one 4-byte dimension, and expect the IllegalArgumentException its javadoc promises 'if lowerValue.length != upperValue.length'. Instead you get a query, printed as f:[binary(0 0) TO binary(1 1)],[binary(0 0) TO binary(1 1)]: the 4-byte upper bound was silently re-split into two 2-byte dimensions. newRangeQuery packs each bound on its own and passes only lowerValue.length as the dimension count, and the PointRangeQuery constructor compares only the packed byte lengths, so a dimension-count mismatch gets through whenever the byte totals agree.",
   "impact_class": "minor",
   "introduced_commit": "e1a1dbfabcc9defb22ba091be1633a31a2810ab8 'LUCENE-7117, LUCENE-7118: Remove multidimensional arrays from PointRangeQuery' by Robert Muir (issues LUCENE-7118 = #8173 and LUCENE-7117 = #8172; JIRA patch, no PR); branch_6_0 copy d8c4e6977b0 (in 6.0.0 and 6.0.1) and branch_6x copy 51b109620be (6.1.0-6.6.6), same day, byte-identical files [read]. It replaced the byte[][] PointRangeQuery constructor, which rejected differing dimension counts, with PointRangeQuery(String, byte[], byte[], int numDims) and made BinaryPoint pass pack(lowerValue).bytes, pack(upperValue).bytes, lowerValue.length. Its lower/upper comparison was first the no-op 'upperPoint.length != upperPoint.length'; 54e662b6dab (Ryan Ernst, 29 minutes later, 'LUCENE-7118: Fix packed points upper/lower bound length check') made it the packed-length check 'lowerPoint.length != upperPoint.length' of every release, which cannot see the dimension count. The @throws clause dates from 099e0311398 (LUCENE-7045, Robert Muir, 2016-02-23), written while the byte[][] constructor still enforced it, and has only been re-wrapped since",
   "introduced_date": "2016-03-20 (author and commit date 2016-03-20T16:05:17-04:00; branch_6_0 and branch_6x copies the same day; follow-up 54e662b6dab 2016-03-20T13:34:22-07:00); first release 6.0.0",
   "first_affected_version": "6.0.0 [exec] (6.0.0 is the first release with BinaryPoint at all; 5.5.5 has no BinaryPoint, so the repro does not compile there [exec]; before e1a1dbfabcc the factory existed only on unreleased master and branches, where the check held, so no release has the n-dimensional factory without the defect)",
   "affected_versions": "Every release from 6.0.0 through 10.6.0 (4ae946e5a9b), 93 releases, and main. Executed and reproduced: 6.0.0 (-ea, -da), 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.6.0 (-ea, -da) and main 5adff78bb168 (-ea, -da) with the finder's one-test repro (before 9.1.0 the same test with LuceneTestCase from its older package org.apache.lucene.util and the JUnit 4 runner), and 10.5.2 with the independent reproduction's own test [exec]; all 84 tagged releases from releases/lucene-solr/6.0.0 to releases/lucene/10.6.0 have the same newRangeQuery body and the packed-length-only constructor check [read], and javap of the untagged 8.8.2-8.11.3 jars matches the executed 8.11.4 jar [read]. Not affected: 5.5.5 and older (API absent; 5.5.5 executed: compile error). Not fixed upstream: upstream main 1c2072f0284 (author date 2026-11-02) has the same newRangeQuery body (BinaryPoint.java:192-194) and the same check (PointRangeQuery.java:84) [read]. Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1226.html",
   "repro": "repro/LFV-1226/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-428",
   "priority": "low",
   "priority_rank": 828,
   "novelty": "known",
   "withheld": false,
   "area": "facet / dynamic range facets (DynamicRangeUtil.computeDynamicRanges and computeDynamicNumericRanges, DynamicRangeInfo.centroid)",
   "title": "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",
   "summary": "You index six documents whose long doc-values field holds epoch-nanosecond timestamps one second apart (about 1.76e18 each) and ask DynamicRangeUtil.computeDynamicRanges for one range, or you pass three values of 4e18 to computeDynamicNumericRanges, and expect the range's centroid, documented as 'the average value in the range', to be about 1.7614800025e18 (or exactly 4e18). Instead you get -1.3129773431182584e18 (or -2.148914691236517e18), below the range's own min, with no error, because the method adds the range's values into a long valueSum that silently wraps once the true sum passes Long.MAX_VALUE and then divides the wrapped sum by the count. Count, weight, min and max are correct, and the weight sums in the same class are checked with Math.addExact and throw instead of wrapping.",
   "impact_class": "silent wrong results",
   "introduced_commit": "0d579338eee8ef29ef8a222e87d987ebb8cd7577 ('Add dynamic range facets', apache/lucene#13689 by stefanvodita, closes #11028 / LUCENE-9989) on main, backported to 9.x as 59ab997adb9b09ba8cbc38d1121fdb5de2847c68 [read]; not a regression: the unchecked value sum is in the first version of the class, and the three later commits on the file (955986d836d and its backport 7964682ddf5, d3130e2e9e1) do not touch it",
   "introduced_date": "2024-09-10",
   "first_affected_version": "9.12.0 [exec] (the first release with DynamicRangeUtil; CHANGES.txt lists GITHUB#13689 under Lucene 9.12.0); the first 10.x release, 10.0.0, is affected too [exec]; 9.11.1 and older do not have the API (the repro does not compile) [exec]",
   "affected_versions": "9.12.0, 9.12.1, 9.12.2, 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main ea57360912ed [exec]; the independent reproduction's independent test fails 3 of 4 on main (-ea, -da), 10.5.2 (-ea, -da), 10.0.0, 9.12.3 and 9.12.0 [exec]; git diff 10.0.0..main and 9.12.0..9.12.3 on the file are empty [read]; upstream main cf398bfb142c (2026-10-26), branch_10x, branch_10_6 and branch_9_12 still have the unchecked long valueSum [read]; not affected: 9.11.1 and older, where the class does not exist [exec]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/13914",
    "https://github.com/apache/lucene/issues/13689",
    "https://github.com/apache/lucene/issues/13760",
    "https://github.com/apache/lucene/issues/14238",
    "https://github.com/apache/lucene/issues/14258",
    "https://github.com/apache/lucene/issues/11028"
   ],
   "doc": "",
   "repro": "repro/LFV-428/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-027",
   "priority": "low",
   "priority_rank": 829,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / flexible",
   "title": "Flexible StandardQueryParser throws NumberFormatException on a fractional phrase slop",
   "summary": "You parse a phrase with a fractional slop such as \"a b\"~30.5 with the flexible StandardQueryParser. You expect it to be accepted, as 9.0.0 did by truncating the slop to 30, or rejected with a parse error. Instead, since 9.1.0, parse() throws NumberFormatException.",
   "impact_class": "wrong error",
   "introduced_commit": "f725b27e12a (LUCENE-10223, PR #429)",
   "introduced_date": "2021-11-11",
   "first_affected_version": "9.1.0",
   "affected_versions": "9.1.0+ [exec]; 9.0.0 accepts it [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-027.html",
   "repro": "repro/LFV-027/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-732",
   "priority": "low",
   "priority_rank": 830,
   "novelty": "new",
   "withheld": false,
   "area": "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)",
   "title": "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",
   "summary": "You parse (the fox)@1 ('at least one of the, fox') with the flexible StandardQueryParser and an analyzer that drops the stopword 'the', or the boosted group (fox dog)^2@1; the class javadoc documents @N for disjunction groups and boosts on grouped clauses, and parse() declares QueryNodeException for failures, so you expect a query (at least one of the remaining clauses, boosted as written). Instead parse() throws java.lang.ClassCastException ('TermQuery / BoostQuery cannot be cast to BooleanQuery') from MinShouldMatchNodeBuilder.build, which casts the group's query to BooleanQuery without a check: after the stopword is removed the one-clause group is collapsed to a TermQuery, and the grammar puts the boost inside the min-should-match node, so the group's query is a BoostQuery. Groups holding a single term, phrase, prefix or other non-Boolean query, such as (fox)@1 or (\"quick fox\")@1, fail the same way, while (fox dog)@1 works.",
   "impact_class": "wrong error",
   "introduced_commit": "f725b27e12a992f12aab12a8e8bfb9b31125bdae (LUCENE-10223 'interval support in standard syntax parser', apache/lucene#429 by dweiss, for issue apache/lucene#11259; branch_9x backport ff9ee28c60354fdb50337192883082192c8e494c). It added the @N operator, MinShouldMatchNode and MinShouldMatchNodeBuilder with the unchecked cast (the builder's only commit), and the GroupingExpr grammar rule that puts the group's boost node inside the MinShouldMatchNode; the one-clause collapse comes from the older BooleanSingleChildOptimizationQueryNodeProcessor (LUCENE-1567, 2009). Not a regression: present since the operator exists [read]",
   "introduced_date": "2021-11-11",
   "first_affected_version": "9.1.0 [exec] (first release with the @N operator; in 9.0.0, the release before, '@1' parses as a separate term and no ClassCastException occurs [exec])",
   "affected_versions": "Every release from 9.1.0 through 10.6.0 (33 releases) and main a9779ef3c193 (unreleased 11.0); never fixed. [exec] the minimal test fails on the 10.6.0 jars (2026-10-31); the follow-up's version-portable probe fails on all 32 releases (9.1.0-9.12.3, 10.0.0-10.5.2) and on main, and passes with the fix shadowed on 9.1.0 and main; the finder's JUnit fails 4 of 5 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the independent reproduction's test fails 4 of 5 on 9.1.0, 9.12.3, 10.5.2 (-ea and -da) and main (-ea and -da); the intended-behaviour check's probe fails on 9.1.0, 10.5.2 and main. 8.x and earlier have no MinShouldMatchNode classes [read]. MinShouldMatchNodeBuilder.java is byte-identical (blob bbb19618d06) from f725b27e12a through every release to main, branch_10x and branch_10_6 [read]. All runs with JDK 25 on aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-732.html",
   "repro": "repro/LFV-732/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-398",
   "priority": "low",
   "priority_rank": 831,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / flexible parser term escaping (EscapeQuerySyntaxImpl, as used by QueryNode#toQueryString)",
   "title": "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",
   "summary": "Since 9.1 the standard flexible parser reads an '@' anywhere in a term as syntax (it must be escaped, as in user\\@example.com), and && and || are its AND and OR operators, so QueryNode#toQueryString, documented to return 'a query string understood by the query parser', has to escape them. Its escaper EscapeQuerySyntaxImpl escapes '@' only when it is the first character of a term and lists AND, OR and NOT but not && or || as reserved words, so the node for 'user\\@example.com' prints 'df:user@example.com' and the nodes for '\\&&' and '\\||' print 'df:&&' and 'df:||'. Parsing any of these strings again throws INVALID_SYNTAX_CANNOT_PARSE; with a small fix to the escaper's tables every printable-ASCII term of length 1-3 round-trips.",
   "impact_class": "minor",
   "introduced_commit": "Two parts with one fix site. '@' part: f725b27e12a9 on main and its branch_9x backport ff9ee28c6035 (LUCENE-10223, GitHub #11259, PR #429 by dweiss, merged 2021-11-11): it excluded '@' from every term character in StandardSyntaxParser.jj (for the new '(...)@N' min-should-match syntax) but did not change EscapeQuerySyntaxImpl, whose first-character-only '@' rule (escapableTermExtraFirstChars) dates from 343992fcbb4b [exec]. && / || part: 343992fcbb4b31249f07354014723f18d0508d8a (LUCENE-1567 'New flexible QueryParser framework', GitHub #2641, SVN r800191; SVN era, no PR): its grammar already defined <AND: \"AND\" | \"&&\"> and <OR: \"OR\" | \"||\"> while escapableWordTokens listed only the word forms [read].",
   "introduced_date": "2009-08-03 (&& / || part, 343992fcbb4b); 2021-11-11 ('@' part, PR #429 merged)",
   "first_affected_version": "2.9.0 [exec] for the && / || part (the first release with the flexible query parser; no earlier release has EscapeQuerySyntaxImpl); 9.1.0 [exec] for the '@' part (9.0.0 [exec] is the last release without it; 10.0.0 is the first main-line release that contains f725b27e12a9)",
   "affected_versions": "&& / || part: every release from 2.9.0 to 10.6.0 and main ea57360912ed; '@' part: 9.1.0 to 9.12.3, 10.0.0 to 10.6.0 and main [exec]; no fixed release, and upstream main cf398bfb142c (2026-10-26) has the same escape tables. [exec] the finder's JUnit (4 tests) fails 3 of 4 on main (-ea and -da), 10.5.2, 10.0.0, 9.12.3 and 9.1.0 and 2 of 4 (only && and ||, inner '@' passes) on 9.0.0, 8.11.4 and 4.0.0 (the pre-9.1 runs with only the test-framework imports changed, 4.0.0 under JUnitCore); a main() probe with the same inputs fails only && and || on 2.9.0 and 3.6.2; the independent reproduction's JUnit fails 6 of 10 on main (-ea and -da), 10.5.2 and 9.12.3, and the independent reproduction's main() probe fails only && and || on 9.0.0, 8.11.2 and 4.0.0. [read] source sweep of every release tag in the history clone; the 8.9.0 to 8.11.3 tags are missing there and are inferred from 8.8.1 (source) and 8.11.4 (executed). Not executed: x86 and each release's own JDK (all runs JDK 25.0.3 aarch64; the code path is pure string handling).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-398.html",
   "repro": "repro/LFV-398/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-906",
   "priority": "low",
   "priority_rank": 832,
   "novelty": "known",
   "withheld": false,
   "area": "expressions / JavascriptCompiler code generation (compileExpression exception translation for class-file size limits)",
   "title": "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",
   "summary": "You compile a well-formed expression that is too big for one JVM method but nested far below the 1024 limit, for example a balanced sum of 10,000 terms or a depth-12 decision tree, with JavascriptCompiler.compile; the javadoc says it throws ParseException 'on failure to compile' and, since 10.6.0 (#16423), IllegalStateException 'if the resulting expression class fails to link (e.g., complexity)', and the author of #16423 said in its review that bytecode-limit refusals now become IllegalStateException. Instead the bytecode generator's own size-limit exception escapes untranslated, because it is thrown before the class is defined and outside every translating catch: org.objectweb.asm.MethodTooLargeException on the 10.6.0 release line and 8.5.0 to 10.5.2 (plus ArrayIndexOutOfBoundsException 'Index -32768 out of bounds for length 40960' from ASM's frame computation when a 127-argument custom function is nested 130 or more deep), ASM's plain RuntimeException 'Method code too large!' on 4.6.0 to 8.4.1, and java.lang.IllegalArgumentException 'Code length N is outside the allowed range' from the JDK class-file API on main. Every expression that does compile evaluates correctly; only the exception type is wrong, and the main-only IllegalArgumentException leg is debatable (a JDK-documented type that maintainers may prefer to document rather than wrap).",
   "impact_class": "wrong error",
   "introduced_commit": "eecd78f37a128dac326294ebf550eae0bbb04434 (trunk merge of the LUCENE-5207 development branch, Subversion r1523462; release line branch_4x 08df432f8ba20370ed18b8933603ceba4007437b, r1523470), LUCENE-5207 'lucene expressions module' (migrated as apache/lucene#6271; pre-GitHub, no pull request), committed by Robert Muir, CHANGES 4.6.0 credits Jack Conradson, Ryan Ernst and Uwe Schindler; the defective shape (generation, ClassWriter.toByteArray() and class definition inside a try that translates only reflective exceptions) is already in the development branch's first commit c73f175c71ee02d057819037105b4e55d4099567 [read]. Original design, not a regression: later changes to the handler (LUCENE-7800 5a50887a4b9, #12873 880d0ba1a8b, #14597 1b5c25f3d48, #16423 b6c2c31e225) all kept the size-limit failure outside every translating catch; the escaping type changed only with the bytecode library (ASM 7.2 via SOLR-14054 a58269f6a60 for 8.5.0, the JDK class-file API via #14597 on main)",
   "introduced_date": "2013-09-15",
   "first_affected_version": "4.6.0 [exec] (the first lucene-expressions release; the module and API do not exist before it: no artifact for 4.5.1 or earlier, repro.sh setup error)",
   "affected_versions": "every lucene-expressions release from 4.6.0 through 10.5.2 (all 121 in the Maven metadata), the 10.6.0 release line (branch_10_6 head 4ae946e5a9b, released as 10.6.0 on 2026-10-29) and main a9779ef3c193; not fixed upstream (last lucene/expressions commits c597effa437 on main, 2026-08-24, and f6fce7e42c5 on branch_10_6, 2026-09-05; branch_10_6 head still 4ae946e5a9b, checked 2026-10-28) [exec]. Not a 10.6.0 regression: 10.5.2 and the branch_10_6 head fail identically; 10.6.0 is only the first release whose javadoc names the complexity case. Caveat: the documented-contract mismatch is sharpest from 10.6.0 on; before it the javadoc listed only ParseException 'on failure to compile'. All runs used JDK 25 on Linux aarch64; the branch_10_6 runs use snapshot jars built from 4ae946e5a9b with the locked ASM 9.6 appended",
   "security": "none",
   "upstream_links": [
    "https://lists.apache.org/thread/vj8m2dng9p85h1l3hzly0425pnf0k21b",
    "https://github.com/apache/lucene/issues/16423",
    "https://github.com/apache/lucene/issues/8022",
    "https://issues.apache.org/jira/browse/LUCENE-6965",
    "https://github.com/apache/lucene/issues/14597",
    "https://github.com/apache/lucene/issues/16919"
   ],
   "doc": "",
   "repro": "repro/LFV-906/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-197",
   "priority": "low",
   "priority_rank": 833,
   "novelty": "new",
   "withheld": false,
   "area": "expressions / JavascriptCompiler literal parsing (hex and octal literals in visitNumeric)",
   "title": "JavascriptCompiler.compile throws NumberFormatException instead of the documented ParseException for a hex or octal literal above Long.MAX_VALUE, such as 0x8000000000000000",
   "summary": "You compile an expression such as '0x8000000000000000', '01000000000000000000000' or '1 + 0xffffffffffffffff' with JavascriptCompiler.compile, and you expect it either to compile (JavaScript reads 0x8000000000000000 as 2^63) or to fail with ParseException, because every compile overload documents '@throws ParseException on failure to compile' and the grammar accepts hex and octal literals of any length. Instead compile throws java.lang.NumberFormatException ('For input string: \"8000000000000000\" under radix 16'): visitNumeric parses hex and octal tokens with signed Long.parseLong, and compileExpression rethrows every RuntimeException that does not wrap a ParseException. The largest in-range literals, 0x7fffffffffffffff and 0777777777777777777777, compile and evaluate correctly, so the boundary is exactly Long.MAX_VALUE.",
   "impact_class": "wrong error",
   "introduced_commit": "c73f175c71ee02d057819037105b4e55d4099567 ('LUCENE-5207: initial patch from ryan', committed by rmuir on the lucene5207 feature branch, svn r1522767), which first wrote Long.parseLong(text.substring(2), 16) for HEX and Long.parseLong(text.substring(1), 8) for OCTAL with no NumberFormatException handling; it reached trunk through merge eecd78f37a128dac326294ebf550eae0bbb04434 and branch_4x through 08df432f8ba20370ed18b8933603ceba4007437b (both 2013-09-15, 'LUCENE-5207: lucene expressions module'); no GitHub PR (svn era), JIRA LUCENE-5207 [read]",
   "introduced_date": "2013-09-13 (feature-branch commit; merged to trunk and branch_4x on 2013-09-15)",
   "first_affected_version": "4.6.0 (the first release with the expressions module, tag dated 2013-11-22) [exec]; 4.5.1 and earlier have no expressions module (Maven Central has no lucene-expressions-4.5.1.jar), so the bug is as old as the API and is not a regression",
   "affected_versions": "every release that ships lucene-expressions, 4.6.0 through 10.6.0, and main ea57360912ed (11.0.0-SNAPSHOT); the follow-up's sweep fails on all 122 lucene-expressions releases from 4.6.0 to 10.6.0 with -ea and -da [exec]. [exec] 14 versions in the history step (a version-agnostic main() with in-range controls, release jars SHA-1-checked against Maven Central, seed DEADBEEF): 4.6.0, 4.10.4, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main, all affected, with identical -ea and -da results on 4.6.0, 9.12.3, 10.5.2 and main; 8.11.4 by the finder and the history step only. 4.x-6.x ran on JDK 25, newer than the JDKs they support; their in-range controls passed. [read] all 112 release tags from 4.6.0 to 10.5.2 in the history clone have the two unguarded Long.parseLong calls and no NumberFormatException handling (8.8.2, 8.9.0, 8.10.x and 8.11.x are not tags there); branch_10_6 (2763db11b0a, the 10.6.0 release branch) and the unreleased branch_10x (1309534296e) have them too (upstream JavascriptCompiler.java:459/461), not executed.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-197.html",
   "repro": "repro/LFV-197/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-182",
   "priority": "low",
   "priority_rank": 834,
   "novelty": "new",
   "withheld": false,
   "area": "expressions / JavascriptCompiler nesting-depth guard (compile(String, Map, int maxNestingDepth), new in #16423, released in 10.6.0)",
   "title": "JavascriptCompiler.compile(source, functions, Integer.MAX_VALUE) rejects every expression, even '1', because maxNestingDepth + 1 overflows to Integer.MIN_VALUE",
   "summary": "You compile an expression with the new overload JavascriptCompiler.compile(source, functions, maxNestingDepth) and pass Integer.MAX_VALUE to ask for no practical nesting limit, and you expect it to accept at least everything that Integer.MAX_VALUE - 1 accepts, because the parameter is documented only as 'the maximum depth of nesting', with no bound. Instead every expression, even '1', fails with ParseException 'Nesting level too deep (>-2147483648)': the parse-time depth listener is created with maxNestingDepth + 1 to account for the root node, that int addition wraps to Integer.MIN_VALUE, and the depth check fails on the first parser rule. Integer.MAX_VALUE - 1 and the default limit of 1024 work, and the overload first shipped in 10.6.0 (released 2026-10-29).",
   "impact_class": "wrong error",
   "introduced_commit": "b6c2c31e22518503a8da0cd26b196217b30f4186 (main) and its branch_10x backport 1dc74b98be6d4a1b8b09c89ecd23fb404f759011 (branch_10_6 forks from branch_10x after it and contains it), PR #16423 'Add (configurable) guards for complexity of expressions' (author and merger uschindler; milestone 10.6.0; CHANGES entry under 10.6.0 Improvements), which added the compile(String, Map, int) overload, DEFAULT_MAX_NESTING_DEPTH, JavascriptNestingDepthListener and the 'maxNestingDepth + 1' line in one change [read]",
   "introduced_date": "2026-07-27 (PR #16423 merged 17:14:20Z; the branch_10x backport was committed the same day)",
   "first_affected_version": "10.6.0 (released 2026-10-29), the first affected release (main, branch_10_6 and branch_10x since 2026-07-27); every release through 10.5.2 lacks the overload [exec]",
   "affected_versions": "main ea57360912ed (11.0.0-SNAPSHOT) [exec]; the branch_10x backport 1dc74b98be6 and branch_10_6 head 2763db11b0a [exec] [read]. Not affected, because the overload does not exist [exec]: 9.12.3, 10.5.0, 10.5.1, 10.5.2, and main just before the commit (parent 96ff912d99d, hybrid). 10.6.0 (released 2026-10-29) is the first release that contains it. By code reading, the package-private compile(String, Map, int, boolean picky) takes the same path, and the default overloads (limit 1024, listener limit 1025) cannot overflow.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-182.html",
   "repro": "repro/LFV-182/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b): 1 of 1 fails, and 3 of 5 for a second test with -ea and -da; 10.5.2 does not have the compile(String, Map, int) overload."
  },
  {
   "id": "LFV-866",
   "priority": "low",
   "priority_rank": 835,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / synonym.word2vec (Word2VecSynonymProvider.getSynonyms search size; Word2VecSynonymFilterFactory validation)",
   "title": "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",
   "summary": "You configure Word2VecSynonymFilterFactory with maxSynonymsPerTerm=2147483647 (Integer.MAX_VALUE), which its validation accepts ('must be a positive integer greater than 0'), to keep every synonym above minAcceptedSimilarity, and you expect those synonyms or a rejection at configuration time. The analyzer builds, but Word2VecSynonymProvider.getSynonyms passes maxSynonymsPerTerm + 1 (int arithmetic) as topK to HnswGraphSearcher.search, which wraps to Integer.MIN_VALUE, so the first token with a model vector throws IllegalArgumentException 'initialCapacity must be > 0 and < 2147483630; got: -2147483648' from TernaryLongHeap (on 9.7.0 to 10.3.2: 'maxSize must be > 0 ...' from LongHeap). Because the search size is never clamped to the model size and the search allocates its queues of topK entries up front, values close to Integer.MAX_VALUE fail the same way and values from roughly heap-bytes/16 up (1e8 at a 1 GiB heap) throw OutOfMemoryError, even for a 3-term model.",
   "impact_class": "crash",
   "introduced_commit": "1f4f2bf50957ad1a13c32d5351c7de77154953f1 on main (apache/lucene#12169 'Introduced the Word2VecSynonymFilter', feature issue #12168; author dantuzi, co-author Alessandro Benedetti; first in 10.0.0) and its branch_9x re-backport 64b48b89b501 (committed 2023-05-30, author date 2023-04-24; first in 9.7.0; an earlier backport 53709ccaecc was reverted by 7e15a390688 on 2023-04-25) [read]",
   "introduced_date": "2023-04-24 (main 1f4f2bf5095); 2023-05-30 (branch_9x re-backport 64b48b89b50, author date 2023-04-24)",
   "first_affected_version": "9.7.0 [exec] (the first release with the API; 9.6.0 has no synonym.word2vec package, the repro does not compile there [exec]); first on the main line: 10.0.0 [exec]",
   "affected_versions": "Every release that has the API: 9.7.0 to 9.12.3 and 10.0.0 to 10.5.2, 24 releases [exec], the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) [exec] and main a9779ef3c193 [exec]. Still present, unchanged, on upstream main c5ab3e57b9b (2026-10-28), branch_10x 1309534296e and branch_10_6 2763db11b0a [read]. The exception text follows the core heap class (LongHeap 'maxSize must be > 0 ...' on 9.7.0 to 10.3.2, TernaryLongHeap 'initialCapacity must be > 0 ...' from 10.4.0) [exec]. The OutOfMemoryError range was measured on main only; on older releases it is inferred from the same eager queue allocation in HnswGraphSearcher.search [read]. All runs on aarch64 Linux with JDK 25. Not affected: 9.6.0 and earlier (API absent).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-866.html",
   "repro": "repro/LFV-866/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-262",
   "priority": "low",
   "priority_rank": 836,
   "novelty": "new",
   "withheld": false,
   "area": "core / search: TopDocs.merge paging window (mergeAux; score, Sort and tie-breaker overloads)",
   "title": "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')",
   "summary": "You merge two shards' results (5 hits in total) with TopDocs.merge(1, Integer.MAX_VALUE, shards) to get every hit after the first, and expect the 4 remaining hits in score order, the same as TopDocs.merge(1, 4, shards) returns. Instead you get an array of length 4 in which every entry is null, and no exception: merge adds start + topN in int, the sum wraps to a negative number, and the loop that copies hits never runs. The Sort and tie-breaker overloads behave the same way; start + topN = 2^31 - 1 still works and 2^31 fails.",
   "impact_class": "minor",
   "introduced_commit": "1fd9722f4956bf557bc7d9e7ca4734559b80d035 (LUCENE-5515 'Improve TopDocs#merge for pagination', by Martijn van Groningen (@martijnvg), reviewed by Mike McCandless (@mikemccand), SVN r1578262 on trunk with no pull request; issue now apache/lucene#6578; branch_4x backport 2e4dd1f1e76, r1578267, the same day, which 4.8.0 to 5.5.5 contain) [read]. The commit added the start parameter and the int sum start + size together, so the defect is as old as the paging API; not a regression. Later changes kept the two lines unchanged (LUCENE-6220 e4436aa7fec, LUCENE-6878 724e803e195, LUCENE-7707 2e56c0e5056, and LUCENE-8857 f686167e710, 2019, which added the custom tie-breaker overloads)",
   "introduced_date": "2014-03-17",
   "first_affected_version": "4.8.0 [exec] (released 2014-04-27; the first release with a start parameter on TopDocs.merge; the 4.8-era repro fails with -ea and -da and the portable probe fails); 4.0.0 to 4.7.2 have no merge overload with a start parameter and are not affected [exec]",
   "affected_versions": "every release from 4.8.0 through 10.5.2 (116 releases), 10.6.0 [exec] and main ea57360912ed; not fixed in any release, and the int sum is still at TopDocs.java:314 on upstream main e1c4184cb983 (read 2026-10-26) [exec]. Caveat: every run used JDK 25.0.3, not the JVM the older releases targeted (the controls pass in each run)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-262.html",
   "repro": "repro/LFV-262/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-960",
   "priority": "low",
   "priority_rank": 837,
   "novelty": "new",
   "withheld": false,
   "area": "grouping / TopGroups.merge (merging second-pass grouped results across shards or slices)",
   "title": "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",
   "summary": "You merge two shards' second-pass grouping results with TopGroups.merge(shardTopGroups, groupSort, docSort, 1, Integer.MAX_VALUE, ...) to get every document after the first in each group, and expect the same groups as with docTopN = 10 on the same small data, just as docOffset 0 with docTopN = Integer.MAX_VALUE already gives. Instead merge throws NegativeArraySizeException: -2147483648: it passes the int sum docOffset + docTopN to TopDocs.merge, the sum wraps negative, and TopDocs.mergeAux sizes its result array with it. Every pair with docOffset + docTopN >= 2^31 fails, for relevance and field order within groups; a sum of 2^31 - 1 still works.",
   "impact_class": "crash",
   "introduced_commit": "a1e74fd6c9463558e3c052f61dfd53c00328902f (trunk, svn r1136080, first released in 4.0.0) and its branch_3x backport c0713158f8c466146a09d2a4d974c656b379c209 (svn r1136465, first released in 3.3): LUCENE-3191 'Add TopDocs.merge to merge multiple TopDocs' (migrated issue #4264; svn era, no GitHub PR) added TopGroups.merge with the int sum docOffset + docTopN [read]",
   "introduced_date": "2011-06-15 (author date of a1e74fd6c94); 2011-06-16 (author date of the branch_3x backport c0713158f8c)",
   "first_affected_version": "3.3 [exec]; 3.2.0 has no TopGroups.merge [exec]",
   "affected_versions": "Every release from 3.3 to 10.5.2 [read], branch_10_6 4ae946e5a9b (10.6.0, released 2026-10-29) [exec] and main a9779ef3c193 [exec]; upstream main 645d4fe14a2 still has both sums and TopGroups.java was last changed by 897625db0f9 (2026-08-20, unrelated) [read]; not fixed",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-960.html",
   "repro": "repro/LFV-960/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-387",
   "priority": "low",
   "priority_rank": 838,
   "novelty": "known",
   "withheld": false,
   "area": "highlighter / matchhighlight PassageSelector (MatchHighlighter, FieldValueHighlighters)",
   "title": "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)",
   "summary": "You highlight a document whose stored field has two values, 'aaaa foo' and 'bbbb foo', for the query text:foo with MatchHighlighter and FieldValueHighlighters.highlighted(Integer.MAX_VALUE, 10, ...), meaning 'no limit on the passage size', and expect both values highlighted, [aaaa >foo<, bbbb >foo<], as a window of 1000 gives. Instead you get only [aaaa >foo<], with no error: PassageSelector.pickBest centres each window in long arithmetic but then shifts it into the value's range with the int statement 'to += range.from - from', which wraps negative for a range that starts after offset 0, so the match in the second value gets no passage. If only the second value matches, both values come back unhighlighted ([bbbb bar, aaaa foo] instead of [aaaa >foo<]).",
   "impact_class": "silent wrong results",
   "introduced_commit": "150a8dacb597 (LUCENE-9463 'Query match region retrieval component, passage scoring and formatting', by GitHub dweiss, apache/lucene-solr#1750, merged 2020-08-14; the issue is now apache/lucene#10503) wrote the int shift 'to += range.from - from', byte-identical to main PassageSelector.java:131 [read]. 1bb455483202 (LUCENE-10135 'Correct passage selector behavior for long matching snippets', by GitHub dweiss, apache/lucene#334, issue #11172, merged 2021-09-30) made it reachable: it moved the window centring two lines above (:128-129) to long + Math.toIntExact and added TestPassageSelector.largeWindow with maxPassageWindow = Integer.MAX_VALUE (one permitted range, at 0), but left the shift in int [exec]. Both commits precede 9.0.0, so no release has a regression; it is the residue of an incomplete overflow fix",
   "introduced_date": "2020-08-14 (150a8dacb59, line written); 2021-09-30 (1bb45548320, made reachable)",
   "first_affected_version": "9.0.0 [exec] (release tag 2021-12-06; the first release with the matchhighlight package; CHANGES lists LUCENE-9463 and LUCENE-10135 under 9.0.0); no 8.x release has the API [exec]",
   "affected_versions": "every release from 9.0.0 through 10.6.0 (the 33 releases through 10.5.2 executed, 10.6.0 by reading) and main ea57360912ed; no version has a fix [exec] [read]. 9.0.0 runs use a copy of the repro that differs only in the LuceneTestCase import. Caveat: every run used JDK 25.0.3, and the end-to-end MatchHighlighter path was executed on main and 10.5.2 only (the per-value ranges it passes date from LUCENE-9464, 2020, before 9.0.0)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/334",
    "https://issues.apache.org/jira/browse/LUCENE-10135",
    "https://github.com/apache/lucene/issues/11172",
    "https://github.com/apache/lucene/issues/10503",
    "https://issues.apache.org/jira/browse/LUCENE-9463",
    "https://github.com/apache/lucene/issues/10559"
   ],
   "doc": "",
   "repro": "repro/LFV-387/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1003",
   "priority": "low",
   "priority_rank": 839,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / analyzing: AnalyzingSuggester and FuzzySuggester lookup (FST top-N queue depth)",
   "title": "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'",
   "summary": "You build an AnalyzingSuggester (or FuzzySuggester) whose index-time analyzer expands one entry into several analyzed forms, for example a SynonymGraphFilter that also indexes 'lucene' as 'search' and 'find', and call lookup(\"luc\", false, num) with a large num; num is documented as the 'maximum number of results to return', so you expect the 8 suggestions that num = 1000 returns. Instead the search's queue depth num * maxAnalyzedPathsForOneInput is computed in int (AnalyzingSuggester.java:786) and wraps: with 3 paths and num = 1431655766 it becomes 2, the top-N search prunes paths it still needs, and lookup returns [lucas, lucifer, lucid] with no error, skipping the higher-weighted luck, lucent and lucerne (FuzzySuggester: 5 of 8), and with 4 paths and num = 2^30 it becomes 0 and lookup throws NoSuchElementException. With assertions enabled, lookup(key, false, Integer.MAX_VALUE) on a suggester with 2 or more paths typically fails 'assert completions.isComplete' (:824), although the same call without assertions returns the right list.",
   "impact_class": "silent wrong results",
   "introduced_commit": "dc49949558d776f3059896438b936d182f8dba33 (trunk, svn r1400634) and 5726a78f9d4ba5e8fb6f12b19cfa4c90bc15fdc0 (branch_4x, r1400635): LUCENE-4481 'add back some optos' (#5547; Michael McCandless; Subversion era, no pull request), which gave Util.TopNSearcher its maxQueueDepth and made AnalyzingSuggester pass num * maxAnalyzedPathsForOneInput as an int product; the line has only been reformatted since (3b67b174932, 2cbf261032d, dbaf97f5dcc). The -ea symptom comes from LUCENE-5519 (803a9907d39 trunk / 30fb5cacac2 branch_4x, 2014-03-12, Simon Willnauer, #6582, first in 4.8.0), which added TopResults.isComplete and 'assert completions.isComplete' [read]",
   "introduced_date": "2012-10-21 (the int product); 2014-03-12 (the isComplete assertion behind the -ea symptom)",
   "first_affected_version": "4.1.0 [exec] (AnalyzingSuggester and FuzzySuggester first shipped in 4.1.0 with the product in place; 4.0.0 has no such class [exec]); the -ea assertion failure from 4.8.0 [exec]",
   "affected_versions": "Every release from 4.1.0 to 10.5.2 (129 releases), 10.6.0 (released 2026-10-29; run as its RC) and main [exec]; the int product is in all 120 local release tags from 4.1.0 on (8.8.2-8.11.3 are not tagged locally and are inferred; 8.11.4 was executed) [read]. Without assertions every executed release gives the same outcomes (3 of 8 at num 1431655766 with 3 paths, 5 of 8 on FuzzySuggester, NoSuchElementException at 2^30 with 4 paths, the right 8 at Integer.MAX_VALUE with 2 paths); with -ea, 4.1.0-4.7.2 still return the short list silently (no isComplete assertion yet) and 4.8.0 on fail the assertion [exec]. Not fixed: upstream main 645d4fe14a20 (2026-10-29) still has line 786, and the newest commits on AnalyzingSuggester.java (54283150a81, 2026-06-14), FuzzySuggester.java (8ac26737913, 2021-08-25) and Util.java (378ca8d1bbf, 2026-01-15) do not touch it; no open PR changes it [read]. Caveat: all runs used JDK 25.0.3 on Linux aarch64; the 6.0+ port uses NIOFSDirectory because 6.0.0's MMapDirectory initializer fails on JDK 25, which is unrelated",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1003.html",
   "repro": "repro/LFV-1003/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-061",
   "priority": "low",
   "priority_rank": 840,
   "novelty": "new",
   "withheld": false,
   "area": "search / HNSW",
   "title": "Concurrent HNSW build retries a lost entry-node promotion with the wrong query vector",
   "summary": "You build or merge HNSW graphs with more than one merge worker. You expect each node's neighbours to be scored against that node's vector. Instead, when an entry-node promotion is lost to another worker and retried, the shared scorer is not reset, so wrong scores are stored and the persisted topology changes.",
   "impact_class": "silent wrong results",
   "introduced_commit": "#14181 (48884e76e08)",
   "introduced_date": "2025-02-06",
   "first_affected_version": "10.2.0 [exec]",
   "affected_versions": "10.2.0 to 10.6.0 (11 releases) and main [exec]; 9.12.3, 10.0.0 and 10.1.0 pass [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-061.html",
   "repro": "repro/LFV-061/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-004",
   "priority": "low",
   "priority_rank": 841,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / merge instances",
   "title": "Merge instances re-open segment files by name, so merging an old reader after a name reuse can copy another segment's data",
   "summary": "You keep an old NRT reader open, roll back writers until a later writer reuses its segment name, and then merge that reader, for example with addIndexes(CodecReader...). You expect the merge to copy the old reader's own stored fields and vectors. Instead its merge instance opens the file again by name and copies the newer segment's data, silently (CheckIndex on the target is clean) or, for compound files of another layout, with a loud exception.",
   "impact_class": "data corruption",
   "introduced_commit": "#16684 (fe67d20e9e, stored fields), #16749 (c95aa21a7b, vectors), #16796 (f94888d85c, compound files); #16622 (cbad01e83e) extends it to the quantized HNSW format; narrowed by #16883 (ea57360912)",
   "introduced_date": "2026-10-01 (#16684, #16749 merged); 2026-10-11 (#16796 merged)",
   "first_affected_version": "10.6.0 (released 2026-10-29); also unreleased main and branch_10x",
   "affected_versions": "before #16883: main b83101cdd2, branch_10_6 d04ee73177 and branch_10x in the default config [exec]; at main ea57360912, a9779ef3c193 and 645d4fe14a2 / branch_10_6 2763db11b0 / branch_10x 1309534296 and 657014b3c579: only with ADVISE_BY_CONTEXT-style advice and >= 4 KiB files [exec]; 10.5.2 and the releases tested back to 8.11.4 copy correctly [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-004.html",
   "repro": "repro/LFV-004/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b): 4 of 7 fail; 10.5.2 passes 7 of 7."
  },
  {
   "id": "LFV-331",
   "priority": "low",
   "priority_rank": 842,
   "novelty": "new",
   "withheld": false,
   "area": "store / FSDirectory pending deletes (delete retry vs. the createOutput/rename revive, thread safety)",
   "title": "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",
   "summary": "On a file system that refuses to delete open files (Windows, or a virus scanner), you delete a file that a reader still holds open, so FSDirectory keeps it as a pending delete; after the reader closes, one thread re-creates that name with createOutput (or renames another file onto it), writes and closes it, while another thread makes any mutating call on the same directory, for example sync() of an unrelated file. You expect the new file to stay, like any file that was created, closed and never deleted. Instead the other thread's pending-delete retry, which copied the pending set before the revive, deletes the new file: listAll() no longer lists it and openInput() fails (on main under the test framework's WindowsFS: 'x was created and closed successfully but is gone: [other]').",
   "impact_class": "data corruption",
   "introduced_commit": "8e784699f009b80301306f7fc55225d64b95416b, the merge of branch lucene-6835 into master (mikemccand), LUCENE-6835 'Directory.deleteFile should \"own\" retrying deletions on Windows' = GitHub #7893; pre-PR era, no pull request [read]. It brought the pending-delete set, the synchronized deletePendingFiles() that retries over a copy (new HashSet<>(pendingDeletes)), the retry from every mutating call and the revive in createOutput/renameFile without that monitor; line origins in the branch: 8cd731be50a, 85c546b742b, 24f55abfd50, plus f8bd22e58c9 on master. The createOutput path was masked in 6.2.0-7.3.1 by LUCENE-6171 (CREATE_NEW; 45d2d2e7d34 / a893c645952) and re-opened in 7.4.0 by LUCENE-8275 (#9322; 9f4e6c5da8d / aa341476fdb), which made the revive delete the old file before creating the new one; LUCENE-8318 (#9365; b178321bd1b / 3fe612bed20, 7.4.0) fixed only the single-threaded re-add and left the race unchanged",
   "introduced_date": "2016-02-06 (merge 8e784699f00; branch commits 2016-02-03 to 2016-02-07)",
   "first_affected_version": "6.0.0 [exec] (createOutput and rename paths; 5.5.5 and earlier have no pending-delete mechanism [exec])",
   "affected_versions": "6.0.0 to 10.6.0 and main ea57360912ed. [exec] the follow-up history probe loses the re-created file on both the createOutput and the rename path on 6.0.0 (-ea and -da), 6.1.0, 7.4.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da), and on the rename path only on 6.2.0, 6.6.6 and 7.3.1 (there the createOutput re-create throws FileAlreadyExistsException instead, LUCENE-6171); the finder's JUnit fails on main (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails on main, 10.5.2, 9.12.3 and 8.11.4; [read] the releases in between, by a code-shape scan of FSDirectory.java at every release tag 5.5.0-10.5.2 (four semantic shapes plus a formatting-only change at 9.0.0; the clone has no 8.8.2-8.11.x tags). Not affected: 5.5.5 and earlier [exec]. 10.6.0 (released 2026-10-29) fails too [exec]. Not run: the release branches. All runs use the test framework's WindowsFS emulation on Linux; nothing was run on real Windows. Not fixed: FSDirectory.java on upstream main cb19aecba8f last changed 2026-06-02 (#16119, unrelated) and no open PR touches it [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-331.html",
   "repro": "repro/LFV-331/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-343",
   "priority": "low",
   "priority_rank": 843,
   "novelty": "known",
   "withheld": false,
   "area": "store / NativeFSLockFactory (write.lock: in-JVM LOCK_HELD guard and cross-process mutual exclusion)",
   "title": "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",
   "summary": "In one JVM you hold an index's write.lock (an open IndexWriter on directory A) and then, in the same JVM, open the same lock file through another real path: a bind mount of A at a second path, or a hard-link copy of A's files that includes write.lock, opened with IndexWriter, CheckIndex or addIndexes(Directory...). You expect that second open to fail with LockObtainFailedException while the first writer keeps its lock, so that a writer in another process on A is refused, as the IndexWriter javadoc promises. Instead the second open gets past NativeFSLockFactory's in-JVM check (LOCK_HELD compares toRealPath() strings, which differ), opens a second FileChannel, gets OverlappingFileLockException and closes that channel, which on Linux drops the process's lock on the file; the first lock still passes ensureValid(), a writer in another process then opens A and commits, and the first writer's next delete-only commit replaces that commit (on main: 'expected:<REFUSED> but was:<OBTAINED>' and 'the other process's acknowledged commit (doc 'child') was replaced by this writer's commit').",
   "impact_class": "data corruption",
   "introduced_commit": "936b7ba82ac7d6a3c2bf87ab68d6dc6d1d657c56 (svn r465882, LUCENE-678 follow-up 'fix sharing of native locks by diff dirs' = GitHub #1753, fix version 2.1; pre-PR era, no pull request): added the static LOCK_HELD set keyed by File.getCanonicalPath() strings [read]. The class itself came three days earlier in 70472ad2cdf2 (r464611), whose in-JVM guard (a static factory map keyed by the canonical lock directory) was path-keyed too; neither commit was released on its own. Not a regression: the path key was never replaced by a file identity. The current lines come from LUCENE-5738 87c8a344a57e / 2887b927a33d (LOCK_HELD re-added after LUCENE-5612 c173dab982b5 had removed it in 4.8.0; first release 4.9.0), LUCENE-5945 3eb66fb19ca2 (getCanonicalPath -> toRealPath, 5.0.0), LUCENE-6507 225e4a580391 / 3a2f2e937b43 (LOCK_HELD.add(realPath.toString()), 5.2.0), LUCENE-6508 fe6c3dc9397b / dcd53bc7336 (obtainFSLock/ensureValid structure, 5.3.0), LUCENE-7959 0283d3e28a6d (8.0.0) and #16278 955ed9e853be / #16303 107884a30e10 (main only, tryLock refactor that still closes the channel on any failure)",
   "introduced_date": "2006-10-19 (936b7ba82ac7; the class was added 2006-10-16 in 70472ad2cdf2)",
   "first_affected_version": "2.1.0 [exec] (2.0.0 has no NativeFSLockFactory [exec]); opt-in in 2.1.0-2.4.1 (FSDirectory defaulted to SimpleFSLockFactory), the default for FSDirectory.open since 2.9.0 (LUCENE-1877, read from CHANGES)",
   "affected_versions": "every release that has NativeFSLockFactory, 2.1.0 to 10.5.2, and main ea57360912ed. [exec] the follow-up's Lock-level main() probe (setup gate: another process REFUSED while the lock is held; same-path control; hard-link alias) fails on 2.1.0, 2.4.1, 2.9.0, 3.0.3, 3.6.2, 4.0.0, 4.7.2, 4.8.0, 4.8.1, 4.9.0, 4.10.4, 5.0.0, 5.2.1, 5.3.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main; the finder's IndexWriter-level JUnit (needs the 9.1+ test framework) fails 3 of 4 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the independent reproduction's JUnit fails 3 of 6 on main (-ea and -da), 10.5.2 and 9.12.3, and the independent reproduction's probe fails on 8.11.4. By era: in 2.1.0-4.7.2 and 5.3.0+ the alias obtain throws the unchecked OverlappingFileLockException; in 4.9.0-5.2.1 it is caught and the alias obtain simply returns false, so nothing at all signals the loss; 4.8.0 and 4.8.1 lose the lock even on the same path (the known, fixed LUCENE-5738). [read] untested releases in between: no commit between the tested points changed the path key or the close-on-failure. Before 9.1 only the Lock-level mechanism was executed; IndexWriter takes write.lock through the same API [read]. All runs on JDK 25.0.3, Linux 5.10 aarch64 (the 2.x-4.x releases originally ran on far older JDKs, whose lock-overlap tracking differed; the symptom on those JDKs was not tested). Not run: macOS (also POSIX locks, likely affected), Windows (expected unaffected), 10.6.0 and the release branches. Not fixed upstream: NativeFSLockFactory.java last changed in #16303 (2026-07-01), and no open PR changes the key.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16303",
    "https://github.com/apache/lucene/issues/13142",
    "https://github.com/apache/lucene/issues/6800",
    "https://issues.apache.org/jira/browse/LUCENE-5738",
    "https://github.com/apache/lucene/issues/7828",
    "https://issues.apache.org/jira/browse/LUCENE-6770"
   ],
   "doc": "",
   "repro": "repro/LFV-343/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-912",
   "priority": "low",
   "priority_rank": 844,
   "novelty": "known",
   "withheld": false,
   "area": "misc / store: HardlinkCopyDirectoryWrapper#copyFrom hard-link path (against the core/store Directory#copyFrom and FilterDirectory#copyFrom contracts; reached through core/index IndexWriter.addIndexes(Directory...))",
   "title": "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",
   "summary": "You wrap an FSDirectory in TrackingDirectoryWrapper (or LockValidatingDirectoryWrapper, or your own FilterDirectory), wrap that in HardlinkCopyDirectoryWrapper, and copy a file in with copyFrom or IndexWriter.addIndexes(Directory...). You expect the copy to pass through the wrapped directory, as createOutput through the same wrapper does: on main Directory#copyFrom says 'Any per-file bookkeeping performed by createOutput must also cover copied files', and FilterDirectory#copyFrom names this class as one that delegates to in.copyFrom. Instead copyFrom unwraps both chains to the innermost FSDirectory and hard-links there, so no layer in between runs: getCreatedFiles() stays [], the copy succeeds after the inner write lock was released, and a byte-transforming layer on one side reads back the raw bytes (through addIndexes, a committed index that cannot be opened), with no error at copy time.",
   "impact_class": "silent wrong results",
   "introduced_commit": "268da5be45e5eed570575eea6a9e85a4cdb658e7 (master) and its branch_6x backport a6839beb87a73bff6139df44a7b9168a498dd426 (identical file), LUCENE-7300 (#8354 'Add directory wrapper that optionally uses hardlinks in copyFrom'; JIRA patch, no GitHub PR; author s1monw), which added the class with FilterDirectory.unwrap(from) / FilterDirectory.unwrap(this) and Files.createLink between the innermost FSDirectories [read] [exec]. The written contract it breaks came later: #16530 (7fbd268187f, author tballison, 2026-08-20, main) and its backport #16539 (FilterDirectory#copyFrom javadoc, branch_10_6); those changes are correct",
   "introduced_date": "2016-05-25 (author date of 268da5be45e and a6839beb87a); the bookkeeping contract it breaks was written on 2026-08-20 (#16530, main) and 2026-08-27 (#16539, branch_10x/branch_10_6)",
   "first_affected_version": "6.1.0 [exec]. The written bookkeeping rule exists only on main (Directory#copyFrom) and in the 10.6.0 line (FilterDirectory#copyFrom javadoc); in 10.5.2 and earlier the behaviour is an undocumented bypass, not a break of a written rule",
   "affected_versions": "every release from 6.1.0 to 10.5.2, 10.6.0 (the branch_10_6 head 4ae946e5a9b, the RC1 revision) and main a9779ef3c193 [exec]. Releases in between by code reading (hard-link path unchanged since 268da5be45e). Not a 10.6 regression. Not fixed upstream: no commit to HardlinkCopyDirectoryWrapper, FilterDirectory or Directory on main (head c5ab3e57b9b, 2026-10-28) or branch_10_6 since 2026-10-20, and no open PR touches the class [read]. Executed only on aarch64 Linux with JDK 25 (the 6.1.0 run needs --add-opens java.base/java.nio for JDK 25)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/5811",
    "https://issues.apache.org/jira/browse/LUCENE-4746",
    "https://github.com/apache/lucene/issues/111",
    "https://github.com/apache/lucene/issues/14985",
    "https://github.com/apache/lucene/issues/16173",
    "https://github.com/apache/lucene/issues/16530"
   ],
   "doc": "",
   "repro": "repro/LFV-912/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-365",
   "priority": "low",
   "priority_rank": 845,
   "novelty": "known",
   "withheld": false,
   "area": "store / NRTCachingDirectory (Directory write-once contract)",
   "title": "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",
   "summary": "You wrap a directory in NRTCachingDirectory, write a file with IOContext.DEFAULT (it goes to the wrapped directory), and then call createOutput again for the same name with a small flush context (which goes to the RAM cache), or the other way round. You expect FileAlreadyExistsException, which the Directory contract requires for any existing name. Instead the second create succeeds and the name lives in both homes, so deleteFile removes only the cached copy while the other copy stays listed and readable (in the order above, with the older content), and close() fails (an AssertionError with -ea; with -da, on 9.0.0 and later, a FileAlreadyExistsException, after which the file is in neither home).",
   "impact_class": "wrong error",
   "introduced_commit": "709c7f081245ed56aaa5e7176d8f44c7d3dcb1c4 (branch_7x, first released in 7.3.0; master twin 4bd49726c1416a6146c9bbb86fdf4d7c2adc2b1c, first released in 8.0.0): LUCENE-8149 'NRTCachingDirectory does not need to preemptively delete segment files and generate exceptions' (apache/lucene#9197; committed from the JIRA patch by GitHub ErickErickson with a +1 from jpountz; no PR) removed createOutput's delete of the other-home copy, which created today's two-home state [read]. The missing exception itself is older: createOutput has never checked the other home since the class was added (LUCENE-3092, 3525ba940fa, 3.2), and it became a contract violation only with LUCENE-8415 (apache/lucene#9461, apache/lucene-solr#424; 9dc6cff38a2 on branch_7x, 8892c0d9aff on master; by GitHub dweiss; 7.5.0). The -da file loss in close() comes from LUCENE-8474 (apache/lucene#9520, d7dc53ff7c3, master only, by GitHub dweiss; 9.0.0), which switched unCache to in.copyFrom [exec].",
   "introduced_date": "2018-02-05 (LUCENE-8149); 2018-07-24 for the contract (LUCENE-8415); 2019-01-28 for the -da close() file loss (LUCENE-8474)",
   "first_affected_version": "7.5.0 [exec] (first release with both the LUCENE-8149 code and the LUCENE-8415 'must throw FileAlreadyExistsException' contract; executed by the intended-behaviour check and the history step, 3 of 4 fail with -ea and -da). 7.3.0, 7.3.1 and 7.4.0 have the identical NRTCachingDirectory.java and the same executed behaviour (7.3.0 and 7.4.0: 3 of 4 fail), but their Directory javadoc stated write-once only as a rule for callers, so they are not counted; this corrects the candidate's 8.0.0.",
   "affected_versions": "every release from 7.5.0 through 10.6.0 (10.6.0 by reading), and main ea57360912ed; not fixed upstream. [exec] the finder's 4-test JUnit with the official release jars: 7.5.0, 7.7.3, 8.0.0 and 8.11.4 fail 3 of 4 (-ea and -da; close() keeps the first on-disk copy), 9.0.0, 9.12.3, 10.5.2 and main fail 4 of 4 with -da and 3 of 4 with -ea; the independent reproduction's 8-test JUnit fails on main, 10.5.2 and 9.12.3 (3 of 8 -ea, 5 of 8 -da). [read] a bytecode scan of the 75 SHA-1-checked core jars 7.0.0-10.5.2 finds no existence check in createOutput in any release and no other-home delete from 7.3.0 on; the contract sentence is in Directory.java at all 57 history-clone tags from 7.5.0 to 10.5.2 and at none from 7.0.0 to 7.4.0 (the 8.8.2-8.11.3 tags are not in the local clones; inferred from 8.8.1, 9.0.0 and the executed 8.11.4). The -da file loss in close() is in 9.0.0 and later only. branch_10_6 (10.6.0, released 2026-10-29): likely affected (NRTCachingDirectory.java unchanged on main since 448c7d8e241, 2026-02-11) [read].",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-3658",
    "https://github.com/apache/lucene/issues/4732",
    "https://issues.apache.org/jira/browse/LUCENE-8149",
    "https://github.com/apache/lucene/issues/9197",
    "https://issues.apache.org/jira/browse/LUCENE-6957",
    "https://github.com/apache/lucene/issues/8014"
   ],
   "doc": "",
   "repro": "repro/LFV-365/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-836",
   "priority": "low",
   "priority_rank": 846,
   "novelty": "new",
   "withheld": false,
   "area": "store / ByteBuffersDirectory (rename vs. a concurrent createOutput or rename onto the source name)",
   "title": "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",
   "summary": "You share one ByteBuffersDirectory between two threads: one renames file 'a' to a new name while the other creates a new 'a' (createOutput, write, close) or renames a temp file onto 'a', and you expect the new 'a' to stay until someone deletes or renames it, as it does on FSDirectory. Instead, now and then the new file vanishes: rename has already moved its own entry with the checked files.remove(source, file) and then runs a leftover unconditional files.remove(source), which can only remove a different entry, the one the other thread has just put under 'a'. Neither call reports an error; afterwards listAll lacks the file and openInput throws NoSuchFileException (stress tests lose between 1 and a few hundred files per 100,000 rounds on every run).",
   "impact_class": "data corruption",
   "introduced_commit": "f762953aab5be90052ee8bbfe6cbc9f1535356a6 (master, 'LUCENE-8468: A ByteBuffer based Directory implementation (and associated classes).', Dawid Weiss; a JIRA patch, no pull request; the issue is now apache/lucene#9514) and its same-day branch_7x backport 7eb7b90edf6, which shipped first, in 7.5.0 [read] [exec]. The three map calls were copied from RAMDirectory.rename, where LUCENE-7345 (c311eb1b7ed, 2016-06-20, now #8399, first released in 6.2.0) replaced 'put(dest, file); remove(source)' with putIfAbsent(dest, file) plus the checked remove(source, file) but kept the old trailing remove(source) [exec]. Present since ByteBuffersDirectory was created, not a regression of that class",
   "introduced_date": "2018-08-28 (f762953aab5 and the branch_7x backport 7eb7b90edf6); the pattern in RAMDirectory 2016-06-20 (c311eb1b7ed, LUCENE-7345)",
   "first_affected_version": "7.5.0 [exec] (tag commit dated 2018-09-17, through the branch_7x backport; the master commit is first in 8.0.0); 7.4.0 and earlier have no ByteBuffersDirectory [exec]. An earlier reading said 'since 8.0'; the executed history shows 7.5.0. Lineage, different class: RAMDirectory had the same leftover from 6.2.0 until it was removed in 9.0 [exec]",
   "affected_versions": "every release that has ByteBuffersDirectory, 7.5.0 through 10.6.0, and main a9779ef3c193 [exec] [read]; not fixed on upstream main 20ced71c1e6, branch_10x or branch_10_6 (2026-10-27/28) [read]. All runs used JDK 25 on one aarch64 Linux host",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-836.html",
   "repro": "repro/LFV-836/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1158",
   "priority": "low",
   "priority_rank": 847,
   "novelty": "new",
   "withheld": false,
   "area": "store / ByteBuffersDirectory (rename failure path: two concurrent renames of one source)",
   "title": "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",
   "summary": "Two threads call rename on one ByteBuffersDirectory with the same source and different destinations, rename('a', 'x') and rename('a', 'y'); you expect one call to win and the other to fail and leave nothing behind, which is what happens when the calls run one after the other (the second throws NoSuchFileException) and on FSDirectory. Instead both calls first publish the file under their own dest, then only one of them can remove 'a', and the loser throws IllegalStateException('File was unexpectedly replaced: a') without withdrawing its dest. Afterwards listAll() shows the same file as both 'x' and 'y', permanently, although one of the two renames reported failure.",
   "impact_class": "minor",
   "introduced_commit": "7eb7b90edf6fc780df6bee58922a714bd665ab34 (branch_7x, 'LUCENE-8468: A ByteBuffer based Directory implementation (and associated classes)', Dawid Weiss; a JIRA patch, no pull request; the issue is now apache/lucene#9514; shipped first, in 7.5.0) and the same change on master, f762953aab5be90052ee8bbfe6cbc9f1535356a6 (first in 8.0.0) [read] [exec]. The code shape (putIfAbsent(dest), then an identity-checked remove(source, file) that throws without withdrawing dest) was taken from RAMDirectory.rename, where LUCENE-7345 (c311eb1b7ed on master, 07920c4fdaa on branch_6x, 2016-06-20, now #8399, first released in 6.2.0) added it [exec]. Present since ByteBuffersDirectory was created, not a regression of that class",
   "introduced_date": "2018-08-28 (author date of 7eb7b90edf6 and f762953aab5); the code shape in RAMDirectory 2016-06-20 (LUCENE-7345)",
   "first_affected_version": "7.5.0 [exec] (through the branch_7x commit 7eb7b90edf6; the master commit is first in 8.0.0); 7.4.0 and earlier have no ByteBuffersDirectory [exec]. Lineage, different class: RAMDirectory had the same missing rollback from 6.2.0 until it was removed in 9.0.0 [exec]",
   "affected_versions": "every release that has ByteBuffersDirectory, 7.5.0 through 10.6.0, and main 5adff78bb168 [exec] [read]; not fixed upstream (main tip 1c2072f0284, 2026-11-02: the file's last commit is c2825cfc4b2, #16063, author and commit date 2026-05-15). Not new in 10.6. All runs used JDK 25 on one aarch64 Linux host",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1158.html",
   "repro": "repro/LFV-1158/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-191",
   "priority": "low",
   "priority_rank": 848,
   "novelty": "new",
   "withheld": false,
   "area": "misc / index tools (IndexSplitter.split, SegmentInfos.commit durability)",
   "title": "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",
   "summary": "You copy segments into a new index with IndexSplitter (new IndexSplitter(src).split(dest, segments), or the command line 'IndexSplitter <src> <dest> <segments>'), and the machine crashes or loses power shortly after the call returns. You expect what every Lucene commit is built for (Directory.sync javadoc: Lucene syncs files 'to prevent a machine/OS crash from corrupting the index'; IndexWriter.commit syncs all referenced files first): the destination's commit only references files whose bytes are on stable storage. Instead split() copies the segment files with Files.copy and never fsyncs them, and SegmentInfos.commit then fsyncs only the new segments_N and the directory, so the commit and the copied file names can survive the crash while the copied .si, .cfs and .cfe data does not, and opening the destination fails (CorruptSegmentInfoException on _1.si on main, CorruptIndexException on 10.5.2 and 9.12.3, in the simulated post-crash state).",
   "impact_class": "index unusable",
   "introduced_commit": "2fc8e01d9e1ae0eae040f27a2bcd044c23d27369 (svn r823153, 'LUCENE-1959: add IndexSplitter tool to pull segment files out of an index into another', committed by mikemccand from a patch contributed on JIRA LUCENE-1959, migrated as apache/lucene#3034; svn era, no PR) [read] [exec]; later in-place rewrites of the copy and commit lines (LUCENE-2805, LUCENE-4055, LUCENE-5945 switched to Files.copy, LUCENE-9600 moved the class to org.apache.lucene.misc.index) kept the omission",
   "introduced_date": "2009-10-08",
   "first_affected_version": "3.0.0 [exec] (released 2009-11-25; contrib/CHANGES.txt 3.0.0 lists LUCENE-1959, and lucene-misc-3.0.0.jar contains org/apache/lucene/index/IndexSplitter.class); 2.9.x and earlier have no IndexSplitter [exec]",
   "affected_versions": "every release from 3.0.0 through 10.6.0, and main ea57360912ed. [exec] The one-test repro fails on the 10.6.0 jars, -ea and -da (2026-10-31). 13 releases fail, each with the copied files never fsynced and a post-crash image that a reader cannot open: 3.0.0, 3.6.2, 4.0.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0 and 9.1.0 (version-portable main() repro with a libc-level fsync tracer), 9.12.3 and 10.5.2 (finder JUnit and tracer), plus main (JUnit and tracer, -ea and -da); in every version the control (IndexWriter.commit in the source directory) fsynced every referenced file, and with the fix shadowed the tracer passes on main; the independent reproduction also showed the missing forces on main, 10.5.2 and 9.12.3 with the JDK's own jdk.FileForce flight-recorder event and no file-system wrapper. [read] the other releases are inferred from unchanged code. Before 4.8.0 (LUCENE-5588) Lucene fsynced no directories, IndexWriter included, so for 3.0-4.7 the 'file names are durable' half of the crash image is the same assumption IndexWriter relied on then. The class is org.apache.lucene.index.IndexSplitter (lucene-misc) up to 8.11.4 and org.apache.lucene.misc.index.IndexSplitter since 9.0.0. Not fixed upstream: main and branch_10x 1309534296e3 have no sync [read]; 10.6.0 is executed above. All runs on aarch64 with JDK 25.0.3; old releases ran on that JDK too, which does not change which files Lucene asks to fsync.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-191.html",
   "repro": "repro/LFV-191/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-201",
   "priority": "low",
   "priority_rank": 849,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexFileDeleter and util/FileDeleter (deletion of expired commits, crash durability)",
   "title": "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",
   "summary": "You index with IndexWriter on an FSDirectory with default settings and commit; after the new commit is fsynced, the default deletion policy removes the previous commit, first its segments_N and then the files only it used. You expect that an OS crash or power loss at that point leaves the old commit either complete or gone, which is what the FileDeleter comments and the LUCENE-6616 CHANGES entry ('the index is never left in a state where an expired segments_N references non-existing files') describe. Instead nothing fsyncs the directory between the two deletion passes, so on a file system that persists those unlinks out of order the old segments_N can survive while its _N.si or compound files are gone; DirectoryReader still opens the newest commit, but new IndexWriter fails (CorruptSegmentInfoException on main), listCommits throws and CheckIndex reports corruption (shown in crash states built in software from the real operation sequence; no physical crash was run).",
   "impact_class": "index unusable",
   "introduced_commit": "93c34fe2026bdc8d26dd3c18232209e200c18e03 (branch_5x, svn r1689940, 2015-07-08, committed by mikemccand: 'LUCENE-6616: IW lists files only once on init, IFD no longer suppresses FNFE, IFD deletes segments_N files last'; issue LUCENE-6616 = apache/lucene#7674, svn era, no PR); same-day trunk commit dd75010e6bfc086c34cf892fa40d568e778723c0 (svn r1689893, first released in 6.0.0) [exec]. The one change did both halves: it removed IndexFileDeleter init's tolerance of a commit whose files are missing (the LUCENE-948 catch around SegmentInfos.readCommit; IndexFileDeleter.java:161 on main still blames to dd75010e6bf), and it made deletion two passes, segments_N first, with no directory fsync between or after them. The parent deleted the expired segments_N last and tolerated the resulting stale commit.",
   "introduced_date": "2015-07-08",
   "first_affected_version": "5.3.0 [exec] (release commit dated 2015-08-20); 5.2.1 is the last unaffected release [exec]; on the trunk line the change first shipped in 6.0.0",
   "affected_versions": "every release from 5.3.0 through 10.5.2, and main ea57360912ed. [exec] a version-portable main() probe (public API only, all 16 crash states per run) fails on 5.3.0, 5.5.5, 6.0.0, 6.1.0, 6.2.0, 6.4.2, 6.5.0, 6.6.6, 7.0.0, 7.1.0, 7.2.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.8.0, 9.9.0, 9.12.3, 10.0.0, 10.5.2 and main (with -da also on 5.3.0, 5.5.5, 6.0.0, 9.12.3, 10.5.2 and main), always with 4 states in which IndexWriter fails on every open; the candidate JUnit tests fail on 8.11.4, 9.12.3, 10.5.2 and main. [read] code identity (segments_N-first pass, no init tolerance, no syncMetaData in the deleter) on all 94 release tags 5.3.0-10.5.2 in the history clone. The symptoms changed over time, the cause did not: with -da, 5.3.0-5.5.5 fail only the 4 .si states, and from 6.0.0 (LUCENE-6835) the 3 .cfs/.cfe states also fail the first open; listCommits throws from 6.5.0 (LUCENE-7662); CheckIndex reports the .si states not clean from 9.9.0 (#12530) and reports them clean on 8.11.4 and 9.8.0; the exception is CorruptSegmentInfoException on main (#16476, which also shipped in 10.6.0), CorruptIndexException 'Unexpected file read error while reading index.' on 6.5.0-10.5.2 and NoSuchFileException on 5.3.0-6.4.2. Unaffected [exec]: 5.2.1 and the two parent commits. Before 5.0 not executed; the init tolerance is present at 3.0.1, 4.0.0 and 4.10.4 [read]. Not fixed upstream: main and branch_10x 1309534296e3 have the same two passes with no sync [read]. All runs on aarch64 with JDK 25; on Windows directory fsync is a no-op (IOUtils.java:526-533) [read].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/7820",
    "https://issues.apache.org/jira/browse/LUCENE-6762",
    "https://github.com/apache/lucene/issues/10906",
    "https://issues.apache.org/jira/browse/LUCENE-5925",
    "https://issues.apache.org/jira/browse/LUCENE-7373",
    "https://github.com/apache/lucene/issues/12530"
   ],
   "doc": "",
   "repro": "repro/LFV-201/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-194",
   "priority": "low",
   "priority_rank": 850,
   "novelty": "new",
   "withheld": false,
   "area": "index / deletion policies (PersistentSnapshotDeletionPolicy persistence, directory fsync)",
   "title": "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",
   "summary": "You protect a commit with PersistentSnapshotDeletionPolicy.snapshot(), whose javadoc says that once the method returns the snapshot information is persisted in the directory. Instead persist() writes and fsyncs the new snapshots_N file but never fsyncs the directory (Directory.syncMetaData()), the step Lucene's own commit takes because a new file's name is not durable until then. After an OS crash or power loss the save file can be gone: the snapshot count comes back as 0 and, with the snapshots in a separate Directory, the reopened IndexWriter deletes the commit the snapshot was protecting (a lost release() instead brings a released snapshot back).",
   "impact_class": "data corruption",
   "introduced_commit": "b7047694256a (branch_4x, svn r1624362, first released in 5.0.0) and its trunk twin bb0256f26076 (svn r1624194, first released in 6.0.0, an ancestor of every 6.x-10.x release and main): LUCENE-5925 'Use rename instead of segments_N fallback / segments.gen etc' by rmuir (JIRA, migrated as #6987; 2014, before GitHub PRs, so no PR) [read]. persist()'s file-only sync itself dates from LUCENE-4976 (8c6e38ee605, 2013, first released in 4.4.0); 4.8.0-4.10.4 were covered by the directory fsync that LUCENE-5588 had put inside FSDirectory.sync().",
   "introduced_date": "2014-09-11 (LUCENE-5925, committed on trunk and branch_4x the same day)",
   "first_affected_version": "5.0.0 [exec] (fsync probe: 4.10.4 passes, 5.0.0 fails; 4.10.4 shipped after 5.0.0 from the 4.10 bugfix branch, which never took LUCENE-5925)",
   "affected_versions": "all 107 Maven Central releases 5.0.0-10.5.2, 10.6.0 and main ea57360912ed [exec]. Not affected: 4.8.0-4.10.4 (9 releases) [exec]. 4.4.0-4.7.2: no verdict by execution (the recorder cannot see their RandomAccessFile fsyncs); by source no Lucene code fsynced any directory then, a Lucene-wide limitation that LUCENE-5588 removed, not this regression [read]. Upstream main, branch_10x, branch_10_6 and branch_9_12 still have the same persist() (read-only check 2026-10-26). Directory.syncMetaData() exists from 6.2.0 (LUCENE-7373), so the one-line fix applies from 6.2.0 on [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-194.html",
   "repro": "repro/LFV-194/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1092",
   "priority": "low",
   "priority_rank": 851,
   "novelty": "known",
   "withheld": false,
   "area": "index / SegmentInfos.FindSegmentsFile (commit discovery)",
   "title": "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)",
   "summary": "You open a healthy index while a writer commits and expect DirectoryReader.open to open one of the commits that existed during the call; FindSegmentsFile lists the directory twice to detect a concurrent change, as its comment says listAll() is weakly consistent. If each of the two listings overlaps one complete commit (rename to segments_N+1, then deletion of segments_N) and omits both segments files, the two listings are equal and open throws IndexNotFoundException 'no segments* file found'; this is shown with a simulated listing that returns only the files present for the whole call.",
   "impact_class": "crash",
   "introduced_commit": "unknown (not bisected); [read] the double-listing check comes from LUCENE-5925 (2014), which said it also solves #3659",
   "introduced_date": "unknown (not bisected); LUCENE-5925 is from 2014 [read]",
   "first_affected_version": "unknown (not bisected); oldest executed 9.12.3 [exec]",
   "affected_versions": "9.12.3 and 10.5.2 [exec]; released 10.6.0 (-da) and main e1faeba08bde (-ea, -da) [exec]: both tests (NIOFSDirectory and ByteBuffersDirectory under the simulated listing) fail.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/3659",
    "https://issues.apache.org/jira/browse/LUCENE-2585",
    "https://issues.apache.org/jira/browse/LUCENE-5925"
   ],
   "doc": "",
   "repro": "repro/LFV-1092/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1142",
   "priority": "low",
   "priority_rank": 852,
   "novelty": "new",
   "withheld": false,
   "area": "util / FST (FSTCompiler.Builder.build: the default on-heap DataOutput)",
   "title": "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",
   "summary": "You create one FSTCompiler.Builder (BYTE1, PositiveIntOutputs, no dataOutput set), build() a compiler, add a -> 1 and read the FST back with FST.fromFSTReader(compile(), getFSTReader()) as compile()'s javadoc shows, then call build() again on the same Builder for a second FST with b -> 2; you expect two independent FSTs, as two Builders give and as the same code gave up to 9.9.2. Instead the second FST returns null for b with assertions off (the first still answers a -> 1), and with -ea the second compile() fails on an assert in ReadWriteDataOutput.writeByte. build() writes its default output into the Builder's own dataOutput field, so the second compiler appends to the first compiler's already frozen output while numbering its node addresses from 1, and its root points into the first FST's bytes.",
   "impact_class": "silent wrong results",
   "introduced_commit": "b6999818474c518953d1290ef304c84dedb04ab6 (#12624 'Allow FST builder to use different writer (#12543)', author dungba88, merged by mikemccand; branch_9x copy 193d8f14107) [read]",
   "introduced_date": "2023-12-07 (author date of b6999818474 on main; PR merged 2023-12-07T14:26:04Z; branch_9x commit 193d8f14107 committed 2023-12-08)",
   "first_affected_version": "9.10.0 [exec]",
   "affected_versions": "9.10.0 to 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT). Executed, fail [exec]: main -ea and -da (finder, the independent reproduction, the intended-behaviour check, judge and the registration check), 10.6.0 -ea and -da, 10.5.2 -da, 10.0.0 -da, 9.12.3 -da, 9.10.0 -ea and -da. Executed, pass: 9.9.2 (-ea and -da, the scenario on the pre-9.10 API; before #12624 each compiler made its own BytesStore). 9.11.0-9.12.2 and 10.1.0-10.5.1 by reading (the line is in every one of those tags, unchanged per blame). Not new in 10.6 (since 9.10.0). Not fixed upstream: upstream main 1c2072f0284 (2026-11-02) still assigns the field (FSTCompiler.java:354), and the newest commit on the file is 8cd74fed97b (#15133, author date 2026-09-29, ramBytesUsed accounting). All runs on Linux aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1142.html",
   "repro": "repro/LFV-1142/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1159",
   "priority": "low",
   "priority_rank": 853,
   "novelty": "new",
   "withheld": false,
   "area": "util / FST (Util.readCeilArc: follow overwritten by readFirstTargetArc before the list-node scan re-reads follow.target())",
   "title": "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)",
   "summary": "You build a small FST (keys ab, ac, x) with the default FSTCompiler and call Util.readCeilArc('a', fst, arc, arc, in) with the start arc as both follow and arc, the same call shape Lucene's own TestUtil uses. You expect the arc 'a', the first arc >= 'a' leaving the start arc, which the same call with two distinct Arc objects returns. Instead it returns the arc 'b' from the node one level down (and null instead of 'x' for label 'w'), because readFirstTargetArc overwrites the shared object before the list-node scan re-reads follow.target(); when follow is a final arc the call reads FST address -1 and throws ArrayIndexOutOfBoundsException.",
   "impact_class": "silent wrong results",
   "introduced_commit": "66b2c78d6bafbed21e70ab1de9fea25f35f2ca04 (LUCENE-3846 'Fuzzy suggester', now #4919, mikemccand; svn feature branch lucene3846 r1397171; no pull request, Subversion era), which reached trunk as d8e44bd09d6 (r1403779) and branch_4x as 1fb15d729d4 (r1403780) [read]",
   "introduced_date": "2012-10-11 (author and commit date of 66b2c78d6ba on the feature branch); trunk and branch_4x commits 2012-10-30",
   "first_affected_version": "4.1.0 [exec]",
   "affected_versions": "every release from 4.1.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT); not fixed anywhere (upstream main 1c2072f0284, 2026-11-02, still has both lines at Util.java:827 and :875). Executed, fail [exec]: main -ea and -da (finder, the independent reproduction, the cross-model review, the intended-behaviour check, judge and the registration check), 10.6.0 (-ea and -da), 10.5.2 (-ea, the independent reproduction), 10.0.0 (-da), 9.12.3 (-ea and -da), 8.11.4, 7.7.3, 6.6.6, 5.5.5, 4.10.4 and 4.1.0 (-da; releases before 9.x through main() adapters with the same FST {ab, ac, x} and the same aliased call); 4.0.0: compile error (API absent). 9.0.0-9.11.x and 10.1.0-10.5.1 by reading (no commit changed the two lines). Not new in 10.6. All runs on Linux aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1159.html",
   "repro": "repro/LFV-1159/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-052",
   "priority": "low",
   "priority_rank": 854,
   "novelty": "new",
   "withheld": false,
   "area": "util / FST",
   "title": "FSTMetadata.save always writes the current version, so re-saving a pre-9.0 BYTE2 FST breaks its lookups",
   "summary": "You load an FST that was written before 9.0 with BYTE2 labels and save it again with Lucene 9.0 or later. You expect the re-saved FST to work like the original. Instead save() writes the header version VERSION_CURRENT, so readers decode the labels with the wrong byte order and the lookups fail (0 of 9 keys found in the repro); FSTs built with setVersion(VERSION_90) are also labelled 9 and rejected by 9.8.",
   "impact_class": "silent wrong results",
   "introduced_commit": "LUCENE-9047 (b84e0c272b6, PR #107) [exec]",
   "introduced_date": "2021-05-03",
   "first_affected_version": "9.0.0 [exec]",
   "affected_versions": "9.0.0 to 10.5.2 (33 releases) and main [exec]; 8.x is not affected",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-052.html",
   "repro": "repro/LFV-052/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-024",
   "priority": "low",
   "priority_rank": 855,
   "novelty": "new",
   "withheld": false,
   "area": "search / multi-term queries",
   "title": "FuzzyQuery on the empty term matches only the empty term",
   "summary": "You run a FuzzyQuery whose term text is empty. You expect it to match every indexed term within the edit distance, as the LUCENE-7439 contract says. Instead it matches only the empty term.",
   "impact_class": "silent wrong results",
   "introduced_commit": "LUCENE-7439 (471f90cf825) [exec]",
   "introduced_date": "2016-09-15",
   "first_affected_version": "6.3.0 [exec]",
   "affected_versions": "6.3.0 to 10.5.2 (all 87 releases) and main [exec]; 5.0.0 to 6.2.1 follow the older documented short-term rule [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-024.html",
   "repro": "repro/LFV-024/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-020",
   "priority": "low",
   "priority_rank": 856,
   "novelty": "new",
   "withheld": false,
   "area": "util / automaton",
   "title": "The Kleene star of the empty language returns the empty language instead of {\"\"}",
   "summary": "You build a RegExp or call Operations.repeat on an operand whose language is empty, such as (a&b)*. You expect the result to accept the empty string, since the star of any language contains it. Instead the result accepts nothing.",
   "impact_class": "silent wrong results",
   "introduced_commit": "LUCENE-6054 fix 54156c042d4 (#7116) added the `return a` that makes the star of the empty language empty; LUCENE-5752 (ec2eaaafad8) had made makeEmpty() 0-state [read]",
   "introduced_date": "2014-11-07 (54156c042d4)",
   "first_affected_version": "4.10.3",
   "affected_versions": "4.10.3+ [read]; 4.10.4, 5.0.0, 10.1.0, 10.5.2 and main [exec]; 4.9.1 correct [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-020.html",
   "repro": "repro/LFV-020/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1167",
   "priority": "low",
   "priority_rank": 857,
   "novelty": "new",
   "withheld": false,
   "area": "util / automaton (Operations.totalize, used by Operations.complement and Operations.minus)",
   "title": "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",
   "summary": "You build Automata.makeCharRange('a', Integer.MAX_VALUE), which accepts every one-code-point word from \"a\" upward, and take its complement with Operations.complement; you expect a deterministic automaton (as the javadoc promises) that rejects \"a\". Instead the complement accepts \"a\" and is not deterministic, with no error: totalize, which complement uses to send every missing label to a dead state, computes t.max + 1 in int, the sum wraps to Integer.MIN_VALUE, so it also adds a dead-state arc over the whole code-point range on top of the real arc, and that dead state becomes accepting in the complement. Operations.minus, which subtracts through complement, likewise keeps words it should remove.",
   "impact_class": "minor",
   "introduced_commit": "5b74a4ec611dd83f1a8214fc5258923c74d828d1 (trunk, svn r940671, 'LUCENE-2265: cutover Fuzzy, Wildcard, Regexp queries to operate on Unicode UTF32 code point not UTF16 code units'; a JIRA patch, no pull request; the issue is now apache/lucene#3341; patch by @rmuir, finished with and committed by @mikemccand) [read] [exec]. It widened transition labels and makeCharRange to int and kept the line `if (t.max + 1 > maxi) maxi = t.max + 1;` from the char-label totalize (b679816a700, LUCENE-2370 flex reintegration, 2010-04-06), where t.max + 1 is at most 65536 and cannot wrap. LUCENE-5752 (#6814; 6ac082fbe1d, 2014-06-17, first in 4.10.0) moved totalize into Operations unchanged",
   "introduced_date": "2010-05-03 (author date = commit date of 5b74a4ec611, 2010-05-03T23:23:57Z)",
   "first_affected_version": "4.0.0-alpha [exec]; the repro's check first fails deterministically in 4.10.0 [exec]; 3.6.2 and earlier have no automaton package [exec]",
   "affected_versions": "every release from 4.0.0-alpha through 10.6.0, and main 5adff78bb168 [read] [exec]; not fixed upstream (main tip 1c2072f0284, 2026-11-02, still has `if (t.max + 1 > maxi)` at Operations.java:1333; last commit on the file 54283150a81, #16255, author and commit date 2026-06-14). complement and minus are not deprecated in 10.6.0 or any earlier release; they are @Deprecated ('will be removed in Lucene 12') only on main and branch_11x, by #15763 and #15755 (author date 2026-02-23). Not new in 10.6. All runs used JDK 25 on one aarch64 Linux host",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1167.html",
   "repro": "repro/LFV-1167/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-813",
   "priority": "low",
   "priority_rank": 858,
   "novelty": "new",
   "withheld": false,
   "area": "util / automaton",
   "title": "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",
   "summary": "You run a RegexpQuery, or a classic QueryParser query /<+1-+9>/, on a field with the terms 5 and 05. The RegExp javadoc says interval bounds are non-negative decimal integers and that bounds with the same number of digits fix the length of the matching strings, so you expect either an 'interval syntax error' (as for '-1', ' 1' or an overflowing bound) or the meaning of <1-9>, which matches 5. Instead the parser accepts the '+' and counts it as a digit, so <+1-+9> matches only 01 to 09 and returns 05; <+1-9> and <+100-999> lose their fixed width and accept any number of leading zeros, and <+100-+999> means 0100 to 0999.",
   "impact_class": "minor",
   "introduced_commit": "b679816a7001ba986618f103a9a9c67ececc7ff8 (svn trunk r931278, 'LUCENE-2370: Reintegrate flex_1458 branch into trunk (revision 931101)'; the code is the dk.brics.automaton port of LUCENE-1606; SVN era, no GitHub PR; the flex-branch commits are not in the history clone) [read]. Latent until Java 7: Integer.parseInt accepts a leading '+' only since JDK 7 (JDK-5017980, fixVersion 7, resolved 2011-05-17); before that '+1' threw NumberFormatException, which this block turns into 'interval syntax error' [read]. Not a Lucene regression: the block has had only two cosmetic edits since (887fe4c83d4, 2020-07-08, LUCENE-9386; fb8183332bc, 2023-08-17, #12462) [read]",
   "introduced_date": "2010-04-06 (Lucene commit); observable only on Java 7 or later runtimes (JDK-5017980, resolved 2011-05-17)",
   "first_affected_version": "4.0.0-ALPHA [exec]; 4.0.0-ALPHA to 4.7.2 supported Java 6, where the input was rejected [read], so 4.8.0 (Java 7 minimum) is the first release affected on every supported runtime; 3.0.1 and 3.6.2 have no automaton package [exec]",
   "affected_versions": "every release from 4.0.0-ALPHA to 10.6.0, and main a9779ef3c193 [exec]. Runtime condition: Java 7 or later. Not fixed upstream: upstream main 20ced71c1e6e (2026-10-27) has the same block, and the newest RegExp.java commit is ba69bfb1ea9a (author date 2026-07-31, unrelated) [read]. The origin library dk.brics.automaton has the same code",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-813.html",
   "repro": "repro/LFV-813/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-441",
   "priority": "low",
   "priority_rank": 859,
   "novelty": "new",
   "withheld": false,
   "area": "util / automaton",
   "title": "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",
   "summary": "You build a numeric-interval automaton with Automata.makeDecimalInterval(min, max, digits) and pass a negative min, for example (-1, 5, 0). You expect either the documented IllegalArgumentException or an automaton for the non-negative integers in the interval (here 0 to 5, as makeDecimalInterval(0, 5, 0) gives). Instead the call returns without error an automaton that rejects \"0\" to \"4\" and accepts \"12\", \"49\", \"-1\" and \"-5\", and some all-negative ranges such as (-15, -1, 0) throw an undocumented StringIndexOutOfBoundsException.",
   "impact_class": "minor",
   "introduced_commit": "b679816a7001ba986618f103a9a9c67ececc7ff8 (svn trunk r931278, 'LUCENE-2370: Reintegrate flex_1458 branch into trunk (revision 931101)'; feature issues LUCENE-1606 and LUCENE-2089 per the CHANGES.txt entry in that commit; no GitHub PR, SVN era): it added BasicAutomata.makeInterval with the check 'if (min > max || (digits > 0 && y.length() > digits)) throw new IllegalArgumentException();', a port of dk.brics.automaton, whose BasicAutomata.makeInterval has the same check [read]. Not a regression: the check line is unchanged since then (LUCENE-5512 diamond edit, LUCENE-5752 class rename and rewrite to Automata.makeInterval, LUCENE-5879 method rename to makeDecimalInterval in 5.2.0, #14218 removeDeadStates in 10.2.0 left it untouched) [read]",
   "introduced_date": "2010-04-06",
   "first_affected_version": "4.0.0-ALPHA [exec]; first GA release 4.0.0 [exec]; 3.0.1 and 3.6.2 have no automaton package (API absent) [exec]",
   "affected_versions": "every release that has the API, 4.0.0-ALPHA to 10.6.0, and main ea57360912ed [exec]; the other releases [read]. API names: BasicAutomata.makeInterval (4.0.0-ALPHA to 4.9.1), Automata.makeInterval (4.10.0 to 5.1.0), Automata.makeDecimalInterval (5.2.0 on). Not fixed upstream: upstream main 49483e82b357 (read 2026-10-26) has the same check and no open PR changes the method [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-441.html",
   "repro": "repro/LFV-441/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-869",
   "priority": "low",
   "priority_rank": 860,
   "novelty": "new",
   "withheld": false,
   "area": "core / analysis: AutomatonToTokenStream (automaton to token-graph conversion)",
   "title": "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)",
   "summary": "You build an automaton with Lucene's standard code-point constructors, for example Automata.makeString(\"\\uD801\\uDC00\") (U+10400) or new RegExp(\"a\" + an emoji).toAutomaton(), and convert it with AutomatonToTokenStream.toTokenStream, whose javadoc says the stream releases the automaton's edges as tokens. You expect the token for the edge labelled U+10400 to be that character (the surrogate pair D801 DC00). Instead incrementToken appends (char) label, which keeps only the low 16 bits, so the token is U+0400 (a Cyrillic letter), U+1F600 becomes the private-use U+F600 and U+10000 becomes a NUL char, silently.",
   "impact_class": "minor",
   "introduced_commit": "647255b4d29bb56ddcfdf44bdb6e7d5d0ca76a14 (apache/lucene#157, LUCENE-9963 'Improve FlattenGraphFilter's robustness when handling incoming token graphs with holes', author @glawson0), which created AutomatonToTokenStream as test infrastructure for FlattenGraphFilter with the (char) cast and the one-token-per-label-value loop already in place; 8.x backport 75eba3892979 (apache/lucene-solr#2551, branch_8x) [read]. Not a regression.",
   "introduced_date": "2021-08-09 (647255b4d29, author date 2021-08-10 05:06:53 +0900 = 2021-08-09T20:06:53Z, the merge time of PR #157); 8.x backport 2021-08-16 (75eba3892979, author date)",
   "first_affected_version": "8.10.0 [exec] (the first release with AutomatonToTokenStream, via the branch_8x backport; lucene-core 8.9.0 has no such class [exec]); 9.0.0 on the main line [exec]",
   "affected_versions": "Every release that has the class, all 40 executed with the defect present: 8.10.0, 8.10.1, 8.11.0-8.11.4, 9.0.0-9.12.3 (21 releases), 10.0.0-10.5.2 (12 releases) [exec]; branch_10_6 head 4ae946e5a9b9 (10.6.0) [exec]; main a9779ef3c193 [exec]. Not fixed upstream: the cast is present on main head c5ab3e57b9b (2026-10-28), branch_10x 657014b3c579 and branch_10_6, and the newest commit on the file is 7335eb0ad96 (#15704, author date 2026-02-26, a refactor) [read]. Not affected: 8.9.0 and earlier (class absent) [exec]. All runs with JDK 25 on aarch64 Linux.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-869.html",
   "repro": "repro/LFV-869/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1166",
   "priority": "low",
   "priority_rank": 861,
   "novelty": "new",
   "withheld": false,
   "area": "util / FST (Outputs.skipFinalOutput default; FST.findTargetArc list-node scan)",
   "title": "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",
   "summary": "You write an Outputs<Long> that delegates everything to PositiveIntOutputs except writeFinalOutput and readFinalOutput, which store final outputs as a fixed 8-byte long, and you keep skipFinalOutput, whose javadoc says it 'defaults to just calling readFinalOutput and discarding the result'; you build an FST from a=5, ab=3, b=7 with the default FSTCompiler.Builder and call Util.get(fst, \"b\"). You expect 7, but get null, with or without assertions (BytesRefFSTEnum.seekExact(\"b\") misses the same way). The default body actually calls skipOutput, the regular-output decoder, so the linear scan of the root list node in FST.findTargetArc skips one byte of arc a's 8-byte final output, loses its place in the node and gives up.",
   "impact_class": "minor",
   "introduced_commit": "86e7b083816f942bd2c3e0124c4008819c734003 (LUCENE-5670, now #6732, 'FST should skip over outputs it is not interested in', Christian Ziech via mikemccand; branch_4x 6574202cef5; Subversion era, no pull request): added skipFinalOutput with a javadoc that names readFinalOutput as the default but a body that calls skipOutput, and switched the readLastTargetArc and seekToNextNode scans from readFinalOutput to it. The repro's silent Util.get/seekExact miss needs a second change, 343a9e7100477edd01c7851acc853e2a20ed56f4 (#12692 'Avoid object construction when linear searching arcs', gf2121, reviewed by mikemccand; branch_9x 6fc3483e4fa), which moved findTargetArc's list-node scan from readNextRealArc (decodes with readFinalOutput) to skipOutput/skipFinalOutput [read]",
   "introduced_date": "2014-05-20 (86e7b083816, LUCENE-5670, 4.9.0); 2023-10-20 +0800 = 2023-10-19T16:41Z (author date of 343a9e71004 and 6fc3483e4fa, #12692, merged 2023-10-19, 9.9.0)",
   "first_affected_version": "9.9.0 for the repro's silent Util.get/seekExact miss [exec]; 4.9.0 for the javadoc/body mismatch, which already breaks FSTEnum.seekFloor for such a subclass with an exception [exec]",
   "affected_versions": "Util.get/seekExact path: every release from 9.9.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT). Executed, fail [exec]: main -ea and -da (finder, the independent reproduction, the cross-model review re-run, the intended-behaviour check, judge and the registration check), 10.6.0 -ea and -da, 10.5.2, 10.0.0, 9.12.3, 9.10.0, 9.9.2 and 9.9.0 (9.9.x through a pre-9.10 API variant that differs only in the compile line); 9.8.0 passes. The others by git tag --contains of 6fc3483e4fa (9.9.0-9.12.3) and 343a9e71004 (10.0.0-10.6.0) [read]. Mismatch since 4.9.0 [read]: a seekFloor history probe with the same kind of subclass throws ArrayIndexOutOfBoundsException in FST.readLastTargetArc on 4.9.0 and 9.8.0 and runs out of a 1 GB heap in FSTEnum.pushLast on 9.12.3, 10.6.0 and main [exec], and passes on 4.8.1. Not fixed upstream: upstream main 1c2072f0284 (2026-11-02) still has skipOutput(in) at Outputs.java:81. Not new in 10.6. All runs on Linux aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1166.html",
   "repro": "repro/LFV-1166/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1147",
   "priority": "low",
   "priority_rank": 862,
   "novelty": "new",
   "withheld": false,
   "area": "util / FST (FSTEnum.rewindPrefix label compare; IntsRefFSTEnum seekCeil/seekFloor)",
   "title": "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",
   "summary": "You build a BYTE4 FST with [3] -> 1 and [3, Integer.MAX_VALUE] -> 2, move one IntsRefFSTEnum to [3, MAX] with seekCeil, then call seekCeil([3]) on the same enum; you expect [3], the smallest term >= [3], as a fresh enum returns. Instead it returns [3, MAX] (and seekFloor([3]) returns null), with or without assertions. FSTEnum.rewindPrefix compares labels as getCurrentLabel() - getTargetLabel(); once the target is used up its label is END_LABEL (-1), so MAX - (-1) wraps to Integer.MIN_VALUE and the enum keeps the MAX arc instead of going back to the node's first arc.",
   "impact_class": "minor",
   "introduced_commit": "1cab313a2b88d3e1d1365af4e30f06f7a0d49547 (LUCENE-2843, now #3917, 'Add variable-gap terms index impl.', mikemccand, trunk r1055405; branch_3x copy 43c373b207e with LUCENE-3140, now #4213, r1128870) [read]",
   "introduced_date": "2011-01-05 (author date of 1cab313a2b8 on trunk; branch_3x copy 43c373b207e: 2011-05-29)",
   "first_affected_version": "3.3 [exec]; on the trunk line 4.0.0-alpha (4.0.0 executed: fail)",
   "affected_versions": "3.3 to 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT). All 130 release tags from 3.3 to 10.6.0 in the history clone contain the line [read]; 8.8.2-8.11.3 are untagged there and affected by inference (8.8.1 has the line, 8.11.4 fails). Executed, fail [exec]: main -ea and -da (finder, the independent reproduction, the cross-model review re-check, the intended-behaviour check, judge and the registration check), 10.6.0 -ea and -da, 10.5.2 -ea and -da, 9.12.3 -ea and -da, 8.11.4 -da, 4.0.0 -ea and -da, 3.6.2 -da, 3.3.0 -ea and -da (releases before 9.10 through main() adapters with the same scenario and assertions). Not affected: every release before 3.3 (no FST package; 3.2.0 executed: compile error). Not new in 10.6. Not fixed upstream: upstream main 1c2072f0284 (2026-11-02) still has the subtraction at FSTEnum.java:79, and the newest commit on FSTEnum.java is 570832eb74a (author date 2023-11-09). All runs on Linux aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1147.html",
   "repro": "repro/LFV-1147/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1163",
   "priority": "low",
   "priority_rank": 863,
   "novelty": "new",
   "withheld": false,
   "area": "util / FST (IntsRefFSTEnum seek targets vs. FSTEnum's virtual END_LABEL arc)",
   "title": "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",
   "summary": "You build a BYTE4 FST with [5] -> 1 and [5, 3] -> 2 and call seekCeil([5, Integer.MIN_VALUE]) on a fresh IntsRefFSTEnum; you expect [5, 3], the smallest term >= the target in IntsRef's signed order ([5] < [5, MIN_VALUE] < [5, 3]). Instead it returns [5], a term below the target, with or without assertions. IntsRefFSTEnum hands the raw target int to FSTEnum's arc scan, and the node after the final arc [5] starts with a virtual end-of-term arc labelled END_LABEL = -1, so a negative int either equals that label (-1) or sorts below it and the scan stops at [5]; seekFloor and seekExact go wrong the same way.",
   "impact_class": "minor",
   "introduced_commit": "1cab313a2b88d3e1d1365af4e30f06f7a0d49547 (LUCENE-2843, now #3917, 'Add variable-gap terms index impl.', Michael McCandless, trunk svn r1055405; no pull request, Subversion era), which added FST.END_LABEL = -1, the 'fake' final first arc in FST.readFirstTargetArc, the FSTEnum base class with seekCeil/seekFloor and IntsRefFSTEnum.getTargetLabel returning the raw target int; branch_3x copy 43c373b207e with LUCENE-3140, now #4213, r1128870 [read]",
   "introduced_date": "2011-01-05 (author date = commit date of 1cab313a2b8 on trunk); branch_3x copy 43c373b207e: 2011-05-29",
   "first_affected_version": "3.3 [exec]; on the trunk line 4.0.0-alpha (4.0.0 executed: fail). seekExact, the third affected method, first shipped in 3.6.0 and 4.0.0-alpha [read]",
   "affected_versions": "every release that has IntsRefFSTEnum, 3.3 through 10.6.0 (released 2026-10-29, 4ae946e5a9b), and main 5adff78bb168 (12.0.0-SNAPSHOT); not fixed anywhere (IntsRefFSTEnum.java, FSTEnum.java and FST.java are unchanged between 5adff78bb168 and upstream main 1c2072f0284, 2026-11-02). Executed, fail [exec]: main -ea and -da (finder, the independent reproduction, the cross-model review, the intended-behaviour check, adjudication, tie-breaker and the registration check), 10.6.0 (-da history step and tie-breaker; -ea finder, the independent reproduction, the intended-behaviour check), 10.5.2 (-ea and -da, the independent reproduction), 10.0.0 (-da), 9.12.3 (-da history step; -ea finder, the independent reproduction), and 8.11.4, 7.7.3, 6.6.6, 5.5.5, 4.10.4, 4.0.0, 3.6.2 and 3.3.0 (-da, main() adapters with the same FST and the same seekCeil([5, MIN_VALUE]); the control seekCeil([5, 0]) gives [5, 3] everywhere); 3.2.0: compile error (API absent). The other releases by reading. History runs cover seekCeil; seekFloor and seekExact by reading. Not new in 10.6. All runs on Linux aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1163.html",
   "repro": "repro/LFV-1163/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1204",
   "priority": "low",
   "priority_rank": 864,
   "novelty": "new",
   "withheld": false,
   "area": "util / FST (FSTCompiler fixed-length node encoding: binary search vs direct addressing)",
   "title": "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)",
   "summary": "You build an FST with FSTCompiler.Builder and set directAddressingMaxOversizingFactor(Float.NEGATIVE_INFINITY), because its javadoc says a negative value disables direct addressing and only binary-search nodes will be created. You expect the root node of five BYTE4 keys with labels 0, 1, 2, 3 and 2^28 to be a binary-search node and the FST to take 34 bytes, as it does with -1 or the default. Instead (int) (sizeForBinarySearch * factor) saturates to Integer.MIN_VALUE, the int subtraction for expansionCost wraps to a negative value, the node is written with direct addressing and the FST takes 33,554,447 bytes, almost all of them presence bits for the 2^28 label range; every key is still found.",
   "impact_class": "minor",
   "introduced_commit": "068b6babac38 on main: LUCENE-8920 'Reduce the memory used by direct addressing of arcs' (apache/lucene-solr#980 by bruno-roustant, merged 2019-11-13; issue #9963), which added Builder#setDirectAddressingMaxOversizingFactor(float) with no range check, its javadoc sentence 'Setting this factor to a negative value (e.g. -1) effectively disables direct addressing, only binary search nodes will be created.' and the int arithmetic 'int allowedOversize = (int) (sizeForBinarySearch * factor); int expansionCost = sizeForDirectAddressing - allowedOversize; if (expansionCost <= 0 || ...) return true;' in FST.shouldExpandNodeWithDirectAddressing; branch_8x 5dd9c4c04bca (same change, 2019-11-14) -> 8.4.0. Later commits changed only the form: 1812b367aba (LUCENE-9089, Builder renamed FSTCompiler.Builder), 2d6ad2fee6d (LUCENE-9570, reformatting) and 04f38dd2885 (#12646, method moved from FST to FSTCompiler) [read] [exec].",
   "introduced_date": "2019-11-13 (author date of 068b6babac3; the branch_8x commit 5dd9c4c04bc was committed 2019-11-14)",
   "first_affected_version": "8.4.0 [exec]; 8.2.0 and 8.3.1 have no oversizing factor [exec]; 9.0.0 on the 9.x line [exec]",
   "affected_versions": "Every release from 8.4.0 to 10.6.0 (55 releases, released 10.6.0 = 4ae946e5a9b included) and main 5adff78bb168 (12.0.0-SNAPSHOT) [exec]. Not affected: 8.2.0 and 8.3.1 (API absent) [exec]. Not fixed upstream: upstream main 1c2072f02843 (2026-11-02) has the same code; the newest commit to FSTCompiler.java is 8cd74fed97b (#15133, author date 2026-09-29, unrelated) [read]. Not new in 10.6. All runs with JDK 25.0.3 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1204.html",
   "repro": "repro/LFV-1204/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-482",
   "priority": "low",
   "priority_rank": 865,
   "novelty": "known",
   "withheld": false,
   "area": "facet / taxonomy NRT reopen (DirectoryTaxonomyWriter.replaceTaxonomy and deleteAll epoch vs DirectoryTaxonomyReader.doOpenIfChanged)",
   "title": "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)",
   "summary": "You keep a near-real-time taxonomy reader open on a DirectoryTaxonomyWriter and refresh it with openIfChanged while the writer swaps in a rebuilt taxonomy with replaceTaxonomy, for example [a, b] replaced by [b, a]. You expect the refreshed reader to show either the old taxonomy or the new one, each with its own ordinals and labels, as the reader/writer concurrency contract and the reader's own 'was the taxonomy recreated?' check intend. Instead, a refresh that lands after the new content is visible but before replaceTaxonomy increments its epoch is treated as a plain append and reuses the replaced taxonomy's caches and parent arrays: it answers getOrdinal(a)=1 and getPath(1)=a, facet counts over the new index (three b documents, one a) come out labelled 'a (3), b (1)' instead of 'b (3), a (1)', and every later openIfChanged returns null, so the wrong reader stays current until the taxonomy changes again (with a smaller replacement the refresh throws ArrayIndexOutOfBoundsException instead).",
   "impact_class": "silent wrong results",
   "introduced_commit": "8b5e57faee943dbf9f4b1123cda6dc3f3d513860 (trunk, LUCENE-3441 'facets NRT support', by shaie, SVN r1412149), released through the branch_4x backport b99587d961dd0bcbed3a216db339a378467cd348 (same title, same day); JIRA LUCENE-3441 is now GitHub issue #4515; no pull request. It added the NRT constructor DirectoryTaxonomyReader(DirectoryTaxonomyWriter), TaxonomyReader.openIfChanged and the NRT 'recreated' check taxoEpoch != taxoWriter.getTaxonomyEpoch(), an unsynchronized read of a marker that replaceTaxonomy already updated last (createTime from LUCENE-4108, 4.0.0; renamed to indexEpoch by LUCENE-4532, 4.1.0); before it only commit(), synchronized like replaceTaxonomy, read that marker [read]. Release bracketing [exec]: 4.0.0 lacks the API (compile error), 4.1.0 fails. Not bisected on trunk snapshots between 8b5e57faee9 and LUCENE-4633 (ee4ad727375), where the repro's pause point does not exist although the race window does",
   "introduced_date": "2012-11-21",
   "first_affected_version": "4.1.0 [exec]; 4.0.0 and older are not affected because the NRT taxonomy reader API did not exist (compile error [exec])",
   "affected_versions": "every release from 4.1.0 through 10.6.0 (the latest 10.x; 10.6.0 by reading), including 9.12.3 (latest 9.x) and 8.11.4 (latest 8.x), plus main ea57360912ed; never fixed. Executed failing, both symptoms: 4.1.0, 4.6.1, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.2, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea; also -da on 9.12.3, 10.5.2 and main) [exec]; the other releases by code reading [read]. The end-to-end facet-label symptom (FastTaxonomyFacetCounts.getTopChildren) was executed on main and 10.5.2; on 9.12.3 getTopChildren labels are correct because its getBulkPath does not use the cache lookup, while getOrdinal/getPath/parents are still wrong [exec]. The deleteAll path (ReindexingEnrichedDirectoryTaxonomyWriter.reindexWithNewOrdinalData, 9.10.0 and later) is by reading and TLA+ only [read]. Upstream main a9779ef3c193 (2026-10-26), branch_10x and branch_10_6 do not change the epoch/reopen logic [read]. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/4859",
    "https://issues.apache.org/jira/browse/LUCENE-3786",
    "https://github.com/apache/lucene/issues/4515",
    "https://issues.apache.org/jira/browse/LUCENE-3441",
    "https://github.com/apache/lucene/issues/11518",
    "https://github.com/apache/lucene/issues/762"
   ],
   "doc": "",
   "repro": "repro/LFV-482/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-012",
   "priority": "low",
   "priority_rank": 866,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter NRT",
   "title": "An orphaned NRT reader can report isCurrent() true for different index content after a new writer session",
   "summary": "You keep an NRT reader after its writer is rolled back or closed, then open a new writer on the same directory and change the index. You expect reader.isCurrent() to return false. Instead SegmentInfos.version restarts in each writer session and the closed-writer branch of isCurrent compares only versions, so the stale reader reports true for different content.",
   "impact_class": "silent wrong results",
   "introduced_commit": "LUCENE-2805 (6c9052d2311 on trunk, 0196fb48869 on branch_3x) [exec]",
   "introduced_date": "2010-12-07",
   "first_affected_version": "3.1.0 [exec]",
   "affected_versions": "3.1.0 to 10.5.2 and main (16 releases run, all reproduce; 2.9.4 and 3.0.3 do not) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-012.html",
   "repro": "repro/LFV-012/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-591",
   "priority": "low",
   "priority_rank": 867,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter construction from a reader's IndexCommit (SegmentInfos.version; DirectoryReader.isCurrent and openIfChanged)",
   "title": "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",
   "summary": "You keep an older commit (for example with NoDeletionPolicy or a snapshot), open a reader on it, and later go back to it by opening a new IndexWriter with setIndexCommit(thatReader.getIndexCommit()) and committing, while another reader is still open on a newer commit. You expect that reader to notice the new commits (isCurrent() false, openIfChanged returning the latest commit), as it does when the same commit is taken from DirectoryReader.listCommits. Instead the writer restarts SegmentInfos.version from the old reader instead of from the newest commit, so one of its commits can get exactly the newer commit's version (segments_3 holding [a, b, c] and segments_5 holding [a] are both version 10), and the stale reader reports isCurrent()=true, openIfChanged returns null and SearcherLifetimeManager.record throws IllegalArgumentException.",
   "impact_class": "silent wrong results",
   "introduced_commit": "2d0ac9bb7f2276d5a277efda29e676096ea034b4 (trunk, svn r1687992, first released in 6.0.0) and its branch_5x backport 7ab3ca7d608 (svn r1687993, first released in 5.3.0): LUCENE-6524 'Create an IndexWriter from an already opened NRT or non-NRT reader' (GitHub #7582, by mikemccand; pre-GitHub, reviewed as patch attachments, no PR). It added the 'else if (reader != null)' branch of the IndexWriter constructor and made StandardDirectoryReader.ReaderCommit carry its reader, so the existing call setIndexCommit(reader.getIndexCommit()) left the commit-point branch, which keeps the newest commit's version, for a branch that takes the version from the reader [read]. The issue's 16 comments never mention the version, write-once or isCurrent.",
   "introduced_date": "2015-06-28",
   "first_affected_version": "5.3.0 [exec]; 5.2.1, the last release before, is not affected [exec]",
   "affected_versions": "every release from 5.3.0 through 10.6.0 (10.6.0 executed with the one-test repro, -ea and -da, 2026-10-31), including 9.12.3 (the latest 9.x), and main a9779ef3c193; the previous hunt main ea57360912ed too (the unit's k=4 enumeration ran on its jars, and none of the 7 commits in between touches IndexWriter, StandardDirectoryReader, SegmentInfos or DirectoryReader); never fixed. [exec] 5.3.0, 5.5.5, 6.0.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main are affected (5.3.0, 10.5.2 and main run with -ea and -da), the listCommits control is clean everywhere; 5.0.0 and 5.2.1 are not affected. [exec] 9.12.3, 10.5.2 and main with -ea and -da: 4 run / 3 fail, control passes; the independent reproduction's own JUnit fails the same way on main, 10.5.2 and 9.12.3, the cross-model review and the intended-behaviour check re-ran on main and 10.5.2. [read] 8.8.2-8.11.3 are counted by inference only (released from the lucene-solr branch_8x line, not in the history clone; 8.8.1 contains the commit and 8.11.4 was run); branch_10_6 and branch_10x have a byte-identical reader branch; upstream main a95c754ee003 does not change it.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-591.html",
   "repro": "repro/LFV-591/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-017",
   "priority": "low",
   "priority_rank": 868,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter NRT",
   "title": "Data race on SegmentInfos.version between newSegmentName and checkpoint",
   "summary": "Several indexing threads allocate new segment names while the writer checkpoints. You expect every SegmentInfos.version increment to be kept, so the version check of a reader is reliable. Instead newSegmentName increments the version under synchronized(segmentInfos) while other increments hold the IndexWriter monitor, so an increment can be lost or go backwards and a stale reader can look current.",
   "impact_class": "silent wrong results",
   "introduced_commit": "6c9052d2311c (LUCENE-2805, #3879) added segmentInfos.changed() inside newSegmentName, which created the two-monitor version++ [read]",
   "introduced_date": "2010-12-07",
   "first_affected_version": "4.0.0 [read]",
   "affected_versions": "4.0.0+ [read]; main [exec] (forced schedule; 124 lost increments in a 10-minute unforced NRT workload); upstream #8550 open since 2016-10-17",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/8550",
    "https://issues.apache.org/jira/browse/LUCENE-7499"
   ],
   "doc": "",
   "repro": "repro/LFV-017/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1127",
   "priority": "low",
   "priority_rank": 869,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter two-phase commit (sequence numbers)",
   "title": "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",
   "summary": "The main thread adds a document and thread A calls IndexWriter.prepareCommit(); while A is still in the merge step that prepareCommit() runs after publishing its pending commit, the main thread calls commit() (which finishes A's commit and returns 3), adds another document (sequence number 4) and calls prepareCommit() again. You expect A's prepareCommit() to return 3, as its javadoc promises ('All sequence numbers <= this value will be reflected in the commit, and all others will not') and as commit() returned for the same commit. Instead it returns 6, the next commit's number, because prepareCommit() re-reads the shared pendingSeqNo field after its maybeMerge instead of returning its own result; the committed index itself is correct.",
   "impact_class": "silent wrong results",
   "introduced_commit": "ea3f8363319955c589eb3a7df59a031621852d3e (branch_6x, first released in 6.4.0) and 2b073a2f296289617bea8256d7efec06049df739 (master, first released in 7.0.0), both 'LUCENE-7570: don't run merges while holding the commitLock to prevent deadlock when merges are stalled and a tragic merge exception strikes' (mikemccand; LUCENE-7570 = apache/lucene#8621, a JIRA patch, no pull request): it moved the post-flush maybeMerge(FULL_FLUSH) out of prepareCommitInternal's commitLock into prepareCommit, between 'pendingSeqNo = prepareCommitInternal()' and 'return pendingSeqNo' [exec]. The re-read line itself dates from the sequence-numbers patch (LUCENE-7302 = #8356, 058970e72bd on master / 88dd1aad774 on branch_6x, 2016-05-24, first in 6.2.0), but there nothing ran between the store and the re-read.",
   "introduced_date": "2016-12-09 (author and commit date of 2b073a2f296 and ea3f8363319)",
   "first_affected_version": "6.4.0 [exec]",
   "affected_versions": "Every release from 6.4.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT). Executed and reproduced with the history probe: 6.4.0 (-ea, -da), 6.6.6, 7.0.0, 7.7.3, 8.5.2, 8.6.0, 8.11.4, 9.12.3, 10.6.0 (-ea, -da) and main (-ea, -da), plus the two LUCENE-7570 commit builds [exec]; the one-test repro fails on main (-ea, -da), 10.6.0, 10.5.2 and 9.12.3 [exec]; the releases in between contain the change [read]. Latent, not reproduced: 6.2.0 and 6.3.0 (the re-read directly follows the store there and the merge runs under commitLock, so the test's window is closed) [exec]. Not affected: 6.1.0 and older (API absent: prepareCommit, commit and addDocument return void) [exec]. Not new in 10.6. Not fixed upstream: upstream main 1c2072f0284 (2026-11-02) still re-reads the field [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1127.html",
   "repro": "repro/LFV-1127/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-184",
   "priority": "low",
   "priority_rank": 870,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter addIndexes(CodecReader...) vs rollback (AddIndexesMergeSource, ConcurrentMergeScheduler)",
   "title": "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",
   "summary": "You call addIndexes(CodecReader...) on one thread while another thread calls rollback() on the same writer (or the writer closes itself after a tragic error). You expect that once rollback() has returned the writer is closed and starts no more merges, so the addIndexes call just fails; Lucene's own TestAddIndexes rollback tests assert that no merge thread is left. Instead, if rollback() lands while addIndexes is asking the merge policy for its merges, the merge is registered after rollback has already aborted all merges, and ConcurrentMergeScheduler starts a new merge thread after rollback() and the scheduler's close() have returned; that thread throws an uncaught MergeException (AlreadyClosedException 'Lock instance already released' on 10.3.0 and later, 'this IndexWriter is closed' on 9.4.0-10.2.2) and addIndexes throws AlreadyClosedException.",
   "impact_class": "minor",
   "introduced_commit": "698f40ad51af on main (branch_9x backport 5dd8e9bdc5ae, PR #1051), PR #633 'LUCENE-10216: Use MergeScheduler and MergePolicy to run addIndexes(CodecReader[]) merges.' (vigyasharma, merged by mikemccand): it replaced the atomic synchronized { ensureOpen(); assert merges.areEnabled(); runningAddIndexesMerges.add(merger); } block with an up-front ensureOpen() + merges.areEnabled() check under the IndexWriter lock, an unlocked MergePolicy.findMerges(CodecReader...) call and AddIndexesMergeSource.registerMerge, which does not check again [read]",
   "introduced_date": "2022-07-06 on main (698f40ad51af); 2022-08-01 on branch_9x (5dd8e9bdc5ae)",
   "first_affected_version": "9.4.0 [exec]; 9.3.0 is the last unaffected release [exec]",
   "affected_versions": "Every release from 9.4.0 to 10.5.2 and main [exec], and 10.6.0 (10.6.0 by reading): the version-neutral sweep probe (no custom merge policy; it pauses inside a FilterCodecReader at each reader call) fails on all 29 releases 9.4.0, 9.4.1, 9.4.2, 9.5.0-9.8.0, 9.9.0-9.9.2, 9.10.0, 9.11.0, 9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2 under -ea, and on 9.4.0 and main ea57360912ed under -da too; the canonical repro fails on 9.4.0, 9.12.3, 10.0.0, 10.2.2, 10.3.0, 10.5.2 and main under -ea, and on 9.4.0, 10.5.2 and main under -da. Not affected: 9.2.0 and 9.3.0 [exec]; releases before 9.1 were not run. Symptom by version [exec]: on 9.4.0-10.2.2 the late merge thread fails at once in flush -> ensureOpen ('this IndexWriter is closed') and writes nothing; from 10.3.0 (#15025 moved that flush to the caller) it starts merging and fails at its first write ('Lock instance already released'). Not fixed upstream: main ea57360912ed, branch_10x 1309534296e3 and branch_10_6 2763db11b0a7 still have registerMerge without a check [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15863",
    "https://github.com/apache/lucene/issues/10349",
    "https://issues.apache.org/jira/browse/LUCENE-9309",
    "https://github.com/apache/lucene/issues/633",
    "https://github.com/apache/lucene/issues/10325",
    "https://issues.apache.org/jira/browse/LUCENE-9285"
   ],
   "doc": "",
   "repro": "repro/LFV-184/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-188",
   "priority": "low",
   "priority_rank": 871,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter forceMergeDeletes MergeObserver (MergePolicy.MergeObserver, MergeSpecification.await)",
   "title": "MergeObserver.await() and await(timeout) return true after a failed or aborted merge, although their javadoc says they return false on error",
   "summary": "You call IndexWriter.forceMergeDeletes(false), which starts the merges in the background and returns a MergeObserver, and then call observer.await() to learn whether they worked; its javadoc says it returns true if all merges completed successfully and false on error. Instead it returns true even when the merge failed with an IOException or was aborted by rollback() or deleteAll(), because every merge's completion future is completed normally with a success flag that await() never reads. A caller that trusts the result believes the deleted documents were merged away although the merge never finished.",
   "impact_class": "minor",
   "introduced_commit": "6862ef978845 (branch_10x backport, released in 10.4.0) and c85c69f19082 (main, unreleased 11.0), the same patch: #15378 'Return MergeObserver from IndexWriter.forceMergeDeletes() (#14515)' by salvatorecampagna, merged 2025-11-02 (fixes #14515) [read]; the patch put the public 'false on error' promise on top of the older, completion-only package-private MergeSpecification.await, which it did not change: await(timeout) from LUCENE-8962 (#1585, 59efe22ac29, 2020), await() from LUCENE-10216 (#633, 698f40ad51a, 2022)",
   "introduced_date": "2025-11-02 (#15378, merged 2025-11-02T23:36:21Z on main and branch_10x)",
   "first_affected_version": "10.4.0 [exec] (first release with MergePolicy.MergeObserver); 10.3.2 and every earlier release, including the whole 9.x line, do not have the API (forceMergeDeletes returns void; the repro does not compile on 10.3.2 and 9.12.3 [exec])",
   "affected_versions": "10.4.0, 10.5.0, 10.5.1, 10.5.2, 10.6.0 (executed with the one-test repro, -ea and -da, 2026-10-31) and main ea57360912ed: every release that contains MergeObserver (10.5.2 was the latest on Maven Central when checked on 2026-10-26). [exec] the finder's JUnit fails on all four releases with -ea, and on 10.5.2 and main also with -da; the independent reproduction's own repro fails on main (-ea, -da), 10.5.2 (-ea, -da) and 10.4.0; the intended-behaviour check's fails on main (-ea, -da), 10.4.0 and 10.5.2; the finder's repro also fails with open PR #16889 applied (heads e304ea8cbd6, 2026-10-26, and 6c281d1cb52, 2026-11-02 on main e1faeba08bd with -ea and -da). MergeObserver, MergeSpecification.await()/await(timeout) and OneMerge.close are source-identical to main at all four tags. Not affected: 10.3.2 and earlier, 9.x (API absent) [exec]. The completion-only package-private MergeSpecification.await already returns true for a failed merge on 9.12.3, 10.3.2, 10.4.0, 10.5.2 and main [exec], but there it made no 'false on error' promise and had no public caller. branch_10x and branch_10_6 are not in the local history clone; prior-report record found no commit touching MergePolicy.java on them after the #15378 backport [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-188.html",
   "repro": "repro/LFV-188/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-312",
   "priority": "low",
   "priority_rank": 872,
   "novelty": "known",
   "withheld": false,
   "area": "search / ReferenceManager refresh listeners (ControlledRealTimeReopenThread, LiveFieldValues)",
   "title": "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",
   "summary": "You add, delete or update a document and wait for it with ControlledRealTimeReopenThread.waitForGeneration (or record its value in LiveFieldValues), and the next refresh of the SearcherManager throws, for example because a warm-up query in the SearcherFactory fails or an I/O error hits while the new segment is opened. You expect waitForGeneration to keep waiting or time out, and LiveFieldValues to keep the value, because the old searcher is still current and does not contain the change. Instead ReferenceManager.doMaybeRefresh calls every listener's afterRefresh(false) from a finally block, the same call a refresh that found nothing to do makes, so ControlledRealTimeReopenThread advances its searching generation and wakes the waiters with true, and LiveFieldValues throws away its buffered values.",
   "impact_class": "silent wrong results",
   "introduced_commit": "1a11ce5fd4ffd5f087a872c404dbad9503cef207 (trunk, svn r1438721; branch_4x 6841b1c9ac88, svn r1438731, the commit the 4.2.0 release contains), 'LUCENE-4695: add LiveFieldValues, to get current (live/real-time) values for fields indexed after the last NRT reopen' by mikemccand (JIRA LUCENE-4695, now #5760; no pull request) [read]. It replaced the success-only 'if (refreshed) notifyRefreshListeners()' (LUCENE-4566, 4.1.0) with notifyRefreshListenersRefreshed(refreshed) inside the finally block and reworded the listener javadoc from 'Called after a successful refresh' to 'Called after the attempted refresh'; neither the commit, its CHANGES entry nor the JIRA discussion mentions refreshes that throw. The ControlledRealTimeReopenThread symptoms came later: LUCENE-4967 (7b90561178d5, branch_4x 79ee60d41bcc, 4.4.0) added HandleRefresh.afterRefresh, which sets searchingGen regardless of didRefresh (a failed refresh by the reopen thread), and LUCENE-9304 (18af6325ed98 on master, 47ed21324c41 on branch_8x, lucene-solr PR #1427, 8.6.0) moved the generation capture into beforeRefresh (a failed refresh started by the application)",
   "introduced_date": "2013-01-25 (LUCENE-4695; the ControlledRealTimeReopenThread forms followed on 2013-05-02, LUCENE-4967, and 2020-04-14, LUCENE-9304)",
   "first_affected_version": "4.2.0 [exec] (LiveFieldValues forgets the buffered value, and a probe listener receives afterRefresh(false) for a refresh that threw; 4.1.0 is unaffected [exec]); the ControlledRealTimeReopenThread reopen-thread form from 4.4.0 [exec] (4.3.1 has no such class, and its predecessor NRTManager passes [exec]); the application-refresh form from 8.6.0 [exec] (8.5.2 passes that test)",
   "affected_versions": "every release from 4.2.0 through 10.5.2 and main ea57360912ed. [exec] fail: 4.2.0 and 4.3.1 (LiveFieldValues); 4.4.0 and 8.5.2 (LiveFieldValues and the reopen-thread form; the application-refresh test passes there); 8.6.0, 8.11.4, 9.0.0, 9.12.3 (-ea and -da), 10.5.2 (-ea and -da) and main (-ea and -da; 60 of 60 over 20 seeds) with all three forms. [exec] pass: 4.1.0, and NRTManager on 4.1.0, 4.2.0 and 4.3.1. [read] all 119 release tags from 4.2.0 on in the history clone notify from the finally block and clear LiveFieldValues unconditionally; tags 4.4.0-8.5.2 capture the generation in run(), 8.6.0-10.5.2 in beforeRefresh. In 4.4.0-8.5.2 a failed application refresh can still advance the generation through a race (reasoned, not executed). Not checked: 10.6.0 (released 2026-10-29) and its branch (main still fails)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15985",
    "https://github.com/apache/lucene/issues/16152",
    "https://github.com/apache/lucene/issues/16911",
    "https://github.com/apache/lucene/issues/15831",
    "https://issues.apache.org/jira/browse/LUCENE-4566",
    "https://github.com/apache/lucene/issues/5632"
   ],
   "doc": "",
   "repro": "repro/LFV-312/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1024",
   "priority": "low",
   "priority_rank": 873,
   "novelty": "new",
   "withheld": false,
   "area": "replicator / NRT segment replication (PrimaryNode.flushAndRefresh, setCurrentInfos: NRT point publication)",
   "title": "NRT PrimaryNode: one I/O error during flushAndRefresh leaves the new point unpublished to replicas, and the retry reports no changes",
   "summary": "You run Lucene's NRT segment replication, index a document and call PrimaryNode.flushAndRefresh; it throws because opening one of the new files hits a transient I/O error, and once the error is gone you call flushAndRefresh again. You expect the retry to publish the new point to replicas, or the failed call to have left the previous point fully in place. Instead the failed call had already switched the primary's current point and released the previous point's files, but not the copy state that replicas are given, so the retry returns false ('no changes'), getCopyStateVersion() stays behind getCurrentSearchingVersion(), and replicas are not offered the new point until the index changes again.",
   "impact_class": "silent wrong results",
   "introduced_commit": "1ae7291429bad742715344f86cfa5200229b3698 (mikemccand, 2016-01-24, 'current patch', the first commit of the LUCENE-5438 feature branch jira/lucene-5438-nrt-replication; LUCENE-5438 'add near-real-time replication', migrated as #6501, developed as JIRA patches with no GitHub PR): it added the whole org.apache.lucene.replicator.nrt package, with PrimaryNode.setCurrentInfos already in the order incRefDeleter(new), curInfos = new, decRefDeleter(old), then serialize and readLocalFileMetaData per file, then copyState = new CopyState(...) [read]. It reached master with the merge 12b8721a44d (mikemccand, 2016-02-11). The bug has been there since the class was written; there is no later regression commit.",
   "introduced_date": "2016-01-24 (1ae7291429b, feature branch); 2016-02-11 (merge 12b8721a44d into master)",
   "first_affected_version": "6.0.0 [exec] (the first release with the org.apache.lucene.replicator.nrt package; the history probe fails with -ea and -da: the retry returns false, searching version 4, copy state version 3, fault inside PrimaryNode.setCurrentInfos -> Node.readLocalFileMetaData); 5.5.5 and earlier: not applicable, the API does not exist (the probe does not compile on 5.5.5) [exec]",
   "affected_versions": "every release from 6.0.0 through 10.6.0, and main 645d4fe14a20 (also ea57360912ed). [exec] 10.6.0: the one-test repro fails on the 10.6.0 release jars (lucene-replicator 10.6.0 from Maven Central, SHA-1 checked) with -ea and -da, with the same message as on main (2026-10-31 re-verification and version-history runs). [exec] follow-up history probe (a main() port of the same steps with the default merge policy and codec): 6.0.0, 6.6.6, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main with -ea and -da; 7.0.0, 8.0.0, 8.8.2, 8.9.0, 8.10.0, 8.10.1, 8.11.0-8.11.3, 9.0.0 and 10.0.0 with -ea; the candidate JUnit unchanged on 9.1.0 and 10.5.2 (-ea and -da) and 10.0.0 (-ea); every run gives the same numbers, with the fault inside PrimaryNode.setCurrentInfos -> Node.readLocalFileMetaData; the independent reproduction's one-test repro also fails on 10.5.2 and 9.12.3 with -ea and -da. [read] the same statement order in all 83 release tags of the history clone that contain 12b8721a44d; branch_10x 657014b3c579 and 10.6.0 (4ae946e5a9b) have a PrimaryNode.java byte-identical to main. Not fixed upstream: the newest commit to PrimaryNode.java is dbaf97f5dcc (2025-07-18).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1024.html",
   "repro": "repro/LFV-1024/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-260",
   "priority": "low",
   "priority_rank": 874,
   "novelty": "new",
   "withheld": false,
   "area": "replicator / NRT segment replication (ReplicaNode.commit commit user data, PrimaryNode.getLastCommitVersion)",
   "title": "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",
   "summary": "You run Lucene's NRT segment replication and call commit() on a replica while the primary keeps publishing NRT points, and during the commit's fsync the replica installs a newer point (version 5, documents [d1, d2]). You expect the commit's VERSION_KEY to name the version whose content it holds (version 3, [d1]), or at worst an older one, because the module uses that value as the place to resume replaying operations and PrimaryNode.commit accepts only a lagging value ('replaying more ops than necessary'). Instead commit() writes the SegmentInfos it captured before the fsync (version 3) but reads VERSION_KEY from the searcher that is current after it (5), so a primary started on that commit reports getLastCommitVersion()=5 while it holds only d1, and a replay from version 5 skips d2.",
   "impact_class": "silent wrong results",
   "introduced_commit": "1ae7291429bad742715344f86cfa5200229b3698 ('current patch' by mikemccand, 2016-01-24; the first commit of the LUCENE-5438 feature branch and the first version of ReplicaNode.java, whose commit() already captured infos under synchronized (this), ran dir.sync(indexFiles) holding only commitLock and then stored VERSION_KEY = getCurrentSearchingVersion()), merged into master by 12b8721a44db (2016-02-11; named by the author as the LUCENE-5438 commit); LUCENE-5438 'add near-real-time replication' (now #6501), no pull request, no CHANGES entry [read]",
   "introduced_date": "2016-01-24 (feature-branch commit); 2016-02-11 (merged into master)",
   "first_affected_version": "6.0.0 [exec] (release commit 48c80f91b8e5, dated 2016-04-01; the first release with org.apache.lucene.replicator.nrt): the 6.0 port of the repro fails under -ea and -da and passes when only the VERSION_KEY line is changed to infos.getVersion(); on 6.0.0 and 6.1.0 the bug is reachable only through a ReplicaNode subclass that survives a separate constructor-time close() bug (success = true missing, fixed in 6.2.0 by de6485ea6a3), as the module's own SimpleReplicaNode does by accident, which is not part of this bug; 5.5.5 has no nrt package (the test does not compile) [exec]",
   "affected_versions": "every release from 6.0.0 through 10.6.0 and main ea57360912ed. [exec] 10.6.0: the one-test repro fails on the 10.6.0 release jars with -ea and -da (2026-10-31, also in the fact check). [exec] 6.0.0 (-ea and -da), 6.2.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) all fail with the same assertion and numbers (VERSION_KEY=5 and getLastCommitVersion()=5, committed SegmentInfos version 3 with [d1]); the independent reproduction's independent test also fails on 10.5.2 and 9.12.3 (-ea and -da). [read] all 83 release tags from 6.0.0 to 10.5.2 in the history clone contain the introducing commit (the clone has no 8.x tags after 8.8.1; 8.11.4 executed), and commit() changed since only by the LUCENE-9570 reformat (2cbf261032d) and #378 (7d5df2d6fee, a null-check removal around updateGeneration). Not fixed on main (ReplicaNode.java:369) or branch_10x (line 375) [read]; no open PR changes the line. Not affected: 5.x (API absent) [exec]. All runs on aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-260.html",
   "repro": "repro/LFV-260/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-270",
   "priority": "low",
   "priority_rank": 875,
   "novelty": "new",
   "withheld": false,
   "area": "replicator / NRT segment replication (ReplicaNode.newNRTPoint, maybeNewPrimary, launchPreCopyMerge: primaryGen fencing)",
   "title": "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",
   "summary": "You run Lucene's NRT segment replication and fail over cleanly: the old primary (generation 1) is closed, then replica A is promoted to primary (generation 2), and replica B follows A and pre-copies A's merged segment. A last notification from the old primary, delayed in transit, then reaches B; you expect B to ignore it, as it already ignores out-of-order older NRT versions, because the primary generation only ever grows. Instead ReplicaNode.maybeNewPrimary treats the older generation as a primary change and deletes A's pre-copied merged files before its only check (an assert), so B's cut-over to A's merged point fails with '_3.si cannot be read - it may be missing or corrupt' or B copies the merged segment again, and with assertions off B also sets lastPrimaryGen back to 1.",
   "impact_class": "crash",
   "introduced_commit": "9afa560054aad72b8cc623b130745bc8778d1d5c (mikemccand, 2016-02-08, 'fix some nocommits; fix one stress test failure', on the LUCENE-5438 feature branch jira/lucene-5438-nrt-replication): it changed newNRTPoint(long version) to newNRTPoint(long newPrimaryGen, long version), moved the maybeNewPrimary call to the top of the method, before the same-version and older-version skips, and made maybeNewPrimary delete every pendingMergeFiles entry with deleteIfNoRef before its only generation check; that assert-only check ('assert newPrimaryGen > lastPrimaryGen') is older, from 1ae7291429bad742715344f86cfa5200229b3698 ('current patch', 2016-01-24, the first commit of ReplicaNode.java); both reached master in the merge 12b8721a44dbd1fbc7878fa37186c16cf6045401 (2016-02-11), which the author named as the LUCENE-5438 commit ('add near-real-time replication', now #6501); no pull request, no CHANGES entry [read]",
   "introduced_date": "2016-02-08 (9afa560054aa, feature branch); 2016-02-11 (merge 12b8721a44db into master); the assert-only generation check dates from 2016-01-24 (1ae7291429ba)",
   "first_affected_version": "6.0.0 [exec] (released 2016-04-08, the first release with the org.apache.lucene.replicator.nrt package): the probe fails 2 of 3 under -ea and -da with the control passing, and passes 3 of 3 with the candidate fix's two ReplicaNode hunks shadowed; the 6.0.0 run needs a test-side close() guard because of a separate 6.0.0-6.1.0 constructor defect (no 'success = true'), which the module's SimpleReplicaNode test node avoids and which is not part of this bug; 6.2.0 is the first release that reproduces with no workaround [exec]; 5.5.0 and 5.5.5 have no nrt package (the repro does not compile) [exec]",
   "affected_versions": "every release from 6.0.0 through 10.6.0, and main ea57360912ed. [exec] 10.6.0 and main 645d4fe14a20 with -ea and -da: the one-test repro fails, the pre-copied merged files deleted (version-history runs, 2026-10-31). [exec] -ea and -da: 6.0.0 (with the close() guard), 6.2.0, 6.6.6, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main; -ea only: 9.0.0 and 10.0.0; the same 2 of 3 failure and the same per-scenario effects in every run (follow-up history sweep, plus the tie-breaker's runs on main, 10.5.2 and 9.12.3). [read] the same maybeNewPrimary body, the call before the version skips in newNRTPoint, the call in launchPreCopyMerge and a deleteIfNoRef that deletes files with no ref entry in every release tag 6.0.0-8.8.1 and 9.0.0-10.5.2, branch_8_8, branch_10x, branch_10_6 and main (8.8.2-8.11.3 are not in the local clones; bracketed by 8.8.1 [read] and 8.11.4 [exec]). Not fixed upstream (apache/lucene main and branch_10x re-read 2026-10-26; no open PR changes this logic). Not affected: 5.x (API absent) [exec]. All runs on aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-270.html",
   "repro": "repro/LFV-270/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-245",
   "priority": "low",
   "priority_rank": 876,
   "novelty": "new",
   "withheld": false,
   "area": "replicator / NRT segment replication (ReplicaNode.launchPreCopyMerge merge pre-copy, ReplicaNode.newNRTPoint)",
   "title": "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",
   "summary": "You run Lucene's NRT segment replication with merge pre-copy: the primary asks replica B to pre-copy a merged segment, and just as B has copied the bytes and is renaming the files into place, another node is promoted to primary and B receives its first NRT point (primaryGen 2). You expect B either to install the merged files and then discard them in the switch, or to notice the switch and cancel the pre-copy, because newNRTPoint says it discards the old primary's pre-copied merged segments and the callback itself checks whether the primary changed. Instead the callback's synchronized (this) locks the anonymous CopyJob.OnceDone, not the ReplicaNode, so the switch runs in the middle of it and B follows primaryGen 2 with the old primary's merged files [_2.cfe, _2.cfs, _2.si] still in pendingMergeFiles and on disk (with -ea, the new primary's later pre-copy of a same-named merged segment then fails with 'file \"_2.si\" is already being warmed!').",
   "impact_class": "minor",
   "introduced_commit": "1ae7291429bad742715344f86cfa5200229b3698 ('current patch' by mikemccand, 2016-01-24, on the feature branch jira/lucene-5438-nrt-replication; the commit that added the whole org.apache.lucene.replicator.nrt package, including launchPreCopyMerge and its anonymous CopyJob.OnceDone whose run() does 'synchronized(this)'), merged into the main line by 12b8721a44db (2016-02-11; named as the LUCENE-5438 commit in the author's JIRA comment of that day); LUCENE-5438 'add near-real-time replication' (now #6501), no pull request, no CHANGES entry [read]; 9afa560054aa (2016-02-08, same branch) moved maybeNewPrimary to the top of newNRTPoint with the 'defensively discard' comment and made it delete pendingMergeFiles, the contract the repro checks; 2cbf261032dc (2021-01-05, LUCENE-9570 reformat) is the only later change to launchPreCopyMerge, whitespace only",
   "introduced_date": "2016-01-24 (branch commit); 2016-02-11 (merged to the main line)",
   "first_affected_version": "6.0.0 [exec] (release tag commit 2016-04-01; the first release with the org.apache.lucene.replicator.nrt package): the 6.0 port of the repro fails, and the same run passes when only that one line is changed to synchronized (ReplicaNode.this); the port needs a close() guard because of a separate 6.0.0-6.1.0 constructor bug (success = true missing, fixed in 6.2.0), which is not part of this bug; 5.5.0 and 5.5.5 have no nrt package (the repro does not compile, 103 errors) [exec]",
   "affected_versions": "every release from 6.0.0 through 10.6.0 and main ea57360912ed. [exec] fail with the same end state (old-primary merged files in pendingMergeFiles and on disk after the switch to primaryGen 2): 6.0.0 (-ea and -da), 6.6.6, 7.7.3 and 8.11.4 (-ea), 9.12.3 (-ea and -da), 10.5.2 (-ea and -da) and main (-ea and -da); 6.0.0 passes with the one-line fix (-ea and -da); the independent reproduction's independent test also fails on 10.5.2 and 9.12.3 (-ea and -da) and the intended-behaviour check's rerun on 10.5.2 and 9.12.3 (-da). [read] all 83 release tags in the history clone from 6.0.0 on (6.0.0..8.8.1 and 9.0.0..10.5.2) contain the merge commit, and at each of them the merge pre-copy OnceDone is an anonymous class whose run() locks 'this' (scripted check, 83 of 83); 8.8.2..8.11.4 are on a branch not in the clone (8.11.4 executed). Not fixed on main (upstream main re-checked 2026-10-26: line 761 still reads 'synchronized (this) {'); 10.6.0 (released 2026-10-29) fails too [exec]. Not affected: 5.x (API absent) [exec]. All runs on aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-245.html",
   "repro": "repro/LFV-245/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1066",
   "priority": "low",
   "priority_rank": 877,
   "novelty": "new",
   "withheld": false,
   "area": "core / search: SearcherLifetimeManager (keeping old searchers for follow-up requests such as paging)",
   "title": "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",
   "summary": "You use SearcherManager with SearcherLifetimeManager as the javadoc shows: request A acquires searcher S1, the manager refreshes to S2, request B acquires and records S2, and then A records S1. You expect prune to pass the searchers newest to oldest, as its javadoc says, so PruneByAge never drops S2, the current searcher. Instead prune sorts them by the time each was first recorded, so S1 goes first with age 0 and S2 is aged from S1's late record: 250 ms later, request C records S2 and gets a token, prune(new PruneByAge(0.1)) drops S2 anyway, acquire(token) returns null, and the older S1 is kept.",
   "impact_class": "minor",
   "introduced_commit": "cbdaea3486e on trunk (LUCENE-3486 = apache/lucene#4560, author mikemccand, 2011-10-10T22:05:55Z) and its branch_3x backport 346799474a2 the same day, first released in 3.5.0 [read]. The age contract the order now breaks came with LUCENE-3639 (aee83bf7eef on trunk, 906894ad97a on branch_3x, 2011-12-18, first released in 3.6.0), which redefined ageSec as the time since the searcher was the current (live) searcher and kept the record-time sort, so there is no later regression",
   "introduced_date": "2011-10-10",
   "first_affected_version": "3.5.0 [exec]; the repro's exact scenario fails from 3.6.0 on [exec], after LUCENE-3639 made the age now-based; 3.4.0 and earlier are not affected [exec]",
   "affected_versions": "every release from 3.5.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 645d4fe14a20; never fixed (upstream main f815e679bf unchanged at the fix site, last commit to the file 54283150a81, author date 2026-06-14, a javadoc typo fix from a build-tooling commit, no behaviour change; checked 2026-11-01). [exec] the JUnit repro fails 1 of 1 on main with -ea and -da (10 of 10 with --iters 10 and -da), on 10.6.0 (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's own JUnit fails on main (-ea and -da), 10.6.0, 10.5.2 and 9.12.3; framework-free probes of the same current-searcher scenario fail on 9.0.0, 8.11.4, 7.7.3, 6.6.6, 5.5.5, 4.10.4, 4.0.0, 3.6.2 and 3.6.0, order probes fail on 9.0.0, 8.11.4, 8.0.0, 7.7.3, 6.6.6, 5.5.5, 4.10.4, 3.6.2 and 3.5.0, and 3.5.0 fails in its record-time-difference form. [read] the 10.6.0-to-main diff of SearcherLifetimeManager.java is javadoc markup and one typo. Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1066.html",
   "repro": "repro/LFV-1066/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1221",
   "priority": "low",
   "priority_rank": 878,
   "novelty": "new",
   "withheld": false,
   "area": "core / search: ReferenceManager (SearcherManager, ReaderManager and other subclasses)",
   "title": "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)",
   "summary": "You call maybeRefresh on a ReferenceManager (for example a SearcherManager), and releasing the old reference inside the swap throws an IOException, which decRef is documented to do; you expect maybeRefresh to throw it and the manager to stay usable, with acquire() returning the new current reference. Instead swapReference has already made the new reference current (ReferenceManager.java:56) before it releases the old one (:57), and doMaybeRefresh's cleanup finally, which exists for a new reference the swap never installed, releases it anyway (:174-178), so the manager drops its own count on its current reference and closes it. Every later acquire() then throws IllegalStateException 'The managed reference has already closed - this is likely a bug when the reference count is modified outside of the ReferenceManager', blaming the caller for a state the manager created itself.",
   "impact_class": "minor",
   "introduced_commit": "a234ffd21c9131f391646c5f3ced8964d6796a82 (branch_3x, svn r1177943, the code that shipped in 3.5.0; trunk twin d514a4ac75b5374a3c19193137e3bbc972f7bdd2, svn r1177940, ten minutes earlier, first in 4.0.0-alpha): LUCENE-3476 'SearcherManager misses to close IR if manager is closed during reopen' (issue #4550; svn era, no PR) added 'success = false; try { swapSearcher(newSearcher); success = true; } finally { if (!success) release(newSearcher); }' to SearcherManager.maybeReopen around a swap that already installed the new searcher before releasing the old one, for the case where close() ran during the reopen and the new searcher was never installed. The same day f02ae7fc9a5 / 52e8d40c2f2 merged the warm and swap try blocks and kept the shape; LUCENE-3761 ('Generalize SearcherManager', #4834) moved it unchanged into the new ReferenceManager (4e5ead2640a on branch_3x, first in 3.6.0; f4c6a4098ea on trunk, where git blame stops because the file was created there); LUCENE-4566 (f6b3aa4054b) renamed the flag to refreshed [read]",
   "introduced_date": "2011-10-01 (author date = commit date: 08:10:21Z trunk, 08:20:40Z branch_3x); moved into ReferenceManager 2012-02-14 (12:55:43Z branch_3x, 15:36:14Z trunk)",
   "first_affected_version": "3.5.0 [exec] (the first release with SearcherManager, stock class: maybeReopen throws, then acquire() spins forever; 3.4.0 has neither SearcherManager nor ReferenceManager [exec]); ReferenceManager, the repro's API, is affected from its first release 3.6.0 [exec]",
   "affected_versions": "Every release from 3.5.0 through 10.6.0 (4ae946e5a9b, released 2026-10-29) and main 5adff78bb168 (12.0.0-SNAPSHOT); never fixed, not a regression, not new in 10.6. Symptom after the failed refresh: 3.5.0 to 4.6.1 acquire() loops forever on the closed current reference; from 4.7.0 (LUCENE-5436, #6499) acquire() throws the IllegalStateException. [exec] 3.5.0 (stock SearcherManager form, -ea), 3.6.0 (-ea and -da), 4.6.1 (-ea), 4.7.0 (-ea) and 8.11.4 (-da) with plain main() copies of the same steps (core jar only; acquire() bounded by a 10 s join because it never returns before 4.7.0), the one-test JUnit repro on 9.12.3, 10.6.0 and main (-ea and -da), the independent reproduction's own test on 10.5.2, 10.6.0 and 9.12.3 (-ea), and the stock-class route (SearcherManager, a RefreshListener that re-enters maybeRefresh once, a throwing ClosedListener on the intermediate reader) on 9.12.3, 10.6.0 and main (-da). [read] all 127 release tags 3.6.0 to 10.6.0 in the history clone have both the swap order and the finally (8.8.2 to 8.11.x are not tagged there; 8.8.1 read and 8.11.4 executed). Reach by version: in 3.5.0 any failure closing the old reader hit it with the stock class; from 3.6.0 maybeRefresh holds its own count on the old reference across the swap, so the stock managers reach it only through a re-entrant RefreshListener (from 4.2.0, when LUCENE-4695 added RefreshListener.beforeRefresh) plus a failing reader close, and otherwise only a custom ReferenceManager reaches it. Not fixed upstream: upstream main 1c2072f0284 (2026-11-02) still has the code, and the newest upstream commit on ReferenceManager.java is cad76ccfd2d (author date 2025-01-16, comment grammar) [read]. Caveats: one seed per run, JDK 25.0.3 on Linux aarch64; the defect is plain Java logic.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1221.html",
   "repro": "repro/LFV-1221/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-015",
   "priority": "low",
   "priority_rank": 879,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter NRT",
   "title": "After rolled-back segment names are reused, reopening an old NRT reader throws a misleading IllegalStateException",
   "summary": "You open an NRT reader from a writer that is then rolled back without committing, a second writer is opened and rolled back too, a third writer reuses the same segment names and commits, and you call openIfChanged(oldReader, commit). You expect a new reader or an AlreadyClosedException, as documented. Instead the LUCENE-5931 guard throws an IllegalStateException that blames the application for removing index files, although Lucene's own IndexFileDeleter deleted them, and its OpenMode.CREATE advice also fails.",
   "impact_class": "wrong error",
   "introduced_commit": "34e56d51f0d (branch_4x; trunk twin c18676ed4fb), LUCENE-4898 'openIfChange now allows targeting an IndexCommit from an NRT reader' (#5963, Michael McCandless): openIfChanged(nrtReader, commit) now reopens through the path that reuses the old reader's segment readers by segment name only, so from 4.3.0 the bug's call sequence silently returns a stale 1-document reader; the misleading IllegalStateException comes from 6b0b119074f (branch_6x, first released in 6.2.0; master twin 664e39292bd, first released in 7.0.0), LUCENE-5931 'detect when segments were (illegally) replaced when re-opening an IndexReader' (#6993, Mike McCandless), which added the segment-id guard in place of the stale reader [read]",
   "introduced_date": "2013-04-04 (LUCENE-4898, the stale-reader form, first released in 4.3.0); 2016-06-12 (LUCENE-5931, the misleading IllegalStateException, first released in 6.2.0)",
   "first_affected_version": "4.3.0 [exec] as a silently stale reader (openIfChanged(r, commit) returns the rolled-back 1-document segment instead of the commit's 2 documents, 4.3.0 to 6.1.0); 6.2.0 [exec] is the first release with the misleading IllegalStateException; 4.0.0 to 4.2.1 refuse the call with IllegalArgumentException [exec]",
   "affected_versions": "4.3.0 to 6.1.0: silently stale reader [exec]; 6.2.0 to 10.6.0 and main 645d4fe14a20: misleading IllegalStateException [exec]; releases in between follow from the code [read]; not affected: 4.0.0 to 4.2.1 (call refused) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-015.html",
   "repro": "repro/LFV-015/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-164",
   "priority": "low",
   "priority_rank": 880,
   "novelty": "new",
   "withheld": false,
   "area": "search / top-k dynamic pruning (BayesianScoreQuery: BayesianScoreScorer#setMinCompetitiveScore)",
   "title": "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",
   "summary": "You run an ordinary top-k search such as searcher.search(query, 10) with a BayesianScoreQuery whose calibrated scores (probabilities) are all below 1e-7, and more than 1,000 documents match. You expect the same top hits as an exhaustive search, because the scores are a monotone transform of the inner BM25 scores and explain() reports exactly those scores. Instead, once the collector starts pruning, BayesianScoreQuery rounds the requested minimum score up to 1e-7 before turning it into a BM25 threshold for the inner query, so the inner query skips documents that are still competitive and the search returns weaker hits (in the repros, in effect the first matches in doc-id order) with no error.",
   "impact_class": "silent wrong results",
   "introduced_commit": "5af15dc4be5b (GITHUB#15827 'Add BayesianScoreQuery and LogOddsFusionQuery for probabilistic hybrid search', by jaepil; 10.x backport 7f55b56a40de, plus e8d1a2a26d6e 'Adjusting for backport', which changes only a throws clause): the lower clamp was added together with the class [read]; kept by d9aa7cbc47d4 (GITHUB#15948, 2026-05-27, which added the base-rate term to the inversion) [read]",
   "introduced_date": "2026-03-27",
   "first_affected_version": "10.5.0 [exec] (the first release with the class; 10.4.0 and 9.12.3 do not have BayesianScoreQuery, so the repros do not compile there [exec])",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2, 10.6.0 and main ea57360912ed [exec]; setMinCompetitiveScore is byte-identical in all four [read]; branch_10x (unreleased) and branch_10_6 carry the same line [read]; not fixed upstream: the line is unchanged on main, branch_10x, branch_10_6, branch_10_5 and the 10.5.2 tag, and open PR #16410 keeps it [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-164.html",
   "repro": "repro/LFV-164/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-450",
   "priority": "low",
   "priority_rank": 881,
   "novelty": "new",
   "withheld": false,
   "area": "search / top-k dynamic pruning (BayesianScoreQuery: BayesianScoreScorer#setMinCompetitiveScore)",
   "title": "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",
   "summary": "You run an ordinary top-k search such as searcher.search(query, 10) with a BayesianScoreQuery, and more than 1,000 documents match. You expect the same top hits as an exhaustive search, because the probability is a monotone function of the inner score and pruning may skip only documents that score below the current k-th hit. Instead, when a later document's probability is exactly one float step above the k-th hit's (most often when probabilities are close to 1), BayesianScoreQuery turns that probability back into an inner-score threshold with a closed-form inverse that lands in the middle of the range of inner scores that all round to that probability, so the inner query skips the document and the search silently returns the weaker hit.",
   "impact_class": "silent wrong results",
   "introduced_commit": "5af15dc4be5b (GITHUB#15827 'Add BayesianScoreQuery and LogOddsFusionQuery for probabilistic hybrid search', by jaepil; 10.x backport 7f55b56a40de, plus e8d1a2a26d6e 'Adjusting for backport', which changes only a throws clause): the closed-form inversion came with the class [read]; kept by d9aa7cbc47d4 (GITHUB#15948, 2026-05-27), which added the base-rate term to score() and to the inversion [read]",
   "introduced_date": "2026-03-27",
   "first_affected_version": "10.5.0 [exec] (the first release with the class; 10.4.0 and 9.12.3 do not have BayesianScoreQuery, so the repro does not compile there [exec])",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2, 10.6.0 and main ea57360912ed [exec]; setMinCompetitiveScore is byte-identical (md5) in all four and on branch_10_5, branch_10_6 and branch_10x [read]; not fixed upstream: the method is unchanged on upstream main, branch_10x and branch_10_6 [read], and open PR #16410 keeps the closed-form inverse [read]; the released 10.6.0 (2026-10-29) carries the same method [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-450.html",
   "repro": "repro/LFV-450/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-104",
   "priority": "low",
   "priority_rank": 882,
   "novelty": "new",
   "withheld": false,
   "area": "search / top-k dynamic pruning (block-max conjunction and MaxScore bulk scorers)",
   "title": "ScorerUtil.minRequiredScore returns NaN when the minimum competitive score is +Infinity, so block-max conjunctions and MaxScore disjunctions drop documents that score +Infinity",
   "summary": "You run an ordinary top-k search, for example IndexSearcher#search(query, 1), with a two-clause conjunction or disjunction whose scores can overflow to +Infinity (two FeatureField linear queries over very large feature values, or two clauses with very large finite boosts). You expect the best documents first, +Infinity before Float.MAX_VALUE and ties by ascending doc id, as Lucene 10.2.2 returns them. Instead, once the minimum competitive score reaches +Infinity, ScorerUtil.minRequiredScore returns NaN and filterCompetitiveHits discards every remaining candidate, so the search silently returns doc 0 scoring Float.MAX_VALUE instead of doc 3000 scoring +Infinity (one thread, one segment), or docs 100, 101, 102 instead of the equally scored docs 0, 1, 2 (a concurrent search in which the slice with the higher doc ids finishes first).",
   "impact_class": "silent wrong results",
   "introduced_commit": "62e02760321 (#14827 'Pre-calculate minRequiredScore to speedup filterCompetitiveHits', main; branch_10x backport 5687ed5e8a0) starts the regression: it replaced the per-document bound test with a precomputed threshold that is +Infinity for a +Infinity minimum (NaN when the remaining clauses' max is infinite), so documents whose finite partial score would overflow to +Infinity are dropped [exec]; today's form (NaN for every +Infinity minimum, so even documents already at +Infinity are dropped) comes from the same-day follow-up 3f71b54c47a 'Improve test and address more test failures.' (main; branch_10x d0a4b104214; pushed without a PR) [exec]; the follow-up in between, bf848a9a3ab 'Fix test failures.' (branch_10x 678b54f9147), does not change the behaviour for this input [exec]; the commits were located with git log -L and git tag --contains [read], and the commit-level runs compile each branch_10x commit's ScorerUtil.java and BlockMaxConjunctionBulkScorer.java over the 10.3.0 jars; a regression from a performance change, absent in 10.2.2",
   "introduced_date": "2025-07-03 (#14827 merged 11:26Z on main; follow-ups bf848a9a3ab at 16:15Z and 3f71b54c47a at 21:05Z the same day)",
   "first_affected_version": "10.3.0 [exec]",
   "affected_versions": "10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2, 10.6.0 and main ea57360912ed through 645d4fe14a2 [exec]; not affected: 10.2.2 and 9.12.3 [exec]; the helpers (minRequiredScore, filterCompetitiveHits, DocAndScoreAccBuffer) do not exist before 10.3.0 [exec]; upstream main and branch_10_6 (10.6.0, released 2026-10-29) have minRequiredScore and filterCompetitiveHits bodies byte-identical to ea57360912ed [read], and 10.6.0 RC1 is affected [exec]; not fixed upstream [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-104.html",
   "repro": "repro/LFV-104/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-113",
   "priority": "low",
   "priority_rank": 883,
   "novelty": "new",
   "withheld": false,
   "area": "search / top-k dynamic pruning (WANDScorer)",
   "title": "WANDScorer mishandles a minimum competitive score of +Infinity: an assertion fails with -ea, and with -da it prunes documents that score +Infinity",
   "summary": "You run a top-k search whose top-level disjunction runs on WANDScorer, for example three FeatureField linear SHOULD clauses with minimumNumberShouldMatch 2, over documents whose finite clause scores add up past Float.MAX_VALUE, so that they score +Infinity. You expect the same documents as an exhaustive (COMPLETE) search: hits tied at +Infinity stay competitive and are ordered by doc id (or by the next sort field). Instead, once the collector raises the minimum competitive score to +Infinity, WANDScorer.scaleMinScore fails its 'Float.isFinite(minScore)' assertion with -ea (even in a single-threaded search), and with -da it saturates the bound to Long.MAX_VALUE and prunes every remaining document, so a concurrent search with the default slicing returns docs 23, 24, 25 instead of 0, 1, 2, all scoring +Infinity.",
   "impact_class": "silent wrong results",
   "introduced_commit": "4fc5a872ded (LUCENE-4100 'Faster disjunctions when the hit count is not needed', a JIRA patch committed directly, no GitHub PR) created WANDScorer and scaleMinScore with only a not-NaN assertion and a saturating cast ('cast might lower the value again if scaled > Long.MAX_VALUE, which is fine'), which turns a +Infinity minimum into Long.MAX_VALUE and rejects every document: the -da wrong results [read]; d9e37f31230 (main; branch_9x db0e712cad3), apache/lucene#794 'Improve accuracy of scaled scores in WANDScorer' (LUCENE-10503; the commit message says LUCENE-10153 by mistake), tightened the assertion to Float.isFinite(minScore): the -ea AssertionError [exec]; the stock collectors reach the -da form through 947f82679af (LUCENE-8507: TopFieldCollector passes the raw bottom score for a score-first sort, 8.0.0) and LUCENE-8992 (apache/lucene-solr#904, branch_8x 1c23a3c14e7: the cross-slice shared bound passes the raw global score to leaves with smaller doc ids, 8.4.0) [exec]; commits located with git log -S and the tag history in the history clone [read]; a long-standing bug, not a recent regression",
   "introduced_date": "2017-12-07 (LUCENE-4100, the -da form); 2022-04-19 (#794, the -ea AssertionError); exposure routes 2018-10-18 (LUCENE-8507) and 2019-10-21 (LUCENE-8992 merged)",
   "first_affected_version": "8.0.0 [exec]; 8.4.0 for the judged cross-slice TopScoreDocCollector form [exec]; 9.2.0 for the -ea AssertionError [exec]",
   "affected_versions": "-da wrong results: every release from 8.0.0 through 10.6.0 and main ea57360912ed; executed: sort route on 8.0.0, 8.11.4, 9.12.3, 10.5.2, 10.6.0 and main, cross-slice route on 8.4.0, 8.11.4, 9.1.0, 9.2.0, 9.12.3, 10.4.0, 10.5.2 and main (each -ea and -da); -ea AssertionError: 9.2.0 through 10.6.0 and main [exec]; not affected: 8.3.1 for the cross-slice route [exec]; 7.x and earlier lack WANDScorer, ScoreMode and setMinCompetitiveScore [exec]; the releases between the executed ones were checked by reading the scaleMinScore body and the collectors' raw-bound code at each tag [read]; the finder's dense msm query passes on 10.4.0 and 10.0.0 only because that query is not routed to WANDScorer before #16176 (10.5.0), while sparse queries reach WANDScorer on every release tested [exec]; upstream main HEAD is the tested commit, and the last WANDScorer.java change on main, branch_10x and branch_10_6 (#16220) does not touch scaleMinScore [read], and 10.6.0 (released 2026-10-29) fails the minimal test with -ea and -da [exec]; not fixed upstream [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-113.html",
   "repro": "repro/LFV-113/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1124",
   "priority": "low",
   "priority_rank": 884,
   "novelty": "new",
   "withheld": false,
   "area": "core / search (DisjunctionMaxQuery: DisjunctionMaxScorer.score and DisjunctionMaxWeight.explain)",
   "title": "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)",
   "summary": "You index one document with two FeatureField features a = b = 1e38 and search DisjunctionMaxQuery([FeatureField.newLinearQuery(f, a, 64), newLinearQuery(f, b, 64)], tieBreakerMultiplier 0) with a collector that counts every hit (TopScoreDocCollectorManager(1, Integer.MAX_VALUE)). Each disjunct scores 64 * 1e38 = +Infinity, so with tie 0 you expect the maximum, +Infinity, which is what the default search(q, n) and DisjunctionMaxScorer.getMaxScore give. You get NaN, with no error: DisjunctionMaxScorer.score moves the first +Infinity into the sum of the other scores and returns Infinity + Infinity * 0 = NaN, and explain() and some BooleanQuery nestings give NaN too, so the same document's score and rank depend on how the query is executed.",
   "impact_class": "minor",
   "introduced_commit": "3c10854e00f ('new DisjunctionMaxQuery/DisjunctionMaxScorer from Chuck Williams: LUCENE-323', committed by Yonik Seeley; JIRA era, no pull request; migrated as apache/lucene#1401): the class was born with score() = max + (sum - max) * tieBreakerMultiplier, which is NaN for any +Infinity sub-score and any tie, and explain() used the same formula. Today's expression, scoreMax + otherScoreSum * tieBreakerMultiplier (DisjunctionMaxScorer.java:72, DisjunctionMaxQuery.java:239), comes from e3f90385b49 (LUCENE-8097, migrated as #9145, Adrien Grand, first released in 8.0.0; git blame on main), which narrowed the NaN to two or more +Infinity sub-scores with tie 0 but did not remove it. c88f9334e5c (#14040, 10.1.0) added DisjunctionMaxBulkScorer (Math.max) for tie 0 under TOP_SCORES, which is why the default top-level search returns +Infinity while the other paths return NaN [read]",
   "introduced_date": "2005-11-16 (author date of 3c10854e00f); today's expression 2017-12-26 (e3f90385b49); the path split 2024-12-06 (c88f9334e5c, #14040)",
   "first_affected_version": "1.9 [exec]; 1.4.3 has no DisjunctionMaxQuery. The repro's own trigger (FeatureField.newLinearQuery) exists from 8.8.0, and the one-test JUnit compiles unchanged from 9.10.0",
   "affected_versions": "every release from 1.9 (2006) through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT). Executed: the one-test JUnit fails on main (-ea and -da; finder, the independent reproduction, the intended-behaviour check, judge and re-runs), 10.6.0 (-ea and -da), 10.1.0, 10.0.0, 9.12.3 and 9.10.0 (-da); the independent reproduction's own test fails on 10.5.2 (-ea and -da); an 8.x variant of the JUnit (same FeatureField trigger) fails on 8.8.0 and 8.11.4; a variant whose TermQuery disjuncts score +Infinity through a tf() that returns +Infinity (older releases lack the repro's APIs) fails on 1.9.1, 7.7.3, 8.0.0 and 8.11.4 (-da) [exec]. Before 8.0.0 even one +Infinity disjunct scored NaN, for any tie [exec]; from 10.1.0 the default top-level search(q, n) returns +Infinity and only the other paths are wrong [exec]. Not new in 10.6. Not fixed upstream: upstream main 1c2072f02843 has DisjunctionMaxScorer.java, DisjunctionMaxQuery.java and DisjunctionMaxBulkScorer.java unchanged, and the newest commits on the first two are bc341f2b3e6 (author date 2024-12-16, #14052) and bc601411a31 (author date 2026-08-19, #16519), neither of which touches the formula [read]. Executed on Linux aarch64 with JDK 25.0.3 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1124.html",
   "repro": "repro/LFV-1124/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-304",
   "priority": "low",
   "priority_rank": 885,
   "novelty": "new",
   "withheld": false,
   "area": "core / search and document: query parameter validation (DisjunctionMaxQuery, LatLonPoint distance feature query)",
   "title": "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",
   "summary": "You build a DisjunctionMaxQuery with tieBreakerMultiplier NaN (for example a computed value, or the XML query parser text tieBreaker='NaN'), or a LatLonPoint.newDistanceFeatureQuery with pivotDistance NaN or +Infinity, and expect the IllegalArgumentException that both constructors already throw for every other out-of-range value ('tieBreakerMultiplier must be in [0, 1]', 'pivotDistance must be > 0'). Instead the value is accepted, because the checks are written as 'x < 0 || x > 1' and 'x <= 0', which are false for NaN (and '<= 0' is false for +Infinity): on main the hits come back with NaN scores, although the distance feature javadoc promises scores in [0, weight], and for a NaN value q.equals(q) is false because equals compares the field with ==. Older releases are worse: with a NaN tie-breaker, 8.0.0 and 8.11.4 return no top-k hits while count() finds them, and 9.12.3 with assertions off returns a sentinel ScoreDoc (doc 2147483647, score -Infinity) in place of a hit.",
   "impact_class": "wrong error",
   "introduced_commit": "Two sites, both first released in 8.0.0 [read]. (1) DisjunctionMaxQuery: e3f90385b492 'LUCENE-8097: Implement maxScore() on disjunctions.' (jpountz; JIRA patch, no GitHub PR; issue now apache/lucene#9145) added 'if (tieBreakerMultiplier < 0 || tieBreakerMultiplier > 1) throw IAE' to the DisjunctionMaxQuery constructor and the same check to the package-private DisjunctionMaxScorer constructor. Not a regression in the usual sense: before it the class had no validation at all, and equals has compared the float with == since the class was added (3c10854e00f, LUCENE-323, 2005, Lucene 1.9) [exec]. (2) LatLonPointDistanceFeatureQuery: 10060a6237cc 'LUCENE-8482: Added feature query in LatLonPoint to boost results by distance' (iverase; JIRA patch; issue now apache/lucene#9528) created the class with 'if (pivotDistance <= 0) throw IAE' and the == equals, together with LatLonPoint.newDistanceFeatureQuery; the check was copied from the long-valued recency feature query (LUCENE-8340), where NaN cannot occur. Neither issue discusses NaN.",
   "introduced_date": "2017-12-26 (DisjunctionMaxQuery check, e3f90385b492); 2018-09-19 (LatLon pivot check, 10060a6237cc)",
   "first_affected_version": "8.0.0 [exec] for both sites: at 8.0.0 the DisjunctionMaxQuery controls (-0.01, 1.01, +/-Infinity) flip from accepted to rejected while NaN stays accepted, and the distance feature API first exists there (7.7.3: the method is absent, compile error); both commits are ancestors of the 8.0.0 tag and of no 7.x tag",
   "affected_versions": "8.0.0 through 10.6.0 and main ea57360912ed for both sites [exec]. The search symptom differs by release [exec]: DisjunctionMaxQuery with 2 matching documents gives 0 top-k hits on 8.0.0 and 8.11.4 (-ea and -da) and 9.0.0 (-ea), an AssertionError on 9.12.3 and 10.0.0 with -ea, sentinel ScoreDocs on 9.12.3 with -da, and both documents with score NaN on 10.5.2 and main; the distance feature query throws AssertionError with -ea on 8.0.0-10.0.0 and returns NaN scores with -da there and in both modes on 10.5.2 and main. DisjunctionMaxQuery in 1.9.1-7.7.3 also accepts NaN with the same non-reflexive equals, but those releases have no range check at all [exec]. Not fixed upstream: both checks are unchanged on upstream main and branch_10x and no open PR changes them (2026-10-26) [read]. All runs on aarch64 with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-304.html",
   "repro": "repro/LFV-304/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-426",
   "priority": "low",
   "priority_rank": 886,
   "novelty": "new",
   "withheld": false,
   "area": "core / document: XY distance sort (XYDocValuesField.newDistanceSort, XYPointSortField, XYPointDistanceComparator)",
   "title": "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",
   "summary": "You build a distance sort with XYDocValuesField.newDistanceSort(\"p\", Float.NaN, 0f), or with an infinite x or y, and expect the IllegalArgumentException that its javadoc promises when the 'location has invalid coordinates', as LatLonDocValuesField.newDistanceSort throws for NaN and as the XYDocValuesField constructor, XYPointField.newDistanceQuery and XYCircle throw for the same values. Instead the sort is built and the search runs, because the XYPointSortField constructor checks only that the field name is not null. With a NaN origin every distance is NaN, which Double.compare orders after +Infinity, so a document without a location (distance +Infinity, documented as 'missing values sort last') is returned before the documents that have one; with an infinite origin all distances tie at +Infinity.",
   "impact_class": "wrong error",
   "introduced_commit": "88dd1c3f3d4eb37c522b9b00a5ccce979e6efad6 (master, now main), backported to branch_8x as 53cb6acf912f54a07b870fe6726bfee329b62d06; both 'LUCENE-9238: Add new XYPointField, queries and sorting capabilities (#1272)' by iverase (PR apache/lucene-solr#1272, 'Adaptation of LatLonPoint to generic cartesian space', one approval and one comment asking for a CHANGES entry, no inline review comments; migrated issue apache/lucene#10278) [read]. Born with the feature, not a regression: the LatLon twin LatLonPointSortField validated its origin from its first commit (LUCENE-7099, b3ee746a8b1, 2016-03-11; GeoUtils.checkLatitude/checkLongitude since 6f0488f7302, 2016-03-27), and XYEncodingUtils.checkVal already required finite values one week before (LUCENE-9218, 4a54ffb553ad, 2020-02-14). No commit-level A/B: the introducing commit creates the affected classes, so its parent cannot compile the repro",
   "introduced_date": "2020-02-21 (author and commit date of 88dd1c3f3d4 and 53cb6acf912)",
   "first_affected_version": "8.5.0 [exec] (the first release with the XY point classes; 8.4.1 has no such API [exec])",
   "affected_versions": "every release from 8.5.0 to 10.6.0, 53 releases (19 on 8.x: 8.5.0-8.11.4; 21 on 9.x: 9.0.0-9.12.3; 13 on 10.x: 10.0.0-10.6.0), and main ea57360912ed and 645d4fe14a20 (unreleased 11.0) [exec]. Not affected: 8.4.1 and earlier (API absent) [exec]. Not fixed upstream: upstream main cf398bfb142 (2026-10-26) has a byte-identical XYPointSortField.java and branch_10x the same constructor; no open PR adds origin validation [read]. All runs on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-426.html",
   "repro": "repro/LFV-426/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1191",
   "priority": "low",
   "priority_rank": 887,
   "novelty": "new",
   "withheld": false,
   "area": "core / store: SleepingLockWrapper (constructor pollInterval check, obtainLock)",
   "title": "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)",
   "summary": "You wrap a directory in new SleepingLockWrapper(dir, 1000, 0), with a pollInterval the constructor accepts (it rejects only negative values, with the message 'pollInterval must be a non-negative number'), and ask it for a lock that nobody holds. You expect either that lock or an IllegalArgumentException from the constructor. Instead every obtainLock, including the one in IndexWriter's constructor, throws java.lang.ArithmeticException '/ by zero' from 'lockWaitTimeout / pollInterval' before the wrapped directory is even asked for the lock.",
   "impact_class": "minor",
   "introduced_commit": "fe6c3dc9397b0397aebf84fedb57875beb163d1d (LUCENE-6508 'Simplify directory/lock API', migrated issue apache/lucene#7567; svn-era commit r1683606, no pull request; same-day branch_5x commit dcd53bc7336de75e0ad8128e83789cb4854ffa81, r1683609): it wrote both the 'pollInterval < 0' check and the 'lockWaitTimeout / pollInterval' division, in a class that was then package-private in org.apache.lucene.index [read]. 5438754ac1cdd3304dfc51e4c7e72fbd4ae916cd (LUCENE-6525 'Deprecate IndexWriterConfig's write lock timeout', #7583, 2015-06-14; branch_5x e8ea6fa26c1) moved it to org.apache.lucene.store and made it public, so applications can call the 3-argument constructor from then on. Both are first released in 5.3.0.",
   "introduced_date": "2015-06-04 (author date = commit date, 18:20 UTC; branch_5x 18:46 UTC); public since 2015-06-14 (LUCENE-6525); first release 5.3.0",
   "first_affected_version": "5.3.0 [exec]; 5.2.1, the last release before, is not affected [exec]",
   "affected_versions": "Every release from 5.3.0 (2015) through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT); never fixed. [exec] history step: 5.3.0 (-ea, -da), 6.6.6, 7.7.3, 8.11.4, 9.12.3 and 10.6.0 (-da) and main (-ea, -da) fail with ArithmeticException '/ by zero' in obtainLock (at :79 on 5.3.0 to 9.12.3, at :81 on 10.6.0 and main); runs before 9.1.0 use copies that change only the LuceneTestCase package (and, for 5.3.0 and 6.6.6, use RAMDirectory instead of ByteBuffersDirectory); finder: main (-ea, -da), 10.6.0 and 9.12.3 (-da); the independent reproduction's own test: main (-ea, -da), 10.6.0, 10.5.2 and 9.12.3 (-da), plus a one-off check on the 5.3.0 core jar; the intended-behaviour check's own test: main (-ea, -da) and 10.6.0 (-da); judge and re-runs on main (-ea, -da). Not affected: 5.2.1 and earlier (no such class). Not new in 10.6 (10.5.2 and every executed older release fail). Not fixed upstream: upstream main still has 'if (pollInterval < 0)' at :71 and the division at :81 (contents API, 2026-11-03); the newest commit on the file is 33f314f3e95 on main and db775275305 on branch_10_6 (#14221, author date 2025-02-12, which made DEFAULT_POLL_INTERVAL final and touches neither line).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1191.html",
   "repro": "repro/LFV-1191/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-083",
   "priority": "low",
   "priority_rank": 888,
   "novelty": "new",
   "withheld": false,
   "area": "queries / function",
   "title": "FunctionRangeQuery over Int/Long/EnumFieldSource turns an exclusive bound at the type limit into an inclusive one",
   "summary": "You run a FunctionRangeQuery over an IntFieldSource, LongFieldSource or EnumFieldSource with an exclusive bound exactly at the type limit, such as n > Integer.MAX_VALUE. You expect no document to match. Instead getRangeScorer adjusts an exclusive bound only when it is not already at the limit (if (!includeLower && lower < Integer.MAX_VALUE) lower++), so at the limit the bound stays inclusive and the document whose value is exactly MAX (or MIN) matches: 1 hit instead of 0.",
   "impact_class": "silent wrong results",
   "introduced_commit": "a993ae9032337ca8d5b2c7a4d58bf41a6f5053f5 (LUCENE-3249 'Moved FunctionQuery impls to new Queries module', #4322, svn trunk r1140906, 2011-06-28), which moved Solr's IntFieldSource and LongFieldSource with the saturating guard 'if (!includeLower && lower < Integer.MAX_VALUE) lower++' (and its upper-bound and Long twins) into Lucene's new queries module; the guard was written for Solr's frange by 6bd49091023 (SOLR-939, 2009-03-23), and FunctionRangeQuery came with LUCENE-6720 (#7778; 13f8ab93a97 on trunk, 88d137632d38 on branch_5x, 2015-08-06) without touching it; later moves kept the text: LUCENE-5247 (#6311, 9db7442d648, 2013-10-01, into IntDocValues/LongDocValues, where git blame stops) and SOLR-5084 (a9f8bf654c2 / 49ed368ae72, 2013-11-05, the int guard copied into EnumFieldSource) [read]",
   "introduced_date": "2011-06-28 (a993ae90323, the guard enters Lucene's queries module; first released in 4.0.0-ALPHA); the guard itself dates from 2009-03-23 (SOLR-939, Solr only) and FunctionRangeQuery from 2015-08-06 (LUCENE-6720, first released in 5.4.0)",
   "first_affected_version": "5.4.0 [exec] for FunctionRangeQuery, the first release with the class (5.3.2 has no FunctionRangeQuery [exec]); the same wrong range scorer is reachable through the public FunctionValues.getRangeScorer of IntFieldSource and LongFieldSource since 4.0.0-ALPHA [exec]; 3.6.2 has no org.apache.lucene.queries.function package [exec]; the EnumFieldSource site from 4.6.0 [read]",
   "affected_versions": "FunctionRangeQuery: every release from 5.4.0 to 10.6.0 and main 645d4fe14a20 [exec]; getRangeScorer level, before FunctionRangeQuery existed: 4.0.0-ALPHA, 4.0.0, 4.10.4, 5.0.0 and 5.3.2 [exec]; [read] the int and long guards are in all 124 release tags of the history clone from 4.0.0-alpha to 10.6.0 (8.9.0-8.11.x are not tagged there; 8.11.4 was executed) and FunctionRangeQuery.java in all 92 tags from 5.4.0; not fixed: upstream main 2f424fd428da (2026-10-30) still has all six guard lines [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-083.html",
   "repro": "repro/LFV-083/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1100",
   "priority": "low",
   "priority_rank": 889,
   "novelty": "known",
   "withheld": false,
   "area": "grouping / TopGroups.merge (sharded grouping)",
   "title": "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)",
   "summary": "You merge the second-pass TopGroups of several shards with TopGroups.merge, as its javadoc suggests, and expect each group's hit count to be the sum of the per-shard counts, which are long TotalHits values. Instead the merge sums them in an int: two shards of 1.5e9 hits wrap negative and new TotalHits(...) throws 'value must be >= 0', while three shards of 1.5e9 silently give 205,032,704 and the average score is divided by that number.",
   "impact_class": "silent wrong results",
   "introduced_commit": "unknown (not bisected). [read] the int accumulator dates from LUCENE-3191 (a1e74fd6c94, 2011, which added TopGroups.merge for sharding, when per-shard counts were ints too); LUCENE-8430 (9ca053712af, 2018, Lucene 8.0) made the per-group count a long TotalHits and kept the int accumulator, so 'totalHits += ...value()' narrows silently.",
   "introduced_date": "2011 (LUCENE-3191) and 2018 (LUCENE-8430) [read]",
   "first_affected_version": "unknown (not bisected); the int accumulator dates from LUCENE-3191 (2011) [read]; oldest executed release 9.12.3 [exec]",
   "affected_versions": "9.12.3 [exec]; 10.5.2 and 10.6.0 [exec]; main 645d4fe14a20 [exec] and main e1faeba08bde with -ea and -da [exec] fail.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/10342",
    "https://issues.apache.org/jira/browse/LUCENE-9302",
    "https://github.com/apache/lucene/issues/16548"
   ],
   "doc": "",
   "repro": "repro/LFV-1100/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-172",
   "priority": "low",
   "priority_rank": 890,
   "novelty": "new",
   "withheld": false,
   "area": "core store + index / stored string fields (DataInput.readString decode, IndexWriter.MAX_STORED_STRING_LENGTH check)",
   "title": "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",
   "summary": "You store a text field of 357,913,941 CJK characters (1,073,741,823 UTF-8 bytes, about half of what IndexWriter's own length check, MAX_STORED_STRING_LENGTH, allows) with the default codec, and IndexWriter accepts and commits it. You expect StoredFields#document to return it, as it does for a string one character shorter. Instead every read throws java.lang.OutOfMemoryError 'UTF16 String size is 1073741823, should be less than 1073741823', whatever the heap, because DataInput.readString decodes with new String(bytes, 0, length, UTF_8), which on JDK 9 and later sizes its UTF-16 buffer by the byte count and refuses 2^30 - 1 or more units; merges that copy the document through a visitor, and flushes of an index-sorted writer, throw the same Error and close IndexWriter.",
   "impact_class": "crash",
   "introduced_commit": "none bisectable: no release executed on JDK 25 passes (5.5.5 to main) [exec]. Three ingredients [read]: (1) stored strings are decoded with the JDK String(byte[], ..., UTF-8) constructor since 8af3598b74d (LUCENE-510, first released 2.4.0); the decode site moved with LUCENE-5989 (fd23211957a / 249d0d25fec, 5.2.0) and LUCENE-8805 (5a694ea26ff, 9.0.0, into DataInput.readString), keeping the same constructor; (2) JDK 9 compact strings size the UTF-16 buffer of a non-Latin-1 result by the UTF-8 byte count and refuse about 2^30 or more units (OpenJDK source reading; JDK 8 decodes into a char[] with no such cap); (3) the documented limit IndexWriter.MAX_STORED_STRING_LENGTH and its IndexWriter check, 2902727a157 (master) / be47009ce76 (branch_6x), LUCENE-7538 (#8589), first released 6.4.0, which states the contract but did not introduce the failure (6.3.0, without the limit, fails identically [exec])",
   "introduced_date": "none bisectable; ingredient dates: 2008-03-26 (LUCENE-510, decode by the JDK constructor), 2016-11-10 (LUCENE-7538, the stated limit), 2017 (JDK 9 GA with compact strings; general knowledge, not checked)",
   "first_affected_version": "<= 5.5.5 [exec] (the oldest release executed; by code reading every release since 2.4.0 decodes stored strings through the same JDK constructor; the documented limit the bug violates exists since 6.4.0; 6.x-8.x are affected only on a JDK 9+ runtime, 9.0.0 and later on every JDK they support [read])",
   "affected_versions": "5.5.5, 6.3.0, 6.4.0, 8.11.4, 9.0.0, 9.12.3, 10.5.2, 10.6.0 and main ea57360912ed [exec]; main also with -da [exec]; main a9779ef3c193 and 645d4fe14a2 and branch_10x 657014b3c579 [exec]; every release from 2.4.0 on [read]; before 9.0.0 an application's own raw-bytes StoredFieldVisitor could still read the field [exec], from 9.0.0 on no visitor can [read]; JDK dependence [read]: 6.x-8.x fail only on JDK 9 or later, JDK 21 and 25 refuse from 2^30 - 1 bytes, JDK 11 and 17 above 2^30 - 1 (exactly 2^30 - 1 not checked); executed on JDK 25 and aarch64 only; not fixed upstream (readString identical on main, branch_10x, branch_10_6, branch_10_5 and branch_9_12, 2026-10-26)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-172.html",
   "repro": "repro/LFV-172/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-613",
   "priority": "low",
   "priority_rank": 891,
   "novelty": "new",
   "withheld": false,
   "area": "util / BKD points (BKDWriter in-heap sort buffer sizing: HeapPointWriter and the BKDRadixSelector heap writers, reached through Lucene90PointsWriter's public maxMBSortInHeap constructor)",
   "title": "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",
   "summary": "You give a points format a sort budget of 2048 MB or more, for example new Lucene90PointsWriter(state, 512, 2200.0) in a custom codec, and merge segments that hold more than 2 GiB of points of one multi-dimensional field (in the repro 8.4M points of 16 dims x 16 bytes). You expect the merge to succeed, because BKDWriter 'uses up to the specified maxMBSortInHeap heap space for writing', spills to disk beyond it, and its constructor accepts the value. Instead BKDWriter sizes its in-heap buffer as budget / bytesPerDoc points with no cap at the Java array limit, HeapPointWriter computes bytesPerDoc * size in int, the length wraps negative, and forceMerge(1) throws NegativeArraySizeException (-2110967296) and leaves the IndexWriter closed with that tragic exception.",
   "impact_class": "crash",
   "introduced_commit": "3ef6e015dd127b356e4163eb48411be94fb2d50c (master) and its same-day branch_8x backport 66d4840860230613881aa42cf5837478d156f6e6 (the copy that shipped), LUCENE-8699 'Use fixed byte array in HeapPointWriter' (apache/lucene#9745, PR apache/lucene-solr#578, by GitHub iverase): HeapPointWriter's list of 4 KB blocks became one byte[packedBytesLength * size] computed in int, today's new byte[config.bytesPerDoc() * size]. Two commits of the same release made it reachable: LUCENE-8673 (5d1d6448b91 / branch_8x a843b3aa35f, radix partitioning, 2019-02-07) removed BKDWriter's OfflineSorter.BufferSize.megabytes(maxMBSortInHeap) call, which since 6.1.0 (LUCENE-7142) had rejected budgets >= 2048 MB with 'Buffer too large for Java (2047mb max)', and LUCENE-8703 (15dd4a17386d / branch_8x 748d483e67b, 2019-03-01) made initPointWriter() allocate a heap writer of exactly totalPointCount points whenever that count fits the budget [read]",
   "introduced_date": "2019-02-20 (LUCENE-8699, master and branch_8x; the enabling LUCENE-8673 is from 2019-02-07 and LUCENE-8703 from 2019-03-01)",
   "first_affected_version": "8.1.0 (tagged 2019-05-13) [exec]; 8.0.0 is the last unaffected release: 6.0.0, 6.1.0, 6.6.6, 7.7.3 and 8.0.0 [exec] reject the same budget with IllegalArgumentException 'Buffer too large for Java (2047mb max)' (in 8.0.0 through IndexWriter at the first flush), so the setting never worked before 8.1.0, but it failed at once with a clear message",
   "affected_versions": "every release from 8.1.0 through 10.6.0 and main a9779ef3c193 and 645d4fe14a20 [exec]. Not affected: 6.0.0-8.0.0 (the budget is rejected) [exec]. The BKD files are byte-identical in main ea57360912ed and a9779ef3c193 [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-613.html",
   "repro": "repro/LFV-613/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-385",
   "priority": "low",
   "priority_rank": 892,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexingChain aborting-exception classification x util / UTF-16 to UTF-8 sizing (CharTermAttributeImpl.getBytesRef, BytesRefBuilder.copyChars, UnicodeUtil.maxUTF8Length)",
   "title": "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",
   "summary": "You index a document whose untokenized indexed field (or a TextField analyzed with KeywordAnalyzer) holds one value of 715,827,878 or more characters, for example 'a' repeated 715,827,883 times. You expect what Lucene does for any over-long term: addDocument throws the documented 'immense term' IllegalArgumentException, skips that document and keeps the IndexWriter open with the other buffered documents. Instead the UTF-16 to UTF-8 conversion sizes its buffer at 3 bytes per character before the length check, that size overflows int (ArithmeticException) or exceeds the maximum array length (IllegalArgumentException), and because the conversion runs inside the indexing chain's aborting try, IndexWriter closes itself and rolls back every document added since the last commit.",
   "impact_class": "crash",
   "introduced_commit": "root cause: b679816a700 (LUCENE-2370 flex reintegration into trunk, now GitHub #3446; SVN era, no PR): each term is converted to UTF-8 into a worst-case-sized buffer (then length*4) before the immense-term length check, inside the aborting step of the indexing chain [read]. Writer-closing form (the title): LUCENE-5987 (now GitHub #7049) by GitHub mikemccand, c064aaa4850 (branch_5x) / de4c6513bcb (trunk), which made every aborting exception close IndexWriter [read]. Later milestones: LUCENE-6133 (52b13f1946b / d249f8bc337) moved the threshold from about 536.9M to 715,827,878 units; LUCENE-7538 (#8589; be47009ce76 / 2902727a157) made n >= 715,827,883 throw ArithmeticException and added a pre-check for stored fields only",
   "introduced_date": "2010-04-06 (root cause, LUCENE-2370); 2014-12-05 (writer closes, LUCENE-5987)",
   "first_affected_version": "4.0.0 [exec] for the root cause (first GA release; milder form: the indexing thread's buffered documents are silently dropped and the caller gets ArrayIndexOutOfBoundsException, the writer stays open); 5.0.0 [exec] for the writer-closing form in the title; 3.6.2 [exec] is not affected (a huge token is skipped like any immense term)",
   "affected_versions": "4.0.0 to 4.10.4, milder form [exec]; 5.0.0 to 10.5.2 (the last release before 10.6.0) and main ea57360912ed: IndexWriter closes with a tragic exception and every uncommitted document is rolled back [exec]; from 6.4.0 on n >= 715,827,883 throws ArithmeticException (before: ArrayIndexOutOfBoundsException with -da, AssertionError with -ea) [exec]; not fixed in any release, nor on upstream main cf398bfb142 [read]. Releases between the executed ones are inferred from code reading, not run one by one. Caveat: every run used JDK 25.0.3 on aarch64",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/8589",
    "https://issues.apache.org/jira/browse/LUCENE-7538",
    "https://github.com/apache/lucene/issues/11033",
    "https://issues.apache.org/jira/browse/LUCENE-9994",
    "https://github.com/apache/lucene/issues/15152",
    "https://github.com/apache/lucene/issues/15330"
   ],
   "doc": "",
   "repro": "repro/LFV-385/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1076",
   "priority": "low",
   "priority_rank": 893,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter delete buffer and stall control (DocumentsWriter.applyDeleteOrUpdate vs the #16867 delete-buffer hard limit)",
   "title": "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)",
   "summary": "On Lucene main with #16867, one thread runs a commit or NRT refresh while another calls deleteDocuments(Term...) or a doc-values update (updateNumericDocValue, updateBinaryDocValue, updateDocValues). You expect these calls to be held at #16867's new 'hard limit' on the shared delete buffer, as document adds and updates (softUpdateDocument included) are, so that the buffer can no longer overflow. Instead only document adds and updates wait on the new stall: the delete and doc-values-update calls keep filling the buffer (to 8x a cap lowered to 256 KB in the repro), and at the real 1945 MB cap they still overflow it at 2 GiB with ArithmeticException 'integer overflow', after which the writer fails every flush and commit until rollback().",
   "impact_class": "index unusable",
   "introduced_commit": "2813efa40a3c61228a1ec3ae4d230772ef8a8c33 (apache/lucene#16867 'Avoid overflows in IndexWriter's delete buffer', by romseygeek, merged with no reviews; branch_11x backport cdfe8aa782936c0455fcc3a8232ac217bdec259b) [exec]. #16867 added the hard limit (DocumentsWriterFlushControl.maxDeleteBytes) and the full-flush stall but did not touch DocumentsWriter.java, where only preUpdate (document adds and updates) waits on the stall. The non-waiting delete path itself is old (deletes never waited on stall control since LUCENE-2573 / LUCENE-3090, 2011; the current applyDeleteOrUpdate shape comes from LUCENE-5189, 2013, through LUCENE-8813, 2019) [read] and was no defect until #16867 made the stall the enforcement of a buffer limit: an incomplete fix",
   "introduced_date": "2026-10-30 (2813efa40a3 author and commit date on main; branch_11x cdfe8aa7829 authored and committed the same day; PR opened 2026-10-19)",
   "first_affected_version": "unreleased (main 12.0.0-SNAPSHOT from 2813efa40a3 and branch_11x 11.0.0-SNAPSHOT from cdfe8aa7829; #16867 is in the 'Lucene 11.0.0' CHANGES section, so it would first ship in 11.0.0). 10.6.0 and earlier have no cap, so this gap cannot exist there [exec]; their uncapped overflow is the original, known #16867 bug",
   "affected_versions": "[exec] upstream main f815e679bf6 (stock build, core jar sha1 ab30711a0c99: the repro fails with -ea and -da, 2,090,208 bytes for the 256 KB cap; the independent reproduction's deleteDocuments test 2,154,744 bytes), main 645d4fe14a20 plus the exact f815e679bf6 (= 2813efa40a3) DocumentsWriterFlushControl.java and FlushByRamOrCountsPolicy.java as shadow classes (by the finder, the independent reproduction, the intended-behaviour check, the adjudication and the registration check, -ea and -da), and the real-scale overflow with the default cap and public API only on stock f815e679bf6 (3 GB and 5 GB heaps). [read] upstream main head e1faeba08bd and branch_11x head da3ea39fa59: no commit to DocumentsWriter.java, DocumentsWriterFlushControl.java or FlushByRamOrCountsPolicy.java since #16867 (checked 2026-11-02). Not affected as this gap: 10.6.0 (4ae946e5a9b), 10.5.x, all 9.x and older, and branch_10_6 (no cap, no backport; [exec] compile_error on 10.6.0 and 9.12.3); there every call path overflows, which is the original #16867 / elastic/elasticsearch#160939 bug (a hunt unit's real-scale probe on 10.6.0 and the independent reproduction's on 10.5.2 overflow through deleteDocuments). Not new in 10.6",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16867",
    "https://github.com/apache/lucene/issues/16959",
    "https://github.com/apache/lucene/issues/15152",
    "https://github.com/apache/lucene/issues/15330"
   ],
   "doc": "",
   "repro": "repro/LFV-1076/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-386",
   "priority": "low",
   "priority_rank": 894,
   "novelty": "new",
   "withheld": false,
   "area": "index / in-RAM postings byte slices (ByteSliceReader, TermsHashPerField)",
   "title": "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",
   "summary": "You add one very large document whose postings fill the indexing thread's in-RAM byte pool to its very last byte (global offset 2^31), and you expect the flushed segment to hold exactly the positions and payloads you indexed, or a loud failure such as the ArithmeticException Lucene has thrown since 9.8.0 once the pool would grow further. Instead, if one term's postings stream ends in the slice that occupies the pool's last bytes, ByteSliceReader.nextSlice computes nextIndex + newSize = 2^31 in int, which wraps negative, so it treats that final slice as non-final, reads its last 3 data bytes plus the level marker as a forwarding address, and returns the stream's last 1-3 bytes from an unrelated part of the pool. IndexWriter commits with no exception (with -ea and -da) and CheckIndex reports the segment clean; in the executed run the last 3 bytes of a 355-byte payload, 0x41 0x42 0x43, read back as 0x11.",
   "impact_class": "data corruption",
   "introduced_commit": "cff5767e443411c78b199fbf9686d1ec672e38f0 (svn r553236, LUCENE-843 'speed up IndexWriter performance', JIRA era, no GitHub PR; committed by mikemccand): it added DocumentsWriter with a nested ByteSliceReader whose 'if (nextIndex + newSize >= endIndex)' (DocumentsWriter.java:2432) and 'if (startIndex+firstSize >= endIndex)' (:2385) are the two lines on main today (ByteSliceReader.java:109 and :58); moved unchanged to its own file by e5f9b4e1cb3 (LUCENE-1212, 2008-03-12) [read]. Latent since then, not a regression: #12392 (b88d3e19889, 2023-06-28, the pool's 2^31 cap) neither caused nor fixed it (9.7.0 and 9.8.0 both fail) [exec]",
   "introduced_date": "2007-07-04",
   "first_affected_version": "2.3.0 [exec]; 2.2.0 has no ByteSliceReader (the probe does not compile) [exec]; end to end through IndexWriter the earliest release executed is 8.11.4 [exec]",
   "affected_versions": "Every release from 2.3.0 to 10.6.0 and main (155 lucene-core versions on Maven Central; none fixed). Executed, all with the same silent wrong bytes: the minimal test on 10.5.2, 10.6.0 and main 645d4fe14a20 (-ea and -da) and on 9.9.0 (-ea); ports of it with the same layout on 2.3.0, 2.3.1, 2.3.2, 2.4.0, 3.0.0, 3.6.2, 4.0.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4 and 9.8.0 (the one-block-earlier control passes on 2.3.0, 2.3.2, 2.4.0, 3.6.2, 4.0.0 and 9.8.0); the independent reproduction JUnit on 9.7.0, 9.8.0, 9.12.3 and 10.5.2 (-ea); end to end through IndexWriter on 8.11.4, 9.0.0, 10.0.0 (-ea), 9.7.0 (-da), 9.12.3 and 10.5.2 (-ea and -da), 10.6.0 and main 645d4fe14a20 (-da), and main ea57360912ed (all repros, -ea and -da); the 3-byte-shorter control passes on 8.11.4, 9.12.3, 10.5.2, 10.6.0 and main [exec]. [read] the expression is unchanged on every ref from 2.3.0 (git log -S); before 8.11.4 IndexWriter reachability is argued from identical code only (the end-to-end schedule was built for the 8.x+ layout); upstream main 2f424fd428da, branch_11x and branch_10_6 still have both lines (2026-10-31). Not affected: 2.2.0 and earlier (no ByteSliceReader) [exec].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-386.html",
   "repro": "repro/LFV-386/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-458",
   "priority": "low",
   "priority_rank": 895,
   "novelty": "new",
   "withheld": false,
   "area": "search / HNSW (merge-time graph reuse: old-to-new ordinal mapping in IncrementalHnswGraphMerger and ConcurrentHnswMerger)",
   "title": "HNSW merge with graph reuse throws BufferAllocationException when the reused graph has more than 805,306,368 vectors",
   "summary": "You merge an HNSW vector field in which one segment's graph has more than 805,306,368 vectors (Lucene writes such a segment without error, for example by merging smaller graphs) and expect the merge to reuse that graph as it does at any smaller size, because no HNSW vector-count limit is documented or enforced below IndexWriter.MAX_DOCS. Instead both mergers presize an IntIntHashMap to the graph size to map old to new ordinals, and that map's fixed 0.75 load factor and 2^30-slot table cap make its constructor throw BufferAllocationException ('Maximum array size exceeded for this load factor') before any other work. The merge fails again on every retry, so such a segment can never be merged with graph reuse; by code reading the IndexWriter is also closed as a tragic event.",
   "impact_class": "crash",
   "introduced_commit": "49d521145dede343c83614b2517380bf1bfc1d38 (main) and its branch_9x backport 7d62b23ee907f012b13399d9b056d0bf7c5c32bb, PR #12950 'Use hppc IntIntHashMap to avoid Integer box/unbox when remapping vector ordinals during merge' (msokolov; approved by benwtrent and gsmiller), which replaced CollectionUtil.newHashMap(initGraphSize) with new IntIntHashMap(initGraphSize) in IncrementalHnswGraphMerger.getNewOrdMapping, a performance-only change whose PR never discusses capacity; carried into both mergers by #14331 (3752dba9c51, branch_10x backport aa1e9f34b37, 10.2.0), which presizes one map per reused graph and gave ConcurrentHnswMerger its own copy of the line [read]",
   "introduced_date": "2023-12-15 (main merge; the branch_9x backport has the same date and title)",
   "first_affected_version": "9.10.0 [exec] (the first release containing the branch_9x backport; 9.9.2, tagged later from the 9.9 bugfix branch, does not contain it and completes the mapping at N = 805,306,369 [exec]); the main commit is first released in 10.0.0",
   "affected_versions": "9.10.0 through 10.5.2, 10.6.0 (branch_10_6 RC1 4ae946e5a9b [exec], below) and main ea57360912ed; on 10.4.0 and 10.5.0 only with a codec whose vectors format is not wrapped per field (with the default codec their merges never reuse graphs: #16400, fixed by #16403 in 10.5.1) [read]. [exec] 9.10.0, 9.12.3, 10.0.0, 10.2.0, 10.5.2 and main fail with -ea and -da (both mergers on 10.2.0 and later; in 9.x and 10.0 the concurrent merger inherits the same method); [read] the presizing line is present at all 19 release tags from 9.10.0 to 10.5.2 (follow-up tag scan). Not affected at this size: 9.9.2 [exec], 9.9.0-9.9.1 (same code) [read], 9.6.0-9.8.0 (unsized HashMap) [read], before 9.6.0 (no merge-time graph reuse) [read]. Older, higher ceiling of the same presizing pattern: 9.9.0-9.9.2 throw IllegalArgumentException from 1,610,612,672 nodes because CollectionUtil.newHashMap's capacity overflows [exec], so #12950 halved an existing ceiling; sizes 805,306,369 to 1,610,612,671 are a true regression. Not fixed upstream: on upstream main 645d4fe14a2 (after #16794) both mergers reach one presized map at IncrementalHnswGraphMerger.java:221; branch_10x and branch_10_6 keep both sites (IncrementalHnswGraphMerger.java:210, ConcurrentHnswMerger.java:147) [exec]. No end-to-end IndexWriter run with a real 805M-vector segment was done on any version.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-458.html",
   "repro": "repro/LFV-458/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-048",
   "priority": "low",
   "priority_rank": 896,
   "novelty": "new",
   "withheld": false,
   "area": "search / scoring",
   "title": "BooleanScorer loops forever on the last 4096-doc window of a segment of about 2^31 documents, and a query timeout cannot stop it",
   "summary": "You run a pure disjunction of two or more SHOULD clauses as a count, an index-order or field sort, or a facet collection (any score mode other than TOP_SCORES) on a segment with maxDoc >= 2,147,479,553 and a match in its last 3,967 doc ids. You expect the search to return. Instead windowMax = Math.min(max, windowBase + 4096) wraps to Integer.MIN_VALUE, no iterator advances and the thread spins at 100% CPU forever: on a real, CheckIndex-clean segment of 2,147,483,519 docs, count(f:a OR f:b) and an index-order sort hung while search(q, 10) returned at once.",
   "impact_class": "hang",
   "introduced_commit": "bd3948c539ec1065db8b05b433ea55dbf844ff27 ('Initial revision', svn r149570, 2001-09-18), the import of the Lucene sources into the Apache repository: BooleanScorer's window end was already an unguarded int sum (currentDoc = Math.min(currentDoc+BucketTable.SIZE, maxDoc)); every later rewrite kept an unguarded form, and LUCENE-6184 (cb3ec682d41 on trunk, 5c9b5e7ea4e on branch_5x, 2015-01-19, first released in 5.1.0) wrote today's line windowMax = Math.min(max, windowBase + SIZE) [read]",
   "introduced_date": "2001-09-18 (the import of the Lucene sources); today's text of the line 2015-01-19 (LUCENE-6184)",
   "first_affected_version": "1.0.1 [read]; the earliest release executed is 1.2 [exec]; no older release is in the repository",
   "affected_versions": "every release from 1.0.1 to 10.6.0 (167 releases) and main 645d4fe14a20 [exec]; the trigger window was 1,024 ids before 1.9 and 2,048 from 1.9 to 9.11.1 (4,096 since #13605, 9.12.0), and reach through IndexSearcher differs by era (opt-in only in 1.9-2.4.1) [read]; not fixed upstream (main 2f424fd428da, 2026-10-30)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-048.html",
   "repro": "repro/LFV-048/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-383",
   "priority": "low",
   "priority_rank": 897,
   "novelty": "new",
   "withheld": false,
   "area": "facet / DrillSideways (sequential DrillSidewaysScorer, union and drill-down-advance strategies)",
   "title": "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)",
   "summary": "You run a faceted DrillSideways search in the default sequential mode on an index whose single segment holds more than 2,147,481,600 documents, which IndexWriter accepts (MAX_DOCS = 2,147,483,519), and expect it to return its hits as it does on a segment 2,048 documents smaller. Instead DrillSidewaysScorer's union and drill-down-advance loops walk the segment in 2048-document chunks with an int nextChunkStart that wraps from 2^31 - 2048 to Integer.MIN_VALUE before the exit test 'nextChunkStart >= maxDoc' can fire, so the search thread spins forever and the hits of the last chunk are never collected. Through the public API on a real segment of MAX_DOCS documents the stock search did not return within 300 s, while the fixed build returned its 3 hits in 0.033 s.",
   "impact_class": "hang",
   "introduced_commit": "2c30b69f82e56b101863d07a31aceded4e421cd3 (trunk, svn r1449972) and its branch_4x twin e01492bbee41b0e65b893370bc99d78118cc6035 (svn r1449973, the commit the 4.x releases contain): LUCENE-4748 'Add DrillSideways helper class to Lucene facets module' (migrated as GitHub issue #5813), by GitHub mikemccand; SVN era, no PR. It added DrillSidewaysScorer with CHUNK = 2048, 'int nextChunkStart = CHUNK' and, in doDrillDownAdvanceScoring and doUnionScoring, 'if (nextChunkStart >= maxDoc) break;' followed by 'nextChunkStart += CHUNK;' (2 sites per method) [read] [exec]",
   "introduced_date": "2013-02-26 (both commits; 4.2.0 tagged 2013-03-11)",
   "first_affected_version": "4.2.0 [exec] (4.1.0 and earlier have no DrillSideways API [exec]; IndexWriter.MAX_DOCS exists since 4.9.1 (LUCENE-5843), which bounds the trigger window to maxDoc in [2^31 - 2047, 2^31 - 129]; before 4.9.1 IndexWriter enforced no document limit)",
   "affected_versions": "every release from 4.2.0 to 10.6.0 and main ea57360912ed and 645d4fe14a20 [exec]; branch_10x (unreleased) and branch_10_6 (10.6.0, released 2026-10-29) hold the same DrillSidewaysScorer blob as 10.0.0-10.5.2, and upstream main (e1c4184cb983 and cf398bfb142c, 2026-10-26) the same blob as ea57360912ed [read]. Not checked: x86; the end-to-end run on a real segment was done on main only",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-383.html",
   "repro": "repro/LFV-383/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-139",
   "priority": "low",
   "priority_rank": 898,
   "novelty": "new",
   "withheld": false,
   "area": "search / BooleanQuery MUST_NOT bulk scoring (ReqExclBulkScorer)",
   "title": "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)",
   "summary": "You index one segment of IndexWriter.MAX_DOCS (2,147,483,519) documents with default settings, one of which has b:y, and count the matches of +*:* -b:y (MatchAllDocsQuery as FILTER plus a MUST_NOT term query) with a plain IndexSearcher; you expect 2,147,483,518. Instead you get 2,147,479,551: all 3,967 documents of the last window [2,147,479,552, MAX_DOCS) are silently missing, because ReqExclBulkScorer's WindowBits.applyMask computes Math.min(NO_MORE_DOCS, offset + bitSet.length()) in int, the sum wraps negative for a 4096-bit window based at 2^31-4096 or above, and the method then clears the whole window. Only segments with more than 2,147,479,552 documents and required clauses denser than 0.3% of maxDoc are affected, and only code since #16669 has the bug: 10.6.0 (released 2026-10-29), main and branch_10x.",
   "impact_class": "silent wrong results",
   "introduced_commit": "c5fa32ce49f6 (apache/lucene#16669 'Use intoBitSet to speed up ReqExclBulkScorer', by kkewwei for performance issue #16668, reviewed and merged by romseygeek on main 2026-09-24; branch_10x backport 92ce3eaf4bf5 the same day, inherited by branch_10_6) [exec]; the line is in the PR's first commit b3094fab914 and unchanged in all 8 PR commits; a regression: before it, the required clause's bulk scorer received the caller's acceptDocs unchanged and WindowBits did not exist",
   "introduced_date": "2026-09-24 (#16669 merged on main at 08:30:33Z; branch_10x backport committed at 08:33:25Z)",
   "first_affected_version": "10.6.0 (released 2026-10-29; branch_10_6 head 2763db11b0a contains it [exec])",
   "affected_versions": "10.6.0 (released 2026-10-29) and unreleased lines: main (11.0.0-SNAPSHOT) from c5fa32ce49f through ea57360912ed [exec]; branch_10x (10.7.0-SNAPSHOT) from the backport 92ce3eaf4bf [exec]; branch_10_6 (10.6.0-SNAPSHOT) head 2763db11b0a [exec]; no release before 10.6.0 is affected: 9.12.3, 10.0.0, 10.1.0, 10.2.2, 10.3.2, 10.4.0 and 10.5.2 return the correct result [exec], and WindowBits exists in no release before 10.6.0 [read]; upstream main, branch_10x and branch_10_6 still carry the line (read-only GitHub API, 2026-10-26), so the released 10.6.0 has it; executed on aarch64 Linux with JDK 25 only (pure int arithmetic)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-139.html",
   "repro": "repro/LFV-139/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b): 2 of 4 fail with -ea and 2 of 2 with -da; 10.5.2 returns the correct result."
  },
  {
   "id": "LFV-185",
   "priority": "low",
   "priority_rank": 899,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / postings reader (Lucene104 BlockPostingsEnum position bookkeeping; also the Lucene101, Lucene103, Lucene99 and Lucene90 readers in backward-codecs)",
   "title": "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",
   "summary": "You index documents that each stay within Lucene's per-document limits but repeat one term about a billion times and run PhraseQuery f:\"v t\", which only C matches. You expect the postings reader to return C's own positions (101, 102, 103, ...) and the query to find C. Instead the reader adds up the frequencies of the documents whose positions it skipped in an int, the sum 2,147,483,696 wraps negative, the skip is not done, and nextPosition() returns the first skipped document's positions (1, 2, 3), so the query finds 0 hits with assertions off (with assertions on, an internal assertion fails instead).",
   "impact_class": "silent wrong results",
   "introduced_commit": "cfdd20f5bc8387ba24653ca2ba15aa5be10d0ae0 on main and its branch_10x backport 8ae03d66ad1579d675e9b7618d598e545e95d5a2 (the commit the 10.x release tags contain), PR #13968 'Move postings back to int[] to take advantage of having more lanes per vector.' (author jpountz): the new Lucene101PostingsReader declared 'private int posPendingCount' and 'int toSkip = posPendingCount - freq' where the Lucene912 reader it replaced used long [read]; #14033 (6c48b404cd4, same release) then made sumOverRange return int, with the same behaviour. This re-introduced a long-standing defect: every default positional postings reader from LUCENE-687 (c0d330c04174, 2006, first in 2.1.0) through 9.11.1 kept the pending count in an int, and only #13585 (b4a8810b7ae, Lucene912, 9.12.0 and 10.0.0) used long; the PR texts and reviews of #13585 and #13968 never discuss overflow, so whether the long was meant as an overflow guard is not established [read]",
   "introduced_date": "2024-11-01 (#13968, main and branch_10x backport the same day); the int counter itself dates from 2006-10-30 (LUCENE-687)",
   "first_affected_version": "10.1.0 for the current code (#13968) [exec]; the same int bookkeeping is in every release from 2.1.0 [read] (oldest executed: 3.6.2) through 9.11.1 [exec]; only 9.12.0-9.12.3 and 10.0.0 are unaffected [exec]",
   "affected_versions": "2.1.0-9.11.1, 10.1.0-10.6.0 and main ea57360912ed. [exec] fail: 3.6.2, 4.0.0, 4.10.4, 6.6.6, 8.11.4, 9.0.0, 9.11.1, 10.1.0, 10.5.2, 10.6.0 (the minimal test, 2026-10-31) and main (main also -ea); pass: 9.12.0, 9.12.3 and 10.0.0 (Lucene912 reader with long counters); small-scale controls pass on 3.6.2, 4.0.0 and 4.10.4. [read] 2.1.0-3.6.1, 4.1.0-4.10.3, 5.x, 7.x, 8.0-8.11.3, 9.1-9.11.0, 10.2.x, 10.3.x, 10.4.0-10.5.1, and on main the backward-codecs Lucene90, Lucene99, Lucene101 and Lucene103 readers (old segments); 2.0.0 and earlier skipped positions eagerly per document, so nothing accumulated [read]. On 9.11.1 the raw positions are wrong but the independent reproduction's PhraseQuery happens to match, because the Lucene99 reader re-checks the count on every nextPosition() and the wrapped value comes back around; from 10.1.0 on the PhraseQuery gives a false negative. Not fixed upstream: main and branch_10x (1309534296e3) still use int (read-only check, 2026-10-26).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-185.html",
   "repro": "repro/LFV-185/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-754",
   "priority": "low",
   "priority_rank": 900,
   "novelty": "new",
   "withheld": false,
   "area": "misc / similarities (SweetSpotSimilarity lengthNorm; NaN effect on impacts-based top-k pruning in core search)",
   "title": "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",
   "summary": "You score with SweetSpotSimilarity (default factors) and index one document whose DOCS_AND_FREQS field has a length of at least 1,073,741,848, for example one token with custom term frequency 1.1e9 or about 1.07e9 ordinary tokens, expecting the documented lengthNorm 1/sqrt(x) (about 3.05e-5, the ClassicSimilarity value) and an ordinary, low-ranked hit. Instead lengthNorm's int sum |x-1| + |x-1| wraps negative, so the norm and the score are NaN and the document is never collected (exhaustive collection returns 5,999 of 6,000 matches); because the NaN also makes the postings block's maximum score NaN, default top-k search skips that block and the skip range above it, so search(q, 7) on a 10,000-document index misses three documents that score 1.0 and returns documents that score 0.5 instead. ClassicSimilarity on the same index is correct.",
   "impact_class": "silent wrong results",
   "introduced_commit": "d2b63d328be030bfd659319cdeea8b3adeb6f10e (LUCENE-577 'SweetSpotSimiliarity', the initial check-in of SweetSpotSimilarity, SVN r409472, mirrored as apache/lucene#1655; no pull request) [read]: the int expression is in the class's first version, so this is not a regression, and every later change to the method (LUCENE-1420 24d76157a06, LUCENE-2912 a01e9cbb861, LUCENE-7730 06a6034d9bc, LUCENE-9570 2cbf261032d) kept it. Today's symptoms became reachable later: 06a6034d9bc (LUCENE-7730, #8781, 7.0.0) moved the NaN from the stored norm byte into the search-time norm table, d276acfbbcb (LUCENE-7854, #8905, 7.0.0) added custom term frequencies (the cheap trigger), and f410df81136 (LUCENE-4198, 8.0.0) added the impacts-based block skipping",
   "introduced_date": "2006-05-25",
   "first_affected_version": "2.0.0 [exec]; 1.9.1 is not affected because SweetSpotSimilarity does not exist there (the probe does not compile) [exec]. The present symptoms start later: NaN score and dropped hit in 7.0.0, skipping of other competitive documents in 8.0.0 [exec]",
   "affected_versions": "Every release from 2.0.0 to 10.6.0 and main a9779ef3c193 and 645d4fe14a20 [exec]; never fixed (SweetSpotSimilarity.java last changed upstream in 7c056ab88c7, #13757, 2024-09-13, a refactor; unchanged at upstream main f7bcc0abd81, branch_10x and branch_10_6; no open PR touches it; read 2026-10-27). [exec] a public-API probe shows the NaN length norm on 18 releases (2.0.0, 2.4.1, 2.9.4, 3.0.3, 3.1.0, 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2) and main; end to end on 11 of them (2.0.0, 2.4.1, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2) and main. Symptoms by era: 2.0.0-6.6.6 the NaN is encoded into the stored norm byte at index time (on this aarch64 host it becomes the largest norm, so the long document ranks first; the x86 outcome, norm 0, is reasoning only); 7.0.0-7.7.3 the score is NaN and the long document is dropped (-ea: Lucene's own collector assertion throws); 8.0.0-10.0.0 top-k also skips competitive documents (-ea: TopScoreDocCollector's 'assert score >= 0' throws first; the distant lost hit depends on the postings format: lost on 8.0.0, 8.11.4 and 9.0.0, found on 9.12.3 and 10.0.0); 10.1.0-10.5.2 and main silent with -ea and -da (the collector assertion was removed by #13939, f8ea1305144): the finder's JUnit fails 6 run / 4 failed. [read] all 144 release tags from 2.0.0 on in the history clone contain the int expression. All runs with JDK 25.0.3 on aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-754.html",
   "repro": "repro/LFV-754/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-661",
   "priority": "low",
   "priority_rank": 901,
   "novelty": "known",
   "withheld": false,
   "area": "suggest / FreeTextSuggester (n-gram counts stored as long FST outputs; lookup-side decode)",
   "title": "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",
   "summary": "You build a FreeTextSuggester from text in which one word occurs more than Integer.MAX_VALUE (2,147,483,647) times and expect lookup to rank that word first with a score near 1.0, because the class javadoc says each result value is Long.MAX_VALUE times a score from 0.0 to 1.0 and build() counts n-grams as long. Instead decodeWeight returns (int) (Long.MAX_VALUE - output), so a count of 2,148,532,224 comes back as -2,146,435,072 and lookup('a', 2) returns [ab score 0.0, a score -0.999]: a negative score, with the most frequent word ranked below a word seen once. The same cast decodes context counts, so every prediction from a context seen that often is scored wrongly, and counts above 2^32 wrap to small positive numbers that stay inside the 0..1 range and are silently wrong.",
   "impact_class": "silent wrong results",
   "introduced_commit": "b50a2edbb2389797a7354775414052df91b108f6 (trunk, svn r1528517, 'LUCENE-5214: add FreeTextSuggester', Michael McCandless (@mikemccand), 2013-10-02) and its same-day branch_4x backport 9494be7ec2ae84e88b6fc07046c35cac15e790d2 (svn r1528521), the commit contained in 4.6.0; issue LUCENE-5214 = apache/lucene#6278, no pull request (Subversion era). Not a regression: the cast 'return (int)(Long.MAX_VALUE - output);' is in the first version of the class [read]; the only later touch, 2cbf261032d (LUCENE-9570, 2021-01-05), changed whitespace only. The same first commit already counts (totTokens, totalTermFreq), encodes (encodeWeight(long) = Long.MAX_VALUE - count, no range check) and stores (writeVLong) counts as long, and decodeWeight is declared to return long. Probable origin [inference from code, not stated anywhere]: the int-weight decoder of the sibling suggesters (WFSTCompletionLookup and AnalyzingSuggester at the parent commit return (int)(Integer.MAX_VALUE - encoded) and reject weights above Integer.MAX_VALUE at encode time).",
   "introduced_date": "2013-10-02",
   "first_affected_version": "4.6.0 [exec] (first release with FreeTextSuggester; 4.5.1 has no such class [exec]; a 4.6.0 control with a count just below 2^31 passes [exec])",
   "affected_versions": "Every release from 4.6.0 through 10.6.0 (10.6.0 by reading) and main a9779ef3c193 (unreleased 11.0); never fixed. [exec] stock-analyzer scale probe fails with identical values on 4.6.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main; the TermFrequencyAttribute JUnit (needs 7.0.0+ API and the 9.x test-framework package) fails on 9.12.3, 10.5.2 and main (-ea and -da on main). [read] all 112 release tags from 4.6.0 through 10.5.2 that contain FreeTextSuggester.java have the cast; upstream main a95c754ee003, branch_10x 657014b3c579 and branch_10_6 4ae946e5a9b9 (2026-10-26) still have it. The trunk commit first shipped in 6.0.0; the 4.x line got it through the backport.",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-5214",
    "https://github.com/apache/lucene/issues/6278",
    "https://github.com/apache/lucene/issues/13390"
   ],
   "doc": "",
   "repro": "repro/LFV-661/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-107",
   "priority": "low",
   "priority_rank": 902,
   "novelty": "new",
   "withheld": false,
   "area": "store / ByteBuffersDataOutput",
   "title": "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",
   "summary": "You copy 2 GiB or more into an in-heap ByteBuffersDataOutput, for example with Directory.copyFrom or IndexWriter.addIndexes(Directory) into a ByteBuffersDirectory. You expect every byte to be copied, as DataOutput.copyBytes(DataInput, long numBytes) promises ('Copy numBytes bytes from input to ourself') and as Lucene 9.2.0 does. Instead the override stores the length in an int, copies max(0, (int) numBytes) bytes (nothing at all for any length from 2^31 to 2^32-1) and returns normally, so the destination file is empty or truncated with no exception; a copied index then fails to open with CorruptIndexException.",
   "impact_class": "data corruption",
   "introduced_commit": "e5bf76b84304 (LUCENE-10657, #1034 'CopyBytes now saves one memory copy on ByteBuffersDataOutput', issue #11693, main), released through its branch_9x backport 7328ad2dafc2 [read]; a regression of an optimisation: the overridden base DataOutput.copyBytes counts down a long",
   "introduced_date": "2022-07-19 (#1034 merged into main; branch_9x backport 7328ad2dafc2 the same day; 9.3.0 release tag dated 2022-07-28)",
   "first_affected_version": "9.3.0 [exec] (first 10.x: 10.0.0 [exec])",
   "affected_versions": "9.3.0 through 10.6.0 (31 releases) and main ea57360912ed: 9.3.0, 9.12.3, 10.0.0, 10.5.2 and main executed with the finder repro (main also with -da), the independent reproduction's repro fails on main, 10.5.2 and 9.12.3 with -ea and -da and on 9.3.0 with -ea [exec]; the other releases by source identity of the method body at every tag 9.3.0..10.5.2 [read]; unaffected: 8.0.0 through 9.2.0 (8.0.0, 8.11.4 and 9.2.0 executed, pass, with a real 2^31+7-byte copy) [exec]; branch_10x, branch_10_6 and branch_9_12 still carry the narrowing line [read], and 10.6.0 (released 2026-10-29) is affected [exec]; not fixed upstream as of main ea57360912ed [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-107.html",
   "repro": "repro/LFV-107/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-186",
   "priority": "low",
   "priority_rank": 903,
   "novelty": "known",
   "withheld": false,
   "area": "codecs / stored fields (Lucene90 compressing writer)",
   "title": "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",
   "summary": "You index a small document and then, before the chunk fills, one document with about 2 GiB of stored content that is within the documented per-document limit, for example exactly 2^31 - 81,920 = 2,147,401,728 serialized bytes after a 49,153-byte document. You expect both to be indexed, as they are when the first document is one byte smaller. Instead flush() steps through the chunk with an int offset that wraps past Integer.MAX_VALUE, ByteBuffersDataInput.slice rejects the negative offset with IllegalArgumentException, and IndexWriter closes itself and drops every uncommitted document.",
   "impact_class": "crash",
   "introduced_commit": "54362bdfc59 (branch_4x, the released copy) / d46bb05fe09 (trunk), LUCENE-5188 'Make CompressingStoredFieldsFormat more friendly to StoredFieldVisitors' (apache/lucene#6252; a JIRA patch, no pull request): it replaced the single compress call in CompressingStoredFieldsWriter.flush with the slice loop 'for (int compressed = 0; ...; compressed += chunkSize)' [read]. It became reachable through the public API with LUCENE-5844 (apache/lucene#6906; 7c771645785 on branch_4x -> 4.10.0, ef7569c5094 -> 4.9.1), which stopped ArrayUtil.grow from asking for byte[Integer.MAX_VALUE] [exec]. LUCENE-10627 (34154736c6e, apache/lucene#987, 2022) rewrote the loop over ByteBuffersDataInput.slice and kept the int variable [read]",
   "introduced_date": "2013-09-04 (trunk) / 2013-09-05 (branch_4x); first release containing the loop 4.5.0 (2013-10-02); reachable from LUCENE-5844 (2014-07-23)",
   "first_affected_version": "4.10.0 (2014-09-02) and the 4.9.1 bugfix release (2014-09-21) [exec]; 4.5.0-4.9.0 contain the loop but an earlier OutOfMemoryError while buffering a ~2 GiB value masks it [exec]",
   "affected_versions": "4.9.1 and 4.10.0 through 10.5.2, and main ea57360912ed. [exec] the follow-up's version-portable public-API history probe (default codec; control = a chunk of exactly (Integer.MAX_VALUE / chunkSize) * chunkSize bytes with a document at the documented limit, then one more earlier byte, then a document one byte below the limit) finds the boundary at exactly that size on 4.9.1, 4.10.0, 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.6.3, 8.7.0, 8.9.0, 8.10.0, 8.11.4, 9.0.0, 9.3.0, 9.4.0, 9.12.3, 10.0.0, 10.5.2 and main (13 runs with -da and 7 with FSDirectory also affected); the finder's JUnit fails on main (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails on main (-ea, -da, two seeds), 10.5.2 and 9.12.3. Releases in between were not run; they contain the same int loop [read]. With the 16 KiB chunks of 4.x-8.6 a document at the documented limit fails after any earlier stored document in its chunk (2 bytes suffice) [exec]. The symptom changes by era: ArrayIndexOutOfBoundsException under LZ4 (4.9.1-7.x); on 7.5-8.4 with ByteBuffersDirectory, an AssertionError with -ea and an addDocument that does not return with -da (still in the flush loop after 120 s) [exec]; IndexOutOfBoundsException from LZ4.compress (8.5-8.6); AssertionError or ArrayIndexOutOfBoundsException in the preset-dictionary compressor (8.7-9.3); IllegalArgumentException from ByteBuffersDataInput.slice (9.4.0-main). Not affected through the API: 4.4.0 and older (no slice loop) and 4.5.0-4.9.0 (masked) [exec]. Not fixed: the loop is unchanged on upstream main and in every open PR [read]. All runs on JDK 25, Linux aarch64; x86 not run.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/6907",
    "https://issues.apache.org/jira/browse/LUCENE-5845",
    "https://github.com/apache/lucene/issues/8589",
    "https://issues.apache.org/jira/browse/LUCENE-7538",
    "https://github.com/apache/lucene/issues/16480",
    "https://github.com/apache/lucene/issues/16690"
   ],
   "doc": "",
   "repro": "repro/LFV-186/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1150",
   "priority": "low",
   "priority_rank": 904,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / compressing (Compressor.compress in CompressionMode FAST, FAST_DECOMPRESSION, HIGH_COMPRESSION and the Lucene90 preset-dict compressors)",
   "title": "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",
   "summary": "You build a valid ByteBuffersDataInput of 2^32 + k bytes (here 4097 views of one 1 MiB buffer, so nothing is copied) and call CompressionMode.FAST.newCompressor().compress(in, out); you expect the whole input to be compressed, or an exception if it is too large. Instead compress returns normally after reading and compressing only the first k bytes (1 MiB of 4,296,015,872), leaving the input positioned at k, and the block it wrote decodes to just that prefix. All five core compressors start with 'final int len = (int) buffersInput.length()' (or length() - position() in the preset-dict modes), and for a length of 2^32 + k that cast yields k.",
   "impact_class": "minor",
   "introduced_commit": "34154736c6ed241d7d9d0c6f4a0e6419936490b7 (LUCENE-10627, apache/lucene#987 'Using ByteBuffersDataInput reduce memory copy on compressing data', author luyuncheng, merged by jpountz; branch_9x copy 2b75fe6d2005785e5214364a0563fdcba5d66c50) [read]",
   "introduced_date": "2022-08-01 (author date 2022-08-02 00:34:41 +0800, that is 2022-08-01 16:34 UTC; merged 2022-08-01; branch_9x commit 2022-08-01)",
   "first_affected_version": "9.4.0 [exec]",
   "affected_versions": "9.4.0 to 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT). Executed, fail [exec]: main with -ea and -da (finder, the independent reproduction, the intended-behaviour check, judge and the registration check), 10.6.0, 10.5.2, 10.0.0 (finder, history step), 9.12.3 (the independent reproduction, history step) and 9.4.0 (-ea and -da, with the test's two length() calls written as size(), the only length accessor before 9.9.0). Not affected: 9.3.0 and older (the API is absent). The other releases by reading: no commit between 9.4.0 and 10.6.0 changes the casts beyond the size() to length() rename. Not new in 10.6 (since 9.4.0). Not fixed upstream: upstream main 1c2072f0284 (2026-11-02) still has the three casts in CompressionMode.java (lines 160, 182, 268). All runs on Linux aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1150.html",
   "repro": "repro/LFV-1150/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-163",
   "priority": "low",
   "priority_rank": 905,
   "novelty": "known",
   "withheld": false,
   "area": "codecs / stored fields (Lucene90StoredFieldsFormat javadoc vs Lucene90CompressingStoredFieldsFormat)",
   "title": "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)",
   "summary": "You read the default codec's stored-fields documentation (Lucene90StoredFieldsFormat, 'Known limitations'), which says only individual documents larger than 2^31 - 2^14 = 2,147,467,264 bytes are unsupported, and you index a document of 2,147,403,644 serialized bytes, below that limit, right after a small document. addDocument fails with ArithmeticException ('integer overflow') and IndexWriter closes itself, while the same big document on its own is indexed. The writer does what the class it delegates to, Lucene90CompressingStoredFieldsFormat, documents (at most 2^31 - chunkSize bytes, with chunks of 81,920 or 491,520 bytes today); the outer javadoc's number was right only when chunks were 16 KiB and was never updated.",
   "impact_class": "minor",
   "introduced_commit": "66745d3ce7f (trunk) / 6e5b1f4dc9b (branch_5x backport, the released copy), LUCENE-5914 'More options for stored fields compression' (GitHub #6976; svn era, no pull request): added Lucene50StoredFieldsFormat.Mode with a BEST_COMPRESSION chunk larger than 2^14 (24,576, then 61,440 by LUCENE-6100, 284e77c02d7 / 14fc39fdbea, before 5.0.0) and copied the 2^31 - 2^14 sentence unchanged [read]; stale for the default BEST_SPEED mode from 27aa5c5f59e (master) / 4cedd92dee0 (branch_8x), LUCENE-9486 apache/lucene-solr#1793 (chunk 610,304, then 614,400 by LUCENE-9525) [read]; Lucene90StoredFieldsFormat inherited the sentence when 144ef2a0c05 (LUCENE-9705, apache/lucene-solr#2444) created it; f1fdd2465c0 (LUCENE-9917, apache/lucene#257) set today's 81,920-byte BEST_SPEED chunk and a9480316e28 / e63222ce6f5 (apache/lucene#12984) rewrote the chunk-size prose of the same javadoc but kept the limit [read]. The sentence itself comes from da6d1ed228c / 0f8ee42a944 (LUCENE-4509, GitHub #5575), when the chunk was 1 << 14 and the value was exact [read]",
   "introduced_date": "2014-12-06 (LUCENE-5914, stale for BEST_COMPRESSION); 2020-09-03 (LUCENE-9486, stale for the default mode); the sentence was written 2012-11-13 (LUCENE-4509) and was correct then",
   "first_affected_version": "5.0.0 [exec] for BEST_COMPRESSION (Lucene50StoredFieldsFormat); 8.7.0 [exec] for the default BEST_SPEED mode (Lucene87StoredFieldsFormat); 9.0.0 [exec] for Lucene90StoredFieldsFormat (it does not exist before 9.0.0)",
   "affected_versions": "Lucene90StoredFieldsFormat, both modes: 9.0.0 to 10.5.2 and main ea57360912ed. [exec] the follow-up's version-portable history main() (public API, default mode, 80,004 + 2,147,403,644 serialized bytes, control = the big document alone) fails on 9.0.0, 9.12.3, 10.5.2 and main (-ea and -da); the finder's JUnit fails on main (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit (both modes, controls pass) fails 2 of 4 on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's runs fail on main (-ea and -da) and 10.5.2, and its BEST_COMPRESSION main() fails on main; the follow-up re-run fails on main (-ea and -da); all on JDK 25, also for older releases. Predecessor formats with the same stale sentence: Lucene50StoredFieldsFormat 5.0.0-8.6.3, BEST_COMPRESSION only [exec]; Lucene87StoredFieldsFormat 8.7.0-8.11.4, both modes [exec]. Not affected by this root cause: 4.1.0-4.10.4 and BEST_SPEED before 8.7.0, where the chunk was 2^14 bytes [exec], although the separate slice-loop overflow (a hunt unit candidate storedfields-slice-loop-int-overflow) already failed there within 16,383 bytes of the stated limit [exec]. Sentence presence read at 5.0.0, 6.6.6, 7.7.3, 8.6.3, 8.7.0, 8.11.4, 9.0.0, 9.10.0, 9.12.3, 10.0.0, 10.5.2 and main; other releases inferred from the unchanged files [read]. Not fixed: the text is unchanged on upstream main (head ea57360912ed at the 2026-10-26 search) and no open PR changes it [read]; other branches not checked.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/6907",
    "https://issues.apache.org/jira/browse/LUCENE-5845",
    "https://github.com/apache/lucene/issues/12984",
    "https://github.com/apache/lucene/issues/5597",
    "https://issues.apache.org/jira/browse/LUCENE-4531",
    "https://github.com/apache/lucene/issues/16660"
   ],
   "doc": "",
   "repro": "repro/LFV-163/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-285",
   "priority": "low",
   "priority_rank": 906,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter addIndexes(CodecReader...) (addIndexesReaderMerge merged view: SlowCompositeCodecReaderWrapper over a MultiReader, BaseCompositeReader doc limit)",
   "title": "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)",
   "summary": "You call IndexWriter.addIndexes(CodecReader...) with readers that have many deleted or filtered-out documents, so their live documents fit under IndexWriter.MAX_DOCS but their maxDoc() values (deleted documents included) add up to more. You expect the call to succeed, since addIndexes counts and reserves only live documents, its javadoc throws IllegalArgumentException only if the index would exceed MAX_DOCS, and 9.8.0 accepted the same call. Instead, with the default configuration it throws IllegalArgumentException 'Too many documents: composite IndexReaders cannot exceed ...' and adds nothing, because since 9.9.0 addIndexesReaderMerge always wraps the inputs in a SlowCompositeCodecReaderWrapper (a MultiReader over the uncompacted inputs) for OneMerge#reorder, whose default returns null and discards the view.",
   "impact_class": "wrong error",
   "introduced_commit": "f7cab1645017d863331b42900581b67d3591e2da on main and its branch_9x backport 6b1538b33136a4737ad0d22b3633e62f3d7f362b, PR #12622 'Add a merge policy wrapper that performs recursive graph bisection on merge.' (jpountz): it added SlowCompositeCodecReaderWrapper and OneMerge#reorder and made addIndexesReaderMerge build the merged view whenever no index sort is configured [read]",
   "introduced_date": "2023-11-23 (f7cab1645017 on main and the branch_9x backport 6b1538b3313, same day)",
   "first_affected_version": "9.9.0 [exec] (tagged 2023-12-04, through the branch_9x backport 6b1538b3313; fails with -ea and -da); on the 10.x line 10.0.0 [exec]; 9.8.0 is the last unaffected release [exec]",
   "affected_versions": "Every release from 9.9.0 through 10.6.0 (23 releases: 9.9.0-9.9.2, 9.10.0, 9.11.0, 9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2, 10.6.0) and main ea57360912ed [exec]; at full scale with no test hook (inputs' maxDoc sum 2^31, 2048 live documents) main and 10.5.2 fail and 9.8.0 passes [exec]. Not affected: 8.11.4, 9.0.0, 9.7.0 and 9.8.0 [exec]; every release from 5.0.0 to 9.8.0 by reading (no merged view before #12622). Not fixed upstream: no later commit touches the defect code on main (head e1c4184cb98, 2026-10-26) or branch_10x [read]; 10.6.0 (released 2026-10-29): the minimal test fails on the 10.6.0 release jars (SHA-1 checked against Maven Central) with -ea and -da [exec]. All runs on aarch64 Linux, JDK 25 (plain Java logic, no vector code).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-285.html",
   "repro": "repro/LFV-285/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-531",
   "priority": "low",
   "priority_rank": 907,
   "novelty": "new",
   "withheld": false,
   "area": "misc / index tools (MultiPassIndexSplitter.split, round-robin mode)",
   "title": "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",
   "summary": "You split an index of IndexWriter.MAX_DOCS (2,147,483,519) documents with MultiPassIndexSplitter in round-robin mode, the command-line default, into 145 parts, and expect every document in exactly one part (part i gets the documents whose id j has j % numParts == i), as the split javadoc says: ids are 'assigned in a deterministic round-robin fashion to one of the output splits'. Instead the parts hold 2,147,483,527 documents in total: documents 2,147,483,511..518 belong to parts 16..23 but are also copied into parts 0..7, and with 149 parts documents 2,147,483,509..518 end up in no part at all; nothing reports an error. The cause is the keep test (j + numParts - i) % numParts == 0 at MultiPassIndexSplitter.java:103, computed in int: for the top doc ids j + numParts - i wraps negative and Java's % keeps the sign, while the equivalent j % numParts == i cannot overflow.",
   "impact_class": "data corruption",
   "introduced_commit": "7d0d4ecc44c6acb60ac3cc0dbf9dc2c18d7497de (svn r824798, 'LUCENE-1959 Add MultiPassIndexSplitter.'; JIRA LUCENE-1959 'Index Splitter', mirrored as apache/lucene#3034; pre-GitHub, no PR) [read]",
   "introduced_date": "2009-10-13",
   "first_affected_version": "3.0.0 (2009-11-25, the first release with the class) [exec]; not affected: 2.9.x and earlier, where the class does not exist [exec]",
   "affected_versions": "every release from 3.0.0 to 10.6.0, plus main ea57360912ed and 645d4fe14a20; 3.0.0 (-da) with a 3.x port: +8 at 2,147,483,519 docs and 145 parts, +1 (-ea and -da) and -5 at 2,147,483,645 docs with 6 and 10 parts; the minimal test (part 0 of 145 holds 14,810,233 documents, expected 14,810,232) fails on the 10.6.0 release jars (SHA-1 checked, -da) and through gradle on main 645d4fe14a20 (-ea and -da) [exec]. [read] the source line is byte-identical at all 133 release tags 3.0.0..10.5.2 of the release-tag clone, and the same int bytecode (iadd, isub, irem) is in split() of the released misc jars of 3.0.0, 3.0.3, 3.6.2, 4.0.0, 4.9.0, 4.10.0, 5.5.5, 6.6.6, 7.7.3, 8.0.0, 8.8.2, 8.11.4, 9.0.0, 9.12.3, 10.0.0 and 10.5.2; releases between 3.0.0 and 9.12.3 were not executed. Reach by era: 3.0.0-4.9.0 accept inputs up to Integer.MAX_VALUE docs, so small part counts fail too near 2^31 (the largest input 3.0.0 could split on this JVM was 2,147,483,645 docs); from 4.9.1/4.10.0 on, IndexWriter.MAX_DOCS = 2^31 - 129 (LUCENE-5843) leaves only part counts of 145 or more",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-531.html",
   "repro": "repro/LFV-531/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1140",
   "priority": "low",
   "priority_rank": 908,
   "novelty": "new",
   "withheld": false,
   "area": "index / index sorting at merge: IndexSorter.StringSorter merge keys (MultiSorter), reached through IndexWriter.addIndexes(CodecReader...)",
   "title": "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",
   "summary": "You configure the index sort new SortField(\"s\", SortField.Type.STRING, false, SortField.STRING_LAST) and merge, with IndexWriter.addIndexes(CodecReader...), sorted source indexes whose 's' dictionaries together hold more than 2^31 - 1 distinct values, expecting documents without a value to come after every document with one, as STRING_LAST and the in-segment comparator promise. At merge, IndexSorter.StringSorter gives a document with a value its long global ordinal (from an OrdinalMap over every input's full dictionary, deleted documents' values included) but gives a document without a value the int key Integer.MAX_VALUE, so every value whose global ordinal is above 2^31 - 1 sorts after the missing documents (a value at exactly 2^31 - 1 gets the same key as they do). The merged segment is written out of its declared sort with no error: in an end-to-end addIndexes(CodecReader...) test over two one-live-document segments whose dictionaries a FilterCodecReader enlarges to 2^30 + 1 terms each, the document without a value ends up at doc 0.",
   "impact_class": "data corruption",
   "introduced_commit": "17f2f96a5cf8e0001a81b9327c2ddced053e6934 on master and its branch_8x copy aad4b411cdd2d517328a2444147b407d4a38343d (the one that shipped first, in 8.2.0), 'LUCENE-8900: Simplify MultiSorter' (a JIRA patch, migrated as apache/lucene#9943, no pull request; by jpountz, +1 from danmuzi). In MultiSorter#getComparableProviders, case STRING, the merge key became a long and 'return Math.toIntExact(globalOrds.get(readerValues.ordValue()))' became 'return globalOrds.get(readerValues.ordValue())', while 'final int missingOrd = Integer.MAX_VALUE' (STRING_LAST) / Integer.MIN_VALUE stayed, so a global ordinal of 2^31 - 1 or more now silently reaches the missing key instead of throwing. The toIntExact guard came from LUCENE-8592 (9f29ed0757e, 2018, #9638); the int sentinel dates from LUCENE-6766 (231cb3eb42e, 2016); LUCENE-9330 (de2bad90390 / ad0cefb8ec2, 2020) moved the code unchanged into IndexSorter.StringSorter, which is what git blame shows on main. [read]",
   "introduced_date": "2019-07-09 (author date of 17f2f96a5cf and aad4b411cdd)",
   "first_affected_version": "8.2.0 [exec] (the first release with LUCENE-8900: the MultiSorter probe merges the document without a value ahead of the largest value). 8.1.1 and 7.6.0 throw ArithmeticException on the same input (Math.toIntExact from LUCENE-8592), a loud failure, not this bug [exec]; 7.0.0-7.5.0 narrow the global ordinal with an (int) cast instead, a different defect [read]; 6.2.0-6.6.x fail loudly ('Too many documents') [read]",
   "affected_versions": "8.2.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 5adff78bb168 (12.0.0-SNAPSHOT). Executed (fail): main with -ea and -da; 10.6.0 (the finder's test with -da, and the independent reproduction's test with -da at the registration check); 10.5.2 (the independent reproduction, -da); 9.12.3 (the finder and the independent reproduction, -da); 9.0.0, 8.11.4 and 8.6.0 (the finder's test, pre-9.1 test-framework copy); 8.5.2 and 8.2.0 (the MultiSorter probe). Inferred [read]: 8.8.2 to 8.11.3. Not affected: 7.6.0 to 8.1.1 throw ArithmeticException instead [exec]; 7.0.0-7.5.0 have a different (int)-truncation defect [read]; 6.2.0-6.6.x fail loudly [read]. Not new in 10.6 (10.5.2 and 9.12.3 fail). Not fixed upstream: upstream main 1c2072f0284 (author date 2026-11-02) still has the int sentinel; the last upstream commit on IndexSorter.java is e6f12f31d08 (#16202, author date 2026-06-05), and no open PR touches IndexSorter.java.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1140.html",
   "repro": "repro/LFV-1140/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-147",
   "priority": "low",
   "priority_rank": 909,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / live docs (Lucene90LiveDocsFormat) and index / CheckIndex live-docs check",
   "title": "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+)",
   "summary": "You index IndexWriter.MAX_DOCS (2,147,483,519) documents into one segment with the default IndexWriterConfig and codec, delete one of them by term and call commit(); you expect the deletion to be saved. Instead commit() throws 'ArrayIndexOutOfBoundsException: Index -3 out of bounds for length 16' ('AssertionError: startIndex=-129, numBits=1024' with -ea) and close() throws it again, because Lucene90LiveDocsFormat.writeBits copies the live docs in 1024-bit batches with 'for (int offset = 0; offset < bits.length(); offset += copy.length())': after the batch at 2^31-1024 the offset wraps to Integer.MIN_VALUE, which is still below the length, so the next batch clears a negative range. CheckIndex.bitsCardinality has the same loop, so on 10.3.0 and later CheckIndex (level 2 or higher) also reports the valid live docs of such a segment as an error; only segments with more than 2,147,482,624 documents are affected.",
   "impact_class": "crash",
   "introduced_commit": "039e7874f7c8 (apache/lucene#15045 'Use FixedBitSet#cardinality for counting liveDocs in CheckIndex', by easyice, merged on main 2025-08-27, branch_10x backport 97740fc27c65; the CheckIndex half, first released in 10.3.0) and 2550eb2a72a6 (apache/lucene#14998 'Speed up flushing of live docs.', by jpountz, opened 2025-07-28, merged on main 2025-09-05, branch_10x backport ece138c3445f; the writer half, first released in 10.4.0) [read]; a regression in both places: the loops these PRs replaced (a per-bit count in CheckIndex, a per-word writer loop) cannot overflow at MAX_DOCS",
   "introduced_date": "2025-08-27 (#15045, CheckIndex half); 2025-09-05 (#14998, writer half)",
   "first_affected_version": "10.3.0 [exec] (CheckIndex half, #15045); the writer half first ships in 10.4.0 [exec] (#14998); 10.2.2 is the last release without either [exec]",
   "affected_versions": "CheckIndex half: 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2, 10.6.0 (by reading) and main [exec]; writer half: 10.4.0, 10.5.0, 10.5.1, 10.5.2, 10.6.0 (by reading) and main [exec]; 10.3.x still writes such .liv files correctly, but its own CheckIndex flags them [exec]; not affected: 9.x and 10.0.0 to 10.2.2 [exec]; both loops are still on upstream main, branch_10x, branch_10_6, branch_10_5 and branch_10_4, and branch_10_3 has the CheckIndex loop only (read-only GitHub API, 2026-10-26); executed on aarch64 Linux with JDK 25 only (pure int arithmetic)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-147.html",
   "repro": "repro/LFV-147/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-170",
   "priority": "low",
   "priority_rank": 910,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / postings reader (Lucene104 BlockPostingsEnum#docIDRunEnd, also the Lucene101 and Lucene103 readers); index / CheckIndex",
   "title": "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",
   "summary": "You have one segment of about 2^31 documents (within about 8,000 docs of IndexWriter.MAX_DOCS) with a term whose postings are dense near the end of the doc-ID space, for example a term that every document has, and you call docIDRunEnd() on its postings or run CheckIndex at level 2 or higher. You expect docIDRunEnd() to return a doc ID greater than the current one, as its javadoc promises, and CheckIndex to pass. Instead, in the dense blocks after the term's last full 8,192-doc level-1 skip block (4,096 docs in 10.2-10.3), the default postings reader returns Integer.MIN_VALUE and CheckIndex reports the healthy segment as corrupt ('Run end -2147483648 is <= doc ID 2147475456'); query results stay correct, and the repro writes the postings through the public codec API rather than indexing 2^31 documents with IndexWriter.",
   "impact_class": "wrong error",
   "introduced_commit": "db00348ef18e3a8090bdab478bdc525f8297d8b9 (main) and its branch_10x backport 6bef45756a96df61cf9c8b34644327b53d651330, PR #14390 'Implement #docIDRunEnd() on PostingsEnum.' (author and merger jpountz, approved by gf2121), which added the level1IsDense shortcut to Lucene101PostingsReader without excluding the NO_MORE_DOCS level-1 sentinel; copied verbatim into Lucene103PostingsReader by #14693 (06afbe701640, 10.3.0) and kept by #15160 (00f2b01e7985, Lucene104 with 256-doc blocks, 10.4.0) [read]; the sentinel state itself (level1DocCountUpto advanced by a full block, level1LastDocID = NO_MORE_DOCS) comes from #13585 (b4a8810b7ae, 9.12.0) and was harmless before #14390 [exec]",
   "introduced_date": "2025-03-24 (merged on main; branch_10x backport the same day)",
   "first_affected_version": "10.2.0 [exec] (10.1.0 is the last unaffected release: DocIdSetIterator#docIDRunEnd, #14312, first shipped in 10.2.0 [exec])",
   "affected_versions": "10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2, 10.6.0 and main ea57360912ed (-ea and -da). [exec] 10.6.0 release jars (SHA-1 checked against Maven Central): the minimal test fails with -ea and -da and the version-spanning probe fails with -ea. [exec] the follow-up's version-spanning probe fails on all 10 releases and main; the independent reproduction's repro fails on 10.2.0, 10.3.2, 10.4.0, 10.5.2 and main; the finder's on 10.4.0, 10.5.2 and main; window: the last 4,096 doc IDs below 2^31 for Lucene101/103 (10.2.x-10.3.x, failing doc 2147479552), the last 8,192 for Lucene104 (10.4.0 on, failing doc 2147475456). [read] the unreleased branch_10x and branch_10_6 and the backward-codecs Lucene101 and Lucene103 readers on main (which read 10.2.x and 10.3.x indexes) have the identical expression. Not fixed upstream: main, branch_10x and branch_10_6 heads still unguarded (read-only check, 2026-10-26).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-170.html",
   "repro": "repro/LFV-170/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-137",
   "priority": "low",
   "priority_rank": 911,
   "novelty": "new",
   "withheld": false,
   "area": "util / FixedBitSet growth (ensureCapacity) and index / DocsWithFieldSet (doc-values and norms flush)",
   "title": "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",
   "summary": "You index into one segment until doc IDs pass about 1.91 billion (legal: IndexWriter.MAX_DOCS is 2^31-129) with a doc-values or norms field that only some documents have, then commit; you expect every indexed value to be in the segment. Instead, when the field's DocsWithFieldSet grows its FixedBitSet to the new doc ID, FixedBitSet.ensureCapacity computes the new length as arr.length << 6 in int arithmetic, which wraps negative once the backing array has 2^25 words, so the set's iterator returns no document although cardinality() counts them, and the flushed segment has no document with a value for that field (with -da; with -ea addDocument throws ArrayIndexOutOfBoundsException for that document). The same call on a small set, ensureCapacity(new FixedBitSet(64), 2_000_000_000), returns a set with length() = -2,044,967,232; the twin LongBitSet.ensureCapacity had the identical overflow and was fixed in 2015 (LUCENE-6409), but FixedBitSet was not.",
   "impact_class": "data corruption",
   "introduced_commit": "b872f4b5c3c5 (LUCENE-5440, migrated as apache/lucene#6503 'Add LongFixedBitSet and replace usage of OpenBitSet', by shaie, svn r1566662 on trunk; same-day branch_4x backport bc1797f526ae, svn r1566670) added FixedBitSet.ensureCapacity with the line 'return new FixedBitSet(arr, arr.length << 6);' during review (mikemccand asked for an ensureCapacity so the doc-values writers could grow a FixedBitSet; the same commit switched NumericDocValuesWriter and BinaryDocValuesWriter to it) [read]; later commits kept the shift: 69af3beaed8 / 84820b04187 (LUCENE-6409, #7469, 2015-04-13, fixed the same overflow in LongBitSet and touched FixedBitSet.bits2words only), 701b7ddf3a2 / 8ea0408615c (LUCENE-6427, #7486, 2015-04-28, added the ghost-bit assertion that throws under -ea), 59df9e799ce (#15582, 2026-01-16, moved the line into ensureCapacityInternal, shared with the new ensureCapacityAndClear)",
   "introduced_date": "2014-02-10 (LUCENE-5440 committed on trunk and backported to branch_4x the same day)",
   "first_affected_version": "4.7.0 [exec]; 4.6.1 and older have no FixedBitSet.ensureCapacity (compile error) [exec]",
   "affected_versions": "every release from 4.7.0 through 10.6.0 and main ea57360912ed. The unit witness (ensureCapacity(new FixedBitSet(64), 2e9) returns length() = -2044967232 under -da; the 1.9e9 control passes) is executed and failing on 4.7.0, 4.10.4, 5.0.0, 5.1.0, 5.2.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main [exec]; all 110 release tags from 4.7.0 to 10.5.2 in the history clone carry the identical line (the clone lacks the 8.8.2-8.11.4 tags; 8.11.4 executed, and 8.8.2, 8.9.0, 8.10.0, 8.10.1, 8.11.0, 8.11.1, 8.11.2 and 8.11.3 executed on the release jars on 2026-10-31, -da) [read]. The DocsWithFieldSet symptom (cardinality 3, empty iterator) needs DocsWithFieldSet (7.0.0, LUCENE-7545) and is executed on 7.0.0, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main [exec]; whether a 4.7.0-6.6.6 flush at this scale loses values was not executed and is not claimed. The end-to-end silent loss is executed on main only. Under -ea, 4.7.0-5.1.0 return the negative length silently; from 5.2.0 the ghost-bit assertion (LUCENE-6427) throws ArrayIndexOutOfBoundsException [exec]. Upstream main, branch_10x, branch_10_6 and branch_9_12 still have the line (2026-10-26) [read], and on 10.6.0 (released 2026-10-29) the minimal test fails on the release jars (SHA-1 checked against Maven Central) with -ea and -da [exec]; branch_9x not checked; not fixed upstream [read]; executed on aarch64 Linux with JDK 25 (64-bit JVM) only",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-137.html",
   "repro": "repro/LFV-137/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-143",
   "priority": "low",
   "priority_rank": 912,
   "novelty": "new",
   "withheld": false,
   "area": "util / VectorUtil byte DOT_PRODUCT score x internal/vectorization / Panama MemorySegment byte scorers",
   "title": "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",
   "summary": "You score two byte vectors of 65,536 dimensions with VectorSimilarityFunction.DOT_PRODUCT (or VectorUtil.dotProductScore, or run a KnnByteVectorQuery on a byte DOT_PRODUCT field indexed through a format that raises getMaxDimensions) and expect the documented score 0.5 + dot / (len * 2^15): within [0, 1] and higher for more similar vectors. Instead the divisor len * (1 << 15) is multiplied in int before the cast to float, so from 65,536 dimensions it wraps to a negative number and every score is mirrored around 0.5: a vector identical to an all-ones query scores 0.49996948 and its opposite 0.5000305, and kNN returns the documents in exactly reverse order. At 131,072 dimensions the divisor wraps to 0 and the scores are +Infinity, -Infinity or NaN.",
   "impact_class": "silent wrong results",
   "introduced_commit": "a693fe819b04 (LUCENE-10577, apache/lucene#1054 'enable quantization of HNSW vectors to 8 bits', by msokolov, merged on main 2022-08-10; branch_9x backport 87a8f7d48f3d) added VectorUtil.dotProductScore with the denominator (float) (a.length * (1 << 15)), multiplied in int [read]; 798c02dd70d (#1073, 2022-08-20, an offset fix) wrote today's 'float denom = (float) (a.length * (1 << 15))' and kept the int product; 45944002161 (#12102) changed only the signature; the same int expression was copied into the Panama graph-build scorer by 05f04aa08a4 (#13339, 2024-05-21; 9.x #13402) and into the Panama query-time scorer by b3f4011292c (#14874, 2025-07-29; 10.x backport #15010), which replaced a correct long product (query.byteSize()) there",
   "introduced_date": "2022-08-10 (a693fe819b0 on main; branch_9x backport committed 2022-08-24); Panama graph-build scorer 2024-05-21 (#13339); Panama query-time scorer 2025-07-29 (#14874)",
   "first_affected_version": "9.4.0 [exec] (VectorUtil / VectorSimilarityFunction path); the Panama query-time scorer from 10.3.0 [exec]; 9.3.0 and older do not have the API [exec]",
   "affected_versions": "VectorUtil.dotProductScore / VectorSimilarityFunction.DOT_PRODUCT byte path: every release from 9.4.0 to 10.6.0 (30 release tags) and main ea57360912ed (unreleased 11.0) [exec]; Panama graph-build scorer (Lucene99MemorySegmentByteVectorScorerSupplier, int product): 9.11.0 to 10.6.0 and main [read]; Panama query-time scorer (Lucene99MemorySegmentByteVectorScorer): long product, correct, in 9.11.0-10.2.2 [exec], int product from 10.3.0 to 10.5.2, 10.6.0 (by reading) and main [exec]; so with Panama on MMapDirectory the kNN query scores through a high-dimension format were correct in 9.11.0-10.2.2 (the graph-build supplier already had the int product there; its effect on graph quality was not measured) and wrong from 10.3.0, while the default provider is wrong in every release from 9.4.0; indexing such fields through a non-stock format is possible only from 9.8.0, when #12436 made the limit codec-defined [read]; 9.3.0 and older are not affected (no API) [exec]; not fixed: upstream main, branch_10x, branch_10_6 and branch_9_12 still have the int expression (2026-10-26) [read]; executed on aarch64 Linux with JDK 25 only (pure int arithmetic, platform-independent)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-143.html",
   "repro": "repro/LFV-143/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-138",
   "priority": "low",
   "priority_rank": 913,
   "novelty": "known",
   "withheld": false,
   "area": "util / byte-vector similarity kernels (VectorUtil, both vectorization providers)",
   "title": "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",
   "summary": "You call VectorUtil.squareDistance, uint8SquareDistance or cosine on two equal-length byte vectors, or score them with VectorSimilarityFunction.EUCLIDEAN or COSINE, at a dimension below the 'will not overflow if dim < 2^18' bound (or 'dim < 2^16' for uint8) that the code comments in DefaultVectorUtilSupport state. You expect the exact sum of squared differences, cosine(v, v) = 1, and closer vectors to score higher. Instead every provider (scalar and Panama) adds up in a 32-bit int that wraps: from 33,026 dimensions the squared distance comes back negative (-2,147,451,646 instead of 2,147,515,650), from 131,072 dimensions cosine(v, v) is -1.0, and at 66,052 dimensions EUCLIDEAN scores the farthest possible vector above an adjacent one.",
   "impact_class": "minor",
   "introduced_commit": "a693fe819b04 on main (branch_9x 87a8f7d48f3d), PR #1054 'LUCENE-10577: enable quantization of HNSW vectors to 8 bits' (msokolov; issue #11613), for the signed-byte kernels cosine / squareDistance / dotProduct with int accumulators and the 'dim < 2^18' comment; ef9128ffe058 on main (branch_10x 66353c55a770), PR #15148 'Add support for uint8 distance comparison' (mccullocht), for uint8SquareDistance / uint8DotProduct and the 'dim < 2^16' comment [read]",
   "introduced_date": "2022-08-10 (signed-byte kernels, #1054); 2025-09-05 (uint8 kernels, #15148)",
   "first_affected_version": "9.4.0 [exec] for the signed-byte kernels (9.3.0 has none [exec]); 10.4.0 [exec] for uint8SquareDistance / uint8DotProduct (10.3.2 has none [exec])",
   "affected_versions": "signed-byte kernels: every release 9.4.0-9.12.3 and 10.0.0-10.6.0 (10.6.0 by reading), and main ea57360912ed; uint8 kernels: 10.4.0-10.6.0 (10.6.0 by reading) and main. Executed failing (seed DEADBEEF, last-safe-dimension controls passing): 9.4.0 (-ea, -da), 9.4.2, 9.5.0, 9.6.0, 9.7.0, 9.12.3, 10.0.0, 10.3.2, 10.4.0, 10.5.2 (-ea, -da) and main (-ea, -da; Panama 256-bit, Panama 128-bit and the default scalar provider); the other releases by tag containment and git grep of the comment on every tag [read]. Not affected: 9.3.0 and earlier (no byte kernels) [exec]. Panama in 9.7.0-10.2.x not executed (those releases do not enable it on JDK 25; their byte bodies also sum in int lanes [read]). Not fixed upstream: the comments are unchanged on main, branch_10x, branch_10_6 and branch_9_12 (2026-10-26) [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/913",
    "https://github.com/apache/lucene/issues/1054",
    "https://github.com/apache/lucene/issues/12694",
    "https://github.com/apache/lucene/issues/16200",
    "https://github.com/apache/lucene/issues/16790",
    "https://github.com/apache/lucene/issues/12306"
   ],
   "doc": "",
   "repro": "repro/LFV-138/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-390",
   "priority": "low",
   "priority_rank": 914,
   "novelty": "new",
   "withheld": false,
   "area": "core vectorization + misc native C / opt-in native int8 dot product (NativeVectorUtilSupport, lucene/misc/src/c/dotProduct.c vdot8s_sve)",
   "title": "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",
   "summary": "You enable Lucene's opt-in native dot product (-Dlucene.useNativeDotProduct=true plus a library built from the example lucene/misc/src/c/dotProduct.c) on an SVE machine and call VectorUtil.dotProduct(byte[], byte[]) on two legal arrays of 2,147,483,645 bytes whose exact dot product is 3, expecting 3 as the Panama and default providers return. Instead the SVE kernel vdot8s_sve keeps its loop index and vector length in int32_t, so its loop test 'i + 4 * vec_length <= limit' (dotProduct.c:66) overflows once i reaches 2^31 - 4*VL (VL = SVE vector length in bytes); in the compiled code the bound wraps negative while the load offset is a 64-bit register, so the loop keeps loading past the end of both arrays until it hits an unmapped page and the JVM dies with SIGSEGV in vdot8s_sve. Every length from 2^31 - 4*VL up to the JVM maximum crashes (2,147,483,520 at 256-bit SVE, 2,147,483,584 at 128-bit SVE), while one element less returns the exact result; a 64-bit loop index with svwhilelt_b8_s64 fixes it.",
   "impact_class": "crash",
   "introduced_commit": "50dac9063104d798c795f4ab23de44c871272bad on main (apache/lucene#15508 'Use native vectorization in Lucene', opened and merged by GitHub shubhamvishu) [read] [exec]. The commit added the whole native path (provider, flag, C file), so the bug is as old as the feature, not a later regression",
   "introduced_date": "2026-02-17 (merged 2026-02-17T13:17:54Z; PR opened 2025-12-17)",
   "first_affected_version": "unreleased (11.0.0 would be the first release: CHANGES.txt lists GITHUB#15508 under Lucene 11.0.0; main / 11.0.0-SNAPSHOT since 50dac906310)",
   "affected_versions": "main from 50dac906310 (2026-02-17) to 645d4fe14a2 [exec]; upstream main cf398bfb142 (checked 2026-10-26) has a byte-identical dotProduct.c and no later commit touches it [read]. Not affected: every 9.x and 10.x release up to 10.6.0, and the branch_10x, branch_10_6 and branch_10_5 tips of 2026-10-24, which have no native provider [exec]; the parent commit d02fb2a4cc7 [exec]. NEON (vdot8s_neon, dotProduct.c:127): the same signed overflow in the source for lengths >= 2^31-64, but GCC 10.5 -O3 compiles it to a counted loop and a NEON-only build returns the exact value at 2147483631 [exec]. All runs: OpenJDK 25.0.3, Linux aarch64, libraries built with GCC 10.5.0 -shared -O3 -march=native -funroll-loops (the independent reproduction: an -O2 build also crashes); other compilers and flags not checked",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-390.html",
   "repro": "repro/LFV-390/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-160",
   "priority": "low",
   "priority_rank": 915,
   "novelty": "new",
   "withheld": false,
   "area": "search / HNSW (merge-time graph reuse: IncrementalHnswGraphMerger base-graph selection)",
   "title": "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)",
   "summary": "You merge an HNSW vector segment that has had most of its vectors deleted and expect Lucene to rebuild the graph or reuse a cleaner one, because the DELETE_PCT_THRESHOLD javadoc says a graph with more than 40% of its vectors deleted is never selected as the merge base. Once more than 21,474,836 vectors of one graph are deleted, the percentage ((graphSize - live) * 100) / graphSize overflows int and goes negative (-59 for 25M deleted out of 30M), so the guard passes and a graph that is up to 100% deleted becomes the base, in either reader order and also when the segment is merged alone. The default merger still finishes, pruning and repairing the reused graph. In 10.4.0 through 10.6.0 and branch_10x, and on main before #16794 (for example ea57360912ed), the opt-in concurrent merger throws ArrayIndexOutOfBoundsException for an all-deleted base; on main since #16794 (from a9779ef3c193; to be released in 11.0, not in 10.6.0) it rebuilds the graph, and only the wrong choice of merge base remains.",
   "impact_class": "minor",
   "introduced_commit": "ef10476d98ab37b92fe48a1f71a1a06dad009ae3 (main) and its branch_10x backport 3e024479d358e77ba7d802308b70ccb25ccf08c4, PR #15003 'Avoid reconstructing HNSW graphs during segment merging.' (author Pulkitg64, merged by benwtrent, CHANGES 10.4.0 Optimizations), which let graphs with deletions be reused and added DELETE_PCT_THRESHOLD = 40 with the int deletePct line [read]",
   "introduced_date": "2025-12-01 (merged 22:14 UTC; the commit's author date is 2025-12-02 +0530; branch_10x backport committed 2025-12-01)",
   "first_affected_version": "10.4.0 [exec]; with the default per-field codec 10.5.1 [read]; 10.3.2 is the last unaffected release [exec]",
   "affected_versions": "10.4.0, 10.5.0, 10.5.1, 10.5.2, 10.6.0 (RC1 4ae946e5a9b, executed 2026-10-29, see 'Also' below) and main ea57360912ed. [exec] the version-neutral history probe fails 3 of 5 and the canonical repro 2 of 3 on each of them (-ea and -da on 10.4.0, 10.5.2 and main); Also [exec]: main 645d4fe14a2 and branch_10_6 RC1 4ae946e5a9b, the canonical repro 2 of 3 (-ea and -da). 9.12.3 and 10.3.2 pass 5 of 5 (-ea and -da). [read] 9.9.0 to 10.3.2 skip every graph with a deletion (noDeletes / hasDeletes) and have no percentage line; before 9.9.0 the writer skipped such segments too (9.8.0 read, not run); 9.9.0-9.12.2 and 10.0.0-10.3.1 were not run. Default codec: main since #15003 and releases from 10.5.1; in 10.4.0 and 10.5.0 only an HNSW format that is not per-field wrapped reaches the line (#16400) [read]. Zero-live ArrayIndexOutOfBoundsException variant [exec]: main ea57360912ed (before #16794; gone on main from a9779ef3c193), 10.4.0, 10.5.2 and branch_10_6 RC1 4ae946e5a9b (-ea, -da; 2026-10-29); branch_10x 657014b3c57 [read]; whether the #16400 gap blocks it in 10.4.0-10.5.0 with the default codec was not checked. Not fixed upstream: main 645d4fe14a2 :133 [exec], branch_10x 657014b3c57 and branch_10_6 :138 still compute the int (read-only check 2026-10-26, re-read 2026-10-29). No physical index with more than 21,474,836 deleted vectors in one segment was built on any version.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-160.html",
   "repro": "repro/LFV-160/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-007",
   "priority": "low",
   "priority_rank": 916,
   "novelty": "new",
   "withheld": false,
   "area": "util / FST",
   "title": "FSTCompiler silently writes a corrupt FST when a fixed-length-arc node would expand to 2^31 bytes or more",
   "summary": "You build an FST in which one node has many arcs and at least one large output, so that its fixed-length arc area numArcs*maxBytesPerArc reaches 2^31 bytes. You expect a correct FST or an error. Instead, with assertions off, compile() returns an FST whose node header was written over the unexpanded arc list: lookups through that node throw, and enumeration can return a key that was never added.",
   "impact_class": "data corruption",
   "introduced_commit": "silent form since LUCENE-4678 (2220c6e8ba9) in 4.2.0; current form #12624 (b6999818474; 9.10.0 ships the backport 193d8f14107), which dropped the long arithmetic",
   "introduced_date": "2013-01-12 (LUCENE-4678); 2023-12-07 (#12624 merged)",
   "first_affected_version": "4.2.0",
   "affected_versions": "silent: 4.2.0-9.4.1 (101 releases) and all 19 releases 9.10.0-10.5.2, branch_10_6 and main [exec]; 9.4.2-9.8.0: silent build, reads return null/empty or hang [exec]; 9.9.0-9.9.2: loud by default, silent with suffixRAMLimitMB(0) [exec]; 3.6.0-4.1.0 loud [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-007.html",
   "repro": "repro/LFV-007/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-003",
   "priority": "low",
   "priority_rank": 917,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / doc values",
   "title": "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",
   "summary": "You call the new bulk BinaryDocValues#binaryValues on the default codec for documents whose values add up to 2^31 bytes or more, which CheckIndex at level 2 or 3 does. You expect the same values as the per-document loop. Instead it throws NegativeArraySizeException, and at 4 GiB or more the size can wrap so that, with assertions off, returned BytesRefs point at other documents' bytes; CheckIndex then reports a valid index as broken, and -exorcise removed every document.",
   "impact_class": "crash",
   "introduced_commit": "#16286 (squash b843b4c6c3 on main; backport f5d01417305 on branch_10x, inherited by branch_10_6); the int-sized shared buffer came from commit d26fd36beb during review",
   "introduced_date": "2026-06-30",
   "first_affected_version": "10.6.0 (released 2026-10-29)",
   "affected_versions": "main and branch_10_6 [exec]; branch_10x same code [read]; releases 9.0.0-10.5.2 lack the API (javap on 33 sha1-checked jars) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-003.html",
   "repro": "repro/LFV-003/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b): CheckIndex -level 2 calls a healthy index of 3 x 1 GiB values broken and -exorcise drops its documents; 10.5.2 does not have the bulk BinaryDocValues API."
  },
  {
   "id": "LFV-381",
   "priority": "low",
   "priority_rank": 918,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / doc values (Lucene90DocValuesProducer dense byte-aligned bulk decode, NumericDocValues#longValues)",
   "title": "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)",
   "summary": "You index a dense numeric doc-values field that the default codec stores as one fixed 40-bit width, in a segment of 429,496,729 documents, and read every value with a single NumericDocValues#longValues call, expecting what the advanceExact/longValue loop in its javadoc returns. Instead Lucene90DocValuesProducer.bulkDecodeByteAlignedValues checks only the unpadded byte count (5 x 429,496,729 = 2,147,483,645) against Integer.MAX_VALUE and then adds 3 padding bytes in int arithmetic, which wraps to Integer.MIN_VALUE; the negative length passes the slice and allocation checks, and the call throws EOFException 'read past EOF (pos=0)' on a valid file (ArrayIndexOutOfBoundsException with NIOFS or an in-heap directory). The same wrap happens at 357,913,941 docs for 48-bit values, and at one size each for 16, 24 and 56 bits the padded count asks for a byte[] longer than the JVM allows (OutOfMemoryError 'Requested array size exceeds VM limit'), while the per-document loop and a batch one document smaller return every value.",
   "impact_class": "crash",
   "introduced_commit": "96691018f58b3d9a870e724842af3254a47f5c67 on main (apache/lucene#16129 'Add bulk decode for dense NumericDocValues via longValues()', by GitHub costin, co-authored by benwtrent, approved by jainankitk, merged by benwtrent), released through the direct branch_10x backport 4f27413dc998 of the same day (identical patch for Lucene90DocValuesProducer.java, git patch-id 5b53d5d740df for both; backport PR #16136 closed unmerged as 'backported directly') [read] [exec]. The commit wrote the whole dense byte-aligned bulk path (padding helper, unpadded guard, int addition of the padding, allocation, readBytes), so the bug is as old as the path and not a later regression",
   "introduced_date": "2026-05-27 (merged 2026-05-27T15:20:43Z)",
   "first_affected_version": "10.5.0 [exec] (release commit f6eaee8148b7, tag 2026-06-25; CHANGES 10.5.0 Optimizations 'GITHUB#16129: Add bulk decode for dense NumericDocValues via longValues().'); 10.4.0, the first release with the longValues API (#15149), has only the per-document default loop there [exec]",
   "affected_versions": "10.5.0, 10.5.1 and 10.5.2 (10.5.2 was the latest lucene-core on Maven Central when checked on 2026-10-26) and 10.6.0 [exec] [exec]; main from 96691018f58b to ea57360912ed [exec]; upstream main cf398bfb142c (read 2026-10-26) and the unreleased branch_10x and branch_10_5 heads and branch_10_6 (10.6.0, released 2026-10-29) carry the byte-identical block [read]. Not affected: 10.4.0 and the parent commit 098ff7d4fc63 [exec]. Not applicable: every release before 10.4.0, including all 9.x, which have no NumericDocValues#longValues [exec]. All runs: OpenJDK 25.0.3, Linux aarch64; the 16/24/56-bit OutOfMemoryError depends on the JVM's maximum array length (JDK 25: Integer.MAX_VALUE - 2 is the largest byte[] it allocates), the 40/48-bit wrap does not",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-381.html",
   "repro": "repro/LFV-381/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1235",
   "priority": "low",
   "priority_rank": 919,
   "novelty": "new",
   "withheld": false,
   "area": "util / compress (LZ4 fast compression hash table: LZ4.compress, LZ4.compressWithDictionary)",
   "title": "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)",
   "summary": "You compress a byte array of 1.1e9 bytes with LZ4.compress, reusing one LZ4.FastCompressionHashTable as the javadoc allows ('can safely be reused'): first the whole array from offset 0, then its last 2^20 bytes (offset 1,098,951,424). You expect the second call to compress the slice, as it does with a fresh table. Instead it throws ArrayIndexOutOfBoundsException ('Index -2096021376 out of bounds for length 1099999997'), because FastCompressionHashTable.get rebuilds a candidate match position as base + stored offset in int, an offset left in the table by the longer first call pushes that sum past Integer.MAX_VALUE, and the wrapped negative position passes get()'s 'is this an earlier position within reach' checks and is then read.",
   "impact_class": "minor",
   "introduced_commit": "b283b8df628dc9bbdbbb994b4a3653b7eecd7fd9 (main line; LUCENE-4702 'Terms dictionary compression', apache/lucene-solr PR #1126, migrated issue apache/lucene#5767, by Adrien Grand (jpountz), merged 2020-01-24), cherry-picked to branch_8x as 33a7af9cbfb9f668b4aee433906ee93d55e1e709: it created the public org.apache.lucene.util.compress.LZ4 with FastCompressionHashTable and replaced reset()'s hashTable.clear() with keeping the old entries and rejecting stale ones in get() by 'ref < off'; the int sum base + stored and that guard are in the first public version [read]. LUCENE-10170 (#377, c36ce300ae2, 2021-10-14) later rewrote the line as base + hashTable.getAndSet(h, off - base) without changing the arithmetic; git blame in the history clone (whose LZ4.java is byte-identical to 5adff78bb168's) attributes LZ4.java:369 to that rewrite and the guard at :372 to b283b8df628.",
   "introduced_date": "2020-01-24 (author date of b283b8df628 on the main line and of its branch_8x cherry-pick 33a7af9cbfb, committed 2020-01-27)",
   "first_affected_version": "8.5.0 [exec]. 8.4.1 has no public org.apache.lucene.util.compress.LZ4 (compile error), and the same input and calls on its package-private predecessor, whose reset() cleared the table, pass [exec]",
   "affected_versions": "Every release from 8.5.0: 8.5.0 to 8.11.4, every 9.x (9.0.0 to 9.12.3), every 10.x (10.0.0 to 10.6.0, released 2026-10-29, 4ae946e5a9b), and main 5adff78bb168 (12.0.0-SNAPSHOT) [read]. [exec] fail: main 5adff78bb168 with -ea and -da, 10.6.0 (-da: finder, the independent reproduction), 10.5.2 (-ea and -da: the independent reproduction), 9.12.3 (-da: finder, the independent reproduction), 9.0.0, 8.11.4 and 8.5.0 (-da: history runs; the independent reproduction also 8.5.0). Not affected: 8.4.1 and earlier (no public API; the package-private predecessor passes [exec]). Not new in 10.6 (10.5.2, 9.12.3 and 8.5.0 fail). Not fixed upstream: get() is unchanged on upstream main (newest commit on LZ4.java is 2a38fffef52, #16478, author date 2026-09-29, decompress side), and the only LZ4 PRs updated since 2026-11-01, #16746 and #16836, change decompression only. All runs used JDK 25.0.3 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1235.html",
   "repro": "repro/LFV-1235/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-453",
   "priority": "low",
   "priority_rank": 920,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter flush-control RAM accounting (DocumentsWriterFlushControl.markForFullFlush drops a 0-document DocumentsWriterPerThread; reached through updateDocuments and softUpdateDocuments with an empty block)",
   "title": "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",
   "summary": "You call IndexWriter.updateDocuments(term, List.of()), or softUpdateDocuments(term, List.of(), softField), to delete a key's documents and add nothing, then refresh or commit; you expect the delete to apply and nothing to stay buffered, so ramBytesUsed() returns to 0 as it does after deleteDocuments(term) or addDocuments(List.of()). Instead the call took a per-thread writer and charged its delete buffer (about 33 KB) to the flush control, and the next full flush throws that 0-document writer away without taking the charge back, so ramBytesUsed() climbs by about 33 KB per round and never comes down (20 rounds with a default config: 660,800 B). Once the phantom total passes the RAM buffer (about 510 rounds at the default 16 MB) the writer flushes after every document, so 200 small documents become 200 segments; with assertions enabled the writer closes itself with an AssertionError instead.",
   "impact_class": "minor",
   "introduced_commit": "75ab79f0aa3509192451c8acb77a4f4f1011fa2e (trunk, svn r1515459) and its branch_4x backport 8003cc7829823ba48bf67686c999b7fb7e4fd42f (svn r1515463), LUCENE-5006 / GitHub issue #6070 'Simplified DW and DWPT synchronization and concurrent interaction with IW' (s1monw); pre-GitHub, no PR. The change created the delete slice in the DWPT constructor, so an empty block no longer throws a NullPointerException, and replaced the in-place re-initialization of a 0-document writer with ThreadState.reset(), which zeroes its byte count without subtracting it from activeBytes [read]. Later commits kept the drop and changed only the size or the symptom: LUCENE-6676 (5.3.0, 7b0b145e173), LUCENE-8200 (#9247, 7.4.0, b627fae0321, added softUpdateDocuments), LUCENE-8590 (#9636, 7.7.0, eaf840867fa, 32 KB FieldUpdatesBuffer block), LUCENE-9304 (apache/lucene-solr#1397; 8.6.0 83b34d47900, main 2602269f3ec8: today's 'drop it on the floor' branch in markForFullFlush and the close-time netBytes assertion), #12198 (9.6.0, 4aab7c4bc2d: the ramBufferGranularity skip hides the 165 B leak under the default config) and #12573 (9.9.0, d3a3391d225 / main 8b84f6c0965: DeletedTerms ByteBlockPool, 32 KB first block).",
   "introduced_date": "2013-08-19 (LUCENE-5006 trunk commit and branch_4x backport); first released in 4.5.0 (tag dated 2013-10-02)",
   "first_affected_version": "4.5.0 [exec] (4.0.0 and 4.4.0 throw a NullPointerException on the same call instead [exec]); the flush storm at a few hundred rounds under the default config starts with 7.7.0 on the softUpdateDocuments path and 9.9.0 on the updateDocuments path [exec]",
   "affected_versions": "every release from 4.5.0 to 10.6.0 and main ea57360912ed: a version-portable public-API probe leaks on 4.5.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.4.0, 7.6.0, 7.7.0, 7.7.3, 8.5.2, 8.6.0, 8.11.4, 9.0.0, 9.5.0, 9.6.0 and 9.8.0 (with setMaxBufferedDocs or the soft path), 9.9.0, 9.12.3, 10.0.0, 10.5.2 and main [exec]; releases in between are inferred from the unchanged drop branch, whose two rewrites (LUCENE-6676, LUCENE-9304) are bracketed by executed releases [read]. Bytes left per round (one empty-block update, then commit, nothing buffered): updateDocuments(term, []) 165 B on 4.5.0-9.5.x, 0 under the default config on 9.6.0-9.8.x (hidden by the #12198 granularity skip; 165 B with setMaxBufferedDocs), 33,040-33,104 B from 9.9.0; softUpdateDocuments(term, [], f) 330 B on 7.4.0-7.6.x and 32,952-32,960 B from 7.7.0 (the API does not exist before 7.4.0). Under -ea: the FlushPolicy 'getNumDocsInRAM() > 0' assertion closes the writer tragically once the phantom bytes reach the buffer (rounds 506-509 at 16 MB on 7.7.0+ soft and 9.9.0+ hard); close() also asserts netBytes == 0 from 8.6.0. The finder's JUnit fails on 9.9.0, 9.12.3, 10.5.2 and main (-ea and -da) and only on its soft-path test on 9.8.0 [exec]. Not affected: 4.0.0-4.4.x (NullPointerException instead). Not fixed upstream: the 0-document branch is unchanged on main 49483e82b357, branch_10x and branch_10_6 as of 2026-10-26 [read], and 10.6.0 (released 2026-10-29) has it too [exec].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-453.html",
   "repro": "repro/LFV-453/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-837",
   "priority": "low",
   "priority_rank": 921,
   "novelty": "known",
   "withheld": false,
   "area": "index / buffered doc-values updates (BufferedUpdates, FieldUpdatesBuffer, FrozenBufferedUpdates)",
   "title": "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)",
   "summary": "You update a doc-values field through IndexWriter (for example updateBinaryDocValue with a 1 MiB value) and expect each update to be buffered once, as every later update of the same field is. Instead BufferedUpdates creates the field's FieldUpdatesBuffer with the update, whose constructor already records it as entry 0, and then adds the same update again, so the first 1 MiB update adds 2,162,956 bytes to ramBytesUsed() while each later one adds 1,048,576, and IndexWriter's InfoStream reports '1 field updates; 20 new updates' for one binary update matching 10 documents. Final values stay correct because the duplicate is identical and adjacent; Lucene 7.6.0 buffered the update once, and the double insert arrived with LUCENE-8590 in 7.7.0.",
   "impact_class": "minor",
   "introduced_commit": "b0e6a92ede321dc6932348978bed1a4c04a70d8c (master) and its branch_7x backport eaf840867fade1dfdd1adb9bf510ec181aa4e3f8 (the commit that shipped in 7.7.0), 'LUCENE-8590: Optimize DocValues update datastructures' (apache/lucene-solr#513 by s1monw, opened 2018-12-04, merged 2018-12-05; issue now apache/lucene#9636) [read] [exec]",
   "introduced_date": "2018-12-04 (author date of both commits; committed 2018-12-05 on master and branch_7x)",
   "first_affected_version": "7.7.0 [exec] (first master-line release 8.0.0 [exec]); 7.6.0 is unaffected [exec]; it and earlier releases [read] buffered each update once in a per-field LinkedHashMap keyed by term",
   "affected_versions": "7.7.0 through 10.5.2, 10.6.0 (by reading) and main a9779ef3c193 [exec]; the other 7.7-10.5 releases by tag ancestry plus cosmetic-only line history [read]; not fixed on upstream main 20ced71c1e6e (2026-10-27) [read], nor on branch_10x and branch_10_6 [read], so the released 10.6.0 has it too",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-8590",
    "https://issues.apache.org/jira/browse/LUCENE-9228",
    "https://github.com/apache/lucene/issues/16214",
    "https://github.com/apache/lucene/pull/16214",
    "https://github.com/apache/lucene/issues/9636",
    "https://github.com/apache/lucene/issues/10268"
   ],
   "doc": "",
   "repro": "repro/LFV-837/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1232",
   "priority": "low",
   "priority_rank": 922,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / term vectors (Lucene90 compressing term-vectors writer; IndexWriter per-thread RAM accounting)",
   "title": "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)",
   "summary": "You index documents with a field that stores term vectors with positions or offsets (default codec and IndexWriterConfig) and expect IndexWriter's RAM accounting, which since 8.7.0 adds the term-vectors writer's ramBytesUsed() so that flush and stall decisions see its heap, to count the writer's buffered positions and offsets in bytes. Instead Lucene90CompressingTermVectorsWriter.ramBytesUsed() adds the lengths of its four int[] buffers (positions, start offsets, lengths, payload lengths) as if each entry took one byte: with one pending document holding one term with 2^20 positions and offsets, the writer reports 3,217,630 bytes while those three int[] alone take at least 12,582,912 bytes (with the one-line fix it reports 12,867,380). Indexed data and search results are unaffected; IndexWriter only flushes later than ramBufferSizeMB and the per-thread hard limit intend.",
   "impact_class": "minor",
   "introduced_commit": "8f895d90755f474dcad1d4e8b1a1b8763536f5f6 on main ('LUCENE-9514: Include TermVectorsWriter in DWPT accounting (#1847)', Simon Willnauer; issue #10553 = LUCENE-9514, PR apache/lucene-solr#1847); the released code came from the same change on branch_8x, 597d8f69522, first in 8.7.0. It made TermVectorsWriter Accountable and added CompressingTermVectorsWriter.ramBytesUsed() as positionsBuf.length + startOffsetsBuf.length + lengthsBuf.length + payloadLengthsBuf.length + byte counts, where the four buffers are int[]; the only later commits on the method are 2d6ad2fee6d (LUCENE-9570, reformatting) and 873ac5f162a (LUCENE-9907, adds scratchBuffer.ramBytesUsed()), and the 9.0 rename to Lucene90CompressingTermVectorsWriter (f8be421ae1f, LUCENE-9705) kept the body [read]",
   "introduced_date": "2020-09-14 (author and merge date of 8f895d90755 on main; the branch_8x commit 597d8f69522 has the same author date and commit date 2020-09-14); first release 8.7.0",
   "first_affected_version": "8.7.0 [exec]; 8.6.3 is the last release without it [exec]",
   "affected_versions": "8.7.0 through 8.11.4, every 9.x release (9.0.0-9.12.3), every 10.x release through 10.6.0 (4ae946e5a9b) and main 5adff78bb168. Executed and failing: 8.7.0, 8.11.4 and 9.0.0 (-ea; 8.x writer reports 3,221,802 bytes, 9.0+ 3,217,630), 9.12.3 (-ea, -da), 10.5.2 (-ea, -da), 10.6.0 (-ea, -da) and main (-ea, -da), with the finder's repro, the independent reproduction's test or the history step's version-adapted copy [exec]; the method body is identical (by hash of the normalized body) at all 34 9.x and 10.x release tags, and the 8.8.0 and 8.8.1 tags contain 597d8f69522 [read]; 8.8.2-8.11.3 are not tagged in the history clone and were not run (inferred affected, as 8.7.0, 8.8.1 and 8.11.4 have it). Not affected: 8.6.3 and older (the method does not exist) [exec]. Not fixed upstream: upstream main 1c2072f0284, branch_11x 6c5889ee89f and branch_10_6 5deb5791f6c still sum the lengths (GitHub contents API, 2026-11-03; main re-checked). Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1232.html",
   "repro": "repro/LFV-1232/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1075",
   "priority": "low",
   "priority_rank": 923,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter tryUpdateDocValue (reader-pool doc-values update RAM)",
   "title": "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",
   "summary": "You open an NRT reader from an IndexWriter and call tryUpdateDocValue on its documents many times, for example 10,000 counter updates or one soft-delete per document, and expect the writer to keep these pending updates within its RAM buffer and write them out once they use too much RAM, as it does for the same updates made through updateNumericDocValue. Instead every call adds one more pending-update object to the writer's per-segment state and nothing ever compares their size with the buffer: with a 1 MB buffer, 10,000 calls leave 3,340,000 bytes pending, and without a refresh, flush() or commit the heap keeps growing until OutOfMemoryError. IndexWriter.ramBytesUsed() reports 0 for all of it.",
   "impact_class": "minor",
   "introduced_commit": "b0b32931b28da83d47f0561f4da734d6b9ee6e16 (master, 'LUCENE-8297: Add IW#tryUpdateDocValues(Reader, int, Fields...)', by Simon Willnauer (s1monw); JIRA LUCENE-8297 = apache/lucene#9344, a patch, no pull request; the code the 8.0+ releases ship) and its same-day branch_7x commit 48a2138e899bca0b8a8485fb7e490a9dc943d997 (the code the 7.x releases ship): tryUpdateDocValue was built on tryModifyDocument, shared with tryDeleteDocument, and adds each call's resolved updates straight to the pooled ReadersAndUpdates (rld.addDVUpdate), so it never reaches writeSomeDocValuesUpdates, the 'reader pool > 50% of our IW buffer' rule from LUCENE-7868 (58105a203a1, 2017-06-21, first in 7.0.0), whose only call site is after a frozen-packet apply; no RAM check was added [read]. Not a regression.",
   "introduced_date": "2018-05-05 (author date; commit dates 2018-05-07 on master and branch_7x)",
   "first_affected_version": "7.4.0 [exec]; 7.3.1 and earlier have no tryUpdateDocValue [exec]",
   "affected_versions": "every release from 7.4.0 through 10.6.0 (released 2026-10-29, 4ae946e5a9b) and main 645d4fe14a20 (unreleased 11.0) [exec]; the releases in between by a static check of all 59 release tags from 7.4.0 to 10.6.0 in the history clone (tryUpdateDocValue present, no RAM check, flush or merge call in it; 8.8.2-8.11.4 are not in the clone, 8.11.4 was executed) [read]. Not new in 10.6 (10.5.2 fails the same test). Not fixed upstream: upstream main e1faeba08bd (2026-11-02) has no change to IndexWriter.java, ReadersAndUpdates.java or ReaderPool.java since 645d4fe (last IndexWriter.java commit #16581, author date 2026-09-21) [read]. Executed on Linux aarch64 with JDK 25 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1075.html",
   "repro": "repro/LFV-1075/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-472",
   "priority": "low",
   "priority_rank": 924,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter NRT merge-on-refresh (getReader point-in-time merges) and IndexFileDeleter refcounts",
   "title": "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",
   "summary": "You keep an IndexWriter open, refresh near-real-time readers from it (DirectoryReader.openIfChanged) with merge-on-refresh on, which is the default since 9.3, and while a refresh-triggered merge of small segments runs, a commit or flush applies deletes that remove every document of that merge. You expect the merged segment, which IndexWriter drops as 100% deleted, to have its files deleted, as happens when the same segment is dropped by an ordinary merge. Instead the refresh has already taken a file reference on it and later closes its reader without releasing that reference, so the segment's files stay in the directory through deleteUnusedFiles(), commit(), close() and rollback(), until the next IndexWriter opens the index.",
   "impact_class": "minor",
   "introduced_commit": "8294e1ae2068 (master) and its branch_8x backport 2f2146aad46b (same day, identical IndexWriter.java patch, equal git patch-id): LUCENE-8962 'Merge segments on getReader' = apache/lucene-solr#1623 (s1monw, co-authored by mikemccand; JIRA now apache/lucene#10005). It added merge-on-refresh and both halves of the leak: the GET_READER callback, run from onMergeComplete at the start of commitMerge before the deletes made during the merge are carried over, opens the merged reader and calls deleter.incRef(sci.files()); finishGetReaderMerge closes the readers left in mergedReaders and clears the map without decRef [read]. Exposure, not code, changed with LUCENE-10078 (apache/lucene#921, b5795db0cf5, 9.3.0), which turned merge-on-refresh on by default",
   "introduced_date": "2020-08-24 (8294e1ae206 merged as lucene-solr#1623; branch_8x backport 2f2146aad46 the same day)",
   "first_affected_version": "8.7.0 [exec]; opt-in from 8.7.0 to 9.2.0, default configuration from 9.3.0 (LUCENE-10078) [read]",
   "affected_versions": "every release from 8.7.0 through 10.6.0, and main ea57360912ed. [exec] 8.7.0, 8.8.0, 8.11.4, 9.0.0, 9.2.0, 9.3.0, 9.12.3, 10.0.0, 10.5.2 and main fail with -ea (also with -da on 8.7.0, 8.11.4, 9.12.3, 10.5.2 and main), and both controls pass in every run; a sibling probe that drops a merge-on-commit merged segment the same way is clean on 8.6.3, 8.7.0, 10.5.2 and main, so the leak is specific to the getReader path. [read] all 36 release tags from 8.7.0 on in the history clone contain the commit or its backport, and the leaking code changed afterwards only by reformatting and stream or comment cleanups; 8.8.1 to 8.10.x and 9.4 to 9.11 were not executed. Exposure: opt-in in 8.7.0 to 9.2.0 (maxFullFlushMergeWaitMillis > 0 plus a merge policy that returns full-flush merges), default configuration from 9.3.0. Not fixed upstream: upstream main IndexWriter.java still has the close-and-clear at :749-750 (read 2026-10-26); 10.6.0 (released 2026-10-29) is affected [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-472.html",
   "repro": "repro/LFV-472/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-630",
   "priority": "low",
   "priority_rank": 925,
   "novelty": "known",
   "withheld": false,
   "area": "core / index IndexFileDeleter reference counting (non-commit checkpoint after a failed Directory.deleteFile; reached from IndexWriter flush, NRT flush and tryDeleteDocument)",
   "title": "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()",
   "summary": "You index with an IndexWriter on a Directory whose deleteFile can throw an IOException (Directory.deleteFile declares it), and one delete fails while the writer checkpoints outside a commit, for example when flush() drops a newly flushed segment whose documents were all deleted; flush() throws, but the writer stays open and reports no tragic exception, so you keep indexing, merging and committing. You expect the writer to delete the files of segments that are merged away once no commit references them, as IndexFileDeleter's reference counting promises (LUCENE-5919 made its decRef exception-safe for this reason). Instead the checkpoint has already taken a reference on every current file and, because decRef threw, skips the line that records those files for release, so in the repro _0.cfe, _0.cfs and _0.si stay on disk after the merge, the next commit, deleteUnusedFiles() and close() (rollback), and only a new IndexWriter removes them.",
   "impact_class": "minor",
   "introduced_commit": "For the documented trigger (an IOException from Directory.deleteFile): 8e784699f009b80301306f7fc55225d64b95416b ('Merge branch lucene-6835', 2016-02-06, by mikemccand; the IndexFileDeleter change was first committed on that branch as 84f44589f6f9 on 2016-02-02; JIRA LUCENE-6835 'Directory.deleteFile should \"own\" retrying deletions on Windows', now apache/lucene#7893; no pull request, the branch was merged directly). It removed IndexFileDeleter's catch-and-retry of delete IOExceptions, so a failed delete now leaves decRef and skips the re-record in checkpoint [read]. The leaking statement order is older: increment the new files, decRef lastFiles, record the new files only if that decRef returned, from LUCENE-710 (1159f9a7685e, 2007, first released in 2.2.0); LUCENE-5919 (trunk c84af3d08a71, 2014-09-03, by mikemccand; backports 477cde076b7 to 4.9.1, 7ce20679d1a to 4.10.1, 7f9c93375de to 5.0.0) wrapped decRef(lastFiles) in try/finally { lastFiles.clear() } but left lastFiles.addAll after the finally, which is today's code; before 6.0.0 only an unchecked throwable from deleteFile reached it [exec]. #12126 (d3b6ef3c86b, 2023, first in 10.0.0) moved the counting into util/FileDeleter with the same rethrow semantics [read]",
   "introduced_date": "2016-02-06 (8e784699f009, LUCENE-6835 merge: the IOException trigger); statement order since 2007-03-13 (LUCENE-710); try/finally form since 2014-09-03 (LUCENE-5919)",
   "first_affected_version": "6.0.0 [exec] for the documented IOException trigger (follow-up history harness: leaks in all four scenarios with -ea and -da); 5.5.5, the last release before, catches the IOException, queues the file and deletes it later, no leak [exec]; LUCENE-6835 was never backported to 5.x. With an unchecked throwable from deleteFile (not declared by Directory.deleteFile, but the failure type Lucene's own TestIndexFileDeleter.testExcInDecRef injects) the same leak is in every executed release from 4.9.1 on; 4.9.0 and 4.10.0 instead hit the over-decRef that LUCENE-5919 fixed (-ea: 'RefCount is 0 pre-decrement') [exec]",
   "affected_versions": "IOException trigger: every release from 6.0.0 through 10.5.2 and main a9779ef3c193; never fixed. [exec] follow-up history harness (public-API main(), stack-scoped injection of the first deleteFile under IndexFileDeleter.checkpoint, as testExcInDecRef does; oracle: no file outside the last commit after forceMerge(1), commit(), deleteUnusedFiles() and rollback(); control: a fresh IndexWriter removes the leftovers): leaks on 6.0.0, 6.6.6, 7.0.0, 7.3.1, 7.4.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea everywhere; -da also on 6.0.0, 7.0.0, 7.3.1, 7.4.0, 9.12.3, 10.0.0, 10.5.2 and main), and passes on main with the fix shadowed; the finder's JUnit fails on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the independent reproduction's JUnit fails on 9.12.3 and 10.5.2; the intended-behaviour check's default-config probe fails on 10.5.2 (481 files left). Route by version: the flush drop of a fully deleted segment reaches the defect in 6.0.0-6.6.6 and again from 7.4.0 (the LUCENE-8324 / LUCENE-8253 backports); in 7.0.0-7.3.1 it is not reached, but tryDeleteDocument through a still-open NRT reader leaks. [read] upstream main a95c754ee003 and branch_10x still have the code (prior-art step). Unchecked-throwable trigger: also 4.9.1, 4.10.1, 4.10.4, 5.0.0, 5.3.0 and 5.5.5 [exec]. Not executed: 5.4.x (its API fits neither harness variant) and releases before 4.9.0.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/6981",
    "https://issues.apache.org/jira/browse/LUCENE-5919",
    "https://github.com/apache/lucene/issues/7020",
    "https://issues.apache.org/jira/browse/LUCENE-5958",
    "https://github.com/apache/lucene/issues/16625",
    "https://github.com/apache/lucene/issues/16643"
   ],
   "doc": "",
   "repro": "repro/LFV-630/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-037",
   "priority": "low",
   "priority_rank": 926,
   "novelty": "known",
   "withheld": false,
   "area": "store / MMapDirectory",
   "title": "MMapDirectory loses shared-arena grouping when a closing arena removes a newer live arena",
   "summary": "You use MMapDirectory with its default shared-arena grouping while files of one group are opened and closed concurrently. You expect the files of a group to share one arena. Instead onClose of an old arena removes the newer live arena's entry, so grouping is lost (577 arenas instead of 10 in the repro).",
   "impact_class": "minor",
   "introduced_commit": "b4fb425c43a (#13570; 9.x backport 83df2ff10e2, #13682)",
   "introduced_date": "2024-07-25",
   "first_affected_version": "9.12.0 [read]",
   "affected_versions": "9.12.0 [read]; 9.12.3, 10.0.0, 10.1.0, 10.3.2, 10.4.0, 10.5.2 [exec]; 10.6.0 [exec]; main before 858c0175e85 [exec]. Fixed: main from 858c0175e85 (e1faeba08bd [exec]); branch_11x from 603af870375 [read]; branch_10_6 from 6dde6c73bd1 (head 91eaab4fb29, the 10.6.1 work, still versioned 10.6.0-SNAPSHOT) [exec]. First fixed releases: 10.6.1 and 11.0.0, both unreleased as of 2026-11-02.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16931",
    "https://github.com/apache/lucene/issues/16945"
   ],
   "doc": "",
   "repro": "repro/LFV-037/",
   "triage_status": "fixed",
   "triage_by": "Uwe Schindler (Lucene PMC)",
   "triage_date": "2026-10-28",
   "triage_link": "https://github.com/apache/lucene/pull/16931#issuecomment-6480391899",
   "triage_note": "Uwe Schindler said it looks very relevant: Uwe had long felt something was wrong with shared arenas, and Gianluca Graziadei had privately reported the same issue (Uwe on #16931, Chris Hegarty agreeing; Uwe's first dev@ message said closely related). Chris Hegarty fixed it in #16931 (merged 2026-10-29; Uwe Schindler cherry-picked it to branch_11x) and backported it for 10.6.1 in #16945. On #16931 Uwe Schindler noted that a single thread reproduces it and that it breaks nothing (no unclosed arenas, only some slowdown after many NRT reopens), so 10.6.0 was not respun for it.",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-177",
   "priority": "low",
   "priority_rank": 927,
   "novelty": "known",
   "withheld": false,
   "area": "index / TieredMergePolicy forced merges (findForcedMerges, IndexWriter.forceMerge with maxNumSegments > 1)",
   "title": "TieredMergePolicy forceMerge(n) with n > 1 can leave more than n segments, because segments too large to re-merge are not counted toward n",
   "summary": "You call IndexWriter.forceMerge(2) (or any n > 1) with the default TieredMergePolicy on an index that holds one very large segment without deletes plus a few small segments, and expect at most n segments afterwards, as the forceMerge javadoc ('maximum number of segments left in the index after merging finishes') and TieredMergePolicy's 'maxNumSegments wins' note promise; merging only the small segments would get there without breaking any size limit. Instead findForcedMerges sets the large segment aside as too big to re-merge but never counts it against n, so it treats the small segments as already merged (or stops one merge early) and forceMerge returns with n + 1 or more segments. In the repro an all-default policy returns no merge at all for [10 GB, 1 GB, 1 GB] at n = 2, and IndexWriter.forceMerge(2) on a 1 MB segment plus three 10-document segments (setMaxMergedSegmentMB(0.1)) stops at 3 segments.",
   "impact_class": "minor",
   "introduced_commit": "2519025fdafe (master, 2018-06-15; branch_7x 9c4e315c1cb, first release 7.5.0): LUCENE-7976 'Make TieredMergePolicy respect maxSegmentSizeMB and allow singleton merges of very large segments' (GitHub #9025; JIRA patch workflow, no PR), by ErickErickson, added the uncounted 'Don't try to merge a segment with no deleted docs that's over the max size' iter.remove() and the 'already merged' test that compares only the remaining segments with maxSegmentCount [read]; widened by 425f207f4098 (LUCENE-8688 'Forced merges merge more than necessary', #9734, by Armin Braun via Adrien Grand, 2019-03-15; branch_8x d89387553d6 -> 8.1.0, branch_7_7 66188bd0293 -> 7.7.2), whose bin packing starts resultingSegments at the number of remaining segments, so [big, small x3] at n = 2 also stops at 3 [exec]",
   "introduced_date": "2018-06-15 (LUCENE-7976); widened 2019-03-15 (LUCENE-8688)",
   "first_affected_version": "7.5.0 [exec] (7.4.0 is not affected [exec]); caveat: 7.5.0-8.11.x shipped a TieredMergePolicy javadoc paragraph (LUCENE-8370, c303c5f126bd) saying forceMerge with maxSegmentCount other than 1 is 'not guaranteed to have <= maxSegmentCount segments' and is 'best effort', which 9.0.0 (LUCENE-10093, e3151d6c7de, PR #375) replaced with 'maxNumSegments wins', so against TieredMergePolicy's own javadoc the violation is undisclaimed from 9.0.0 on [read]; the IndexWriter.forceMerge and MergePolicy.findForcedMerges javadocs say '<=' in every version checked (7.4.0, 7.5.0, 8.8.1, main) [read]",
   "affected_versions": "7.5.0-7.7.1 and 8.0.0 only when the remaining segments number n or fewer, e.g. [big, small, small] at n = 2 [exec]; 7.7.2-7.7.3 and 8.1.0-8.11.4 also when more than n small segments remain, e.g. [big, small x3] at n = 2 [exec]; 9.0.0-9.12.3 [exec]; 10.0.0-10.5.2 [exec]; main ea57360912ed [exec]; the releases in between are affected by reading (after LUCENE-8688 findForcedMerges changed only by a reformat, the maxMergeAtOnceExplicit removal, comments and the forceMergeRunning size test, none of which touches the three affected lines) [read]; 7.4.0 not affected [exec], older releases not affected [read]; not fixed upstream: main, branch_10x, branch_10_6 and branch_9_12 still have the uncounted exclusion, the uncounted 'already merged' check and resultingSegments = startingSegmentCount [read]; history runs used JDK 25, not each release's own JDK",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9417",
    "https://issues.apache.org/jira/browse/LUCENE-8370",
    "https://issues.apache.org/jira/browse/LUCENE-7976",
    "https://github.com/apache/lucene/issues/11131",
    "https://issues.apache.org/jira/browse/LUCENE-10093",
    "https://github.com/apache/lucene/issues/375"
   ],
   "doc": "",
   "repro": "repro/LFV-177/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-592",
   "priority": "low",
   "priority_rank": 928,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter forced merge (writer-wide forced-merge target shared by concurrent forceMerge calls)",
   "title": "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",
   "summary": "You call forceMerge(1) on an IndexWriter and, while it is still merging, another thread calls forceMerge(2) on the same writer. You expect forceMerge(1) to return only once the index is down to 1 segment, because its javadoc defines maxNumSegments as the 'maximum number of segments left in the index after merging finishes' and IndexWriter allows concurrent calls to any method. Instead forceMerge(1) returns normally with 2 segments: both calls share one writer-wide target, the second call overwrites it (also on the first call's running merges), and the first call's wait loop only checks that no forced merge is left, never its own target.",
   "impact_class": "minor",
   "introduced_commit": "97fbfb542737a2625ff983feb8cb3c0af58a6805 'LUCENE-982: add new method optimize(int maxNumSegments) to IndexWriter' (Subversion r599766, by mikemccand; pre-GitHub, no PR; GitHub issue #2058), which added the per-call target, wrote it into every pending and running merge ('merge.maxNumSegmentsOptimize = maxNumSegments'), re-planned the merge-finish cascade with that overwritten value and left the wait loop checking only that no optimize merge is pending [read]. Precondition: 299d6357dd296f87a099fadd0764292b28dbde47 (LUCENE-845/847/870, 2007-09-18) made optimize() unsynchronized and added the writer-wide segmentsToOptimize and the wait loop, when every call targeted 1 segment. LUCENE-2618 (trunk 0630ca3119f, 2010) added the writer-wide optimizeMaxNumSegments (today mergeMaxNumSegments), a second place where the latest call's target wins; LUCENE-3454 (19889d68738, 2011) renamed optimize to forceMerge, which is why git blame on main points at 2011.",
   "introduced_date": "2007-11-30",
   "first_affected_version": "2.3.0 [exec]; 2.2.0 has only a synchronized optimize() without a target [exec]",
   "affected_versions": "every release from 2.3.0 through 10.6.0 (10.6.0 [exec]: the minimal test fails on the 10.6.0 release jars (SHA-1 checked against Maven Central), assertions on), including 9.12.3 (the latest 9.x), and main a9779ef3c193; never fixed. [exec] 2.3.0, 2.3.2, 2.4.1, 2.9.4, 3.0.3, 3.1.0, 3.6.2, 4.0.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (also -da on 9.12.3, 10.5.2 and main): the first call returned with 2 segments in every bug trial (72/72 together with the introducing-commit build) and the control with 1. [exec] 8.6.0, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main (-ea and -da) fail with 2 segments; the independent reproduction repeated it on main, 10.5.2 and 9.12.3 with its own public-API JUnit, the intended-behaviour check on main and 10.5.2. [read] every release tag from 2.3.0 on contains the introducing commit (139 of 139) and keeps the same overwrite, cascade and wait-loop structure; IndexWriter.java is identical on the previous hunt main ea57360912ed; the forceMerge block is byte-identical on branch_10x and branch_10_6 (fetch dated 2026-10-24) and unchanged on upstream main a95c754ee003 (2026-10-26).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-592.html",
   "repro": "repro/LFV-592/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-178",
   "priority": "low",
   "priority_rank": 929,
   "novelty": "new",
   "withheld": false,
   "area": "index / merge policy (LogMergePolicy forced-deletes selection, IndexWriter.forceMergeDeletes)",
   "title": "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",
   "summary": "You use LogDocMergePolicy or LogByteSizeMergePolicy and call IndexWriter.forceMergeDeletes(true) while another merge is pending or running, for example the natural merge that the call's own flush starts. You expect what LogMergePolicy's javadoc says ('Finds merges necessary to force-merge all deletes from the index'): every segment with deletes that is not already being merged is merged before the blocking call returns. Instead the policy groups adjacent segments with deletes into runs without skipping the ones that are already merging, IndexWriter rejects every run that contains such a segment (it only writes an infoStream message), and the call returns with the other segments of that run still holding their deletes, for example a 5000-document segment that keeps all 500 of its deletes.",
   "impact_class": "minor",
   "introduced_commit": "1d4ab6879680d35a212539a85ff942e081ef0579 (svn r620604, 'LUCENE-325: add expungeDeletes methods to IndexWriter', now apache/lucene#1403; committed from a JIRA patch, no PR) [read] [exec]; LUCENE-3577 (5267d23d4661, 3.5.0) renamed the methods to forceMergeDeletes / findForcedDeletesMerges, and none of the 19 later commits that touched the method (20 with the introducing one) added a merging-segments check",
   "introduced_date": "2008-02-11",
   "first_affected_version": "2.4.0 [exec] (CHANGES.txt 2.4.0, API Changes item 4, LUCENE-325); 2.3.2 and earlier have no expungeDeletes API [exec]",
   "affected_versions": "every release from 2.4.0 through 10.6.0, and main ea57360912ed. [exec] the canonical scenario (S1 5000 docs with 500 deleted, S2-S4 20 docs with 2 deleted each, LogDocMergePolicy mergeFactor=3, a natural merge of S2-S4 pending or running) fails on 2.4.0 (pending variant -ea and -da, running variant -ea), 2.4.1, 2.9.4, 3.0.3, 3.6.2, 4.10.4, 5.5.5, 6.6.6 and 7.7.3 (version ports of the pending variant; the same program without a concurrent merge passes on 2.4.0, 2.9.4, 3.0.3, 3.6.2, 4.10.4, 5.5.5, 6.6.6 and 7.7.3), 8.11.4 (the canonical JUnit with two test-framework imports changed), 9.12.3 and 10.5.2 (-ea and -da) and main (-ea and -da); the intended-behaviour check's hook-free probe fails on main (50/50 -ea, 19/20 -da), 10.5.2 (10/10) and 9.12.3 (10/10). [read] all 138 release tags from 2.4.0 on contain the introducing commit, and the method never mentions merging segments at any of them; the default configuration was affected in 2.4.0-3.1, when LogByteSizeMergePolicy was the default, and since 3.2 only applications that choose a LogMergePolicy are. 10.6.0 (released 2026-10-29) is affected [exec]; the method is unchanged on main. All runs on aarch64 with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-178.html",
   "repro": "repro/LFV-178/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-502",
   "priority": "low",
   "priority_rank": 930,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter point-in-time merges (merge-on-commit, merge-on-getReader: updatePendingMerges, registerMerge, preparePointInTimeMerge, MergeSpecification.await)",
   "title": "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",
   "summary": "You install a merge policy whose findFullFlushMerges (merge-on-commit or merge-on-getReader) proposes a segment that another merge is already working on, a case whose outcome the javadoc spells out: commit() 'will throw a IllegalStateException'. Instead IndexWriter quietly refuses to register that merge but still opens its segment readers and waits for it, so commit() returns normally only after the full maxFullFlushMergeWaitMillis, the rejected merge's files stay open after IndexWriter.close(), and DirectoryReader.open(writer) keeps waiting even after another thread has called rollback(). The merges that did register are applied normally.",
   "impact_class": "minor",
   "introduced_commit": "7f352a96659b4d304ae3ef0c7a1b62784ce2a406 (main) and its branch_8x backport 9b1c92809e730a70c1d9bf9e5b65a4b521bddc8b, apache/lucene-solr#1617 (LUCENE-8962 'Merge small segments on commit', s1monw, co-authored by msfroh, msokolov and mikemccand) [read]: the new on-commit merge takes the spec that updatePendingMerges returns (it ignores registerMerge's boolean, a loop from 2007-2010 that was harmless until #1585, 59efe22ac29, made it return the spec), opens readers for every merge in it and awaits every merge, and the javadoc sentence promising the IllegalStateException is kept. The getReader path came with 8294e1ae2068 / 2f2146aad46b (apache/lucene-solr#1623, 'Merge segments on getReader', 8.7.0). The reverted first implementation 043c5dff6f4 (#1155) threw the documented exception when registerMerge returned false; the reverted #1552 (972c84022ec) was the first version without that check. Since #13017 (47792dfcd3c9 / fc9d6770a55, 9.11.0 and 10.0.0) the rejected merge also holds IndexFileDeleter references [read]",
   "introduced_date": "2020-06-27 (#1617 on main and branch_8x); getReader extension 2020-08-24 (#1623)",
   "first_affected_version": "8.6.0 [exec] (commit path; 8.5.2 does not have findFullFlushMerges, MergeTrigger.COMMIT or setMaxCommitMergeWaitMillis [exec]); the getReader-after-rollback symptom from 8.7.0 [exec] (8.6.3 has no MergeTrigger.GET_READER [exec])",
   "affected_versions": "Every release from 8.6.0 to 10.6.0 and main ea57360912ed. [exec] the minimal test fails on the 10.6.0 release jars (SHA-1 checked against Maven Central) with -ea and -da. [exec] the finder's JUnit (or its 8.6 / pre-9.1 API variants) fails on 8.6.0 and 8.6.3 (3 of 3, commit path only), 8.7.0, 8.11.4, 9.0.0, 9.8.0, 9.12.3, 10.0.0, 10.5.2 and main -ea and -da (4 of 4), and an 8.6.0 control with a registrable spec passes; the independent reproduction's own JUnit fails 4 of 5 on main (-ea, -da), 10.5.2 and 9.12.3 with its control passing; the intended-behaviour check's hook-free probe fails on main (-ea, -da) and 10.5.2. [read] the code shape (unchecked registerMerge, initMergeReaders over every point-in-time merge, await, no exception) is present at every release tag in the history clone (8.6.0-8.8.1, 9.0.0-9.12.3, 10.0.0-10.5.2; 8.8.2-8.11.3 are not in the clone). Reach: in 8.6.0-9.2.0 the code path runs only with an explicit non-zero wait; since 9.3.0 (LUCENE-10078) merge on full flush is on by default with a 500 ms wait [read]. Not fixed upstream: no commit to IndexWriter.java or MergePolicy.java on main (a9779ef3c193), branch_10x or branch_10_6 since 2026-09-21 [read]; branch_10_6 not executed. All runs on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-502.html",
   "repro": "repro/LFV-502/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-228",
   "priority": "low",
   "priority_rank": 931,
   "novelty": "known",
   "withheld": false,
   "area": "index / merge policy (SoftDeletesRetentionMergePolicy.numDeletesToMerge, soft deletes)",
   "title": "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",
   "summary": "You enable soft deletes with SoftDeletesRetentionMergePolicy and a retention query that keeps soft-deleted documents, soft-delete a document (it is kept as history), commit, and later hard-delete the same document with deleteDocuments. You expect what MergePolicy.numDeletesToMerge promises, 'the number of deletes that a merge would claim', and since LUCENE-8381 IndexWriter does drop such a hard-deleted document in a merge even though the retention query matches it. Instead the policy subtracts every deleted document that has the soft-delete field and matches the retention query, hard-deleted or not, so in the repro it reports 0 where forceMerge(1) drops 1, and forceMergeDeletes() leaves a segment with 1 of its 4 documents hard-deleted (25%, above TieredMergePolicy's 10% threshold) untouched.",
   "impact_class": "minor",
   "introduced_commit": "0ccd5d580d1ba0688e3804e73c27c252ace09bb8 ('LUCENE-8381: Do not count hard-deletes as soft-deletes in merges', JIRA LUCENE-8381, now apache/lucene#9428; patch reviewed on JIRA, no PR; branch_7x c65fb8568a9d) [read] [exec]; the counting loop itself dates from e99a19755c75 (LUCENE-8246, 7.4.0), when it still matched the merge",
   "introduced_date": "2018-07-04 (commit date on master; author date 2018-07-03)",
   "first_affected_version": "7.5.0 [exec] (tagged 2018-09-22); 7.4.0 has the API, and its count agrees with its merge because the merge itself kept the document (the older LUCENE-8381 bug) [exec]; 7.3.1 and earlier have no soft-deletes API [exec]",
   "affected_versions": "every release from 7.5.0 through 10.5.2, and main ea57360912ed. [exec] fails on 7.5.0, 7.7.3, 8.0.0, 8.11.4, 9.12.3, 10.5.2 and main (version ports, -ea; also -da on 7.5.0, 8.11.4, 9.12.3, 10.5.2 and main) and with the canonical JUnit on 9.12.3, 10.5.2 and main (-ea and -da); the independent reproduction's independent JUnit also fails on 9.12.3 and 10.5.2. [read] all 57 release tags 7.5.0..10.5.2 in the history clone have the same loop with no hard-live-docs check (tags 8.8.2..8.11.4 are missing from the clone; 8.11.4 was executed). 10.6.0 (released 2026-10-29; branch_10_6 not in the clone) was not checked; the method is unchanged on upstream main. All runs on aarch64 with JDK 25.",
   "security": "none",
   "upstream_links": [
    "https://lists.apache.org/thread/q0kyo58lqz4fn5fzpynfylgr446703g5",
    "https://issues.apache.org/jira/browse/LUCENE-8381",
    "https://github.com/apache/lucene/issues/11064",
    "https://issues.apache.org/jira/browse/LUCENE-10025",
    "https://github.com/apache/lucene/issues/14531",
    "https://github.com/apache/lucene/issues/16847"
   ],
   "doc": "",
   "repro": "repro/LFV-228/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-213",
   "priority": "low",
   "priority_rank": 932,
   "novelty": "new",
   "withheld": false,
   "area": "index / merge policy (TemporalMergePolicy forced-deletes selection, IndexWriter.forceMergeDeletes)",
   "title": "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)",
   "summary": "You use TemporalMergePolicy and call IndexWriter.forceMergeDeletes() while some time window holds exactly one segment whose share of deleted documents is above forceMergeDeletesPctAllowed (default 10%), for example in a single-segment index, or after forceMerge(1), which leaves one segment per window. You expect that segment to be rewritten without its deleted documents, as the policy's setForceMergeDeletesPctAllowed javadoc and MergePolicy.findForcedDeletesMerges ('expunge all deletes') describe and as TieredMergePolicy and LogMergePolicy do. Instead the policy skips every window with fewer than two eligible segments (and drops the one left over after full batches of maxThreshold), so the call schedules no merge and returns at once: a 10-document segment with 5 deletes still has maxDoc 10, and calling it again changes nothing.",
   "impact_class": "minor",
   "introduced_commit": "1596b7604b67ed47314aa648f14b91dc75ce8134 (apache/lucene#15620 'Add Temporal Merge Policy for time-series data', merged to main 2026-03-17; branch_10x backport 4a2c3fd0901cbd4a31704b619e0dde15ac65f284, contained in 10.5.0, 10.5.1, 10.5.2 and 10.6.0) [read]. Original code, not a regression: there was never a correct earlier behaviour",
   "introduced_date": "2026-03-17 (merge of #15620; the guards date from the PR's first commit, 2026-01-27)",
   "first_affected_version": "10.5.0 [exec] (first release with TemporalMergePolicy); 10.4.0 and 9.12.3 do not have the class [exec]. CHANGES.txt lists GITHUB#15620 under the 10.4.0 heading, but 10.4.0 (tagged before the merge) does not contain the class, so CHANGES.txt cannot date this bug",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2, 10.6.0 (released 2026-10-29; [exec] the minimal test fails on the 10.6.0 release jars (SHA-1 checked against Maven Central), assertions on) and main ea57360912ed. [exec] the finder's JUnit fails 2 of 2 and the independent reproduction's suite fails 4 of 8 (all four bug cases fail, all four controls pass) on 10.5.0, 10.5.1, 10.5.2 and main with -ea, and also with -da on 10.5.2 and main; a separate JUnit fails on main (-ea, -da) and 10.5.2, and the intended-behaviour check's own controls fail on main (-ea, -da). [read] branch_10x and branch_10_6: TemporalMergePolicy.java blob b3e4e927d4a6 is identical to 10.5.2 in a local mirror fetched 2026-10-24 (not executed); the 10.x file differs from main only in a lambda parameter name. Not applicable: 10.4.0 and every earlier release (class absent). All runs on aarch64 with JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-213.html",
   "repro": "repro/LFV-213/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1213",
   "priority": "low",
   "priority_rank": 933,
   "novelty": "new",
   "withheld": false,
   "area": "index / merge policy (TemporalMergePolicy forced-deletes merges, IndexWriter.forceMergeDeletes)",
   "title": "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",
   "summary": "You configure TemporalMergePolicy with setMaxThreshold(Integer.MAX_VALUE), which the setter accepts (it checks only maxThreshold >= minThreshold and says larger values merge more aggressively), and call IndexWriter.forceMergeDeletes() while one time window holds two segments whose share of deleted documents is above forceMergeDeletesPctAllowed, for example two 4-document segments with one deleted document each. You expect the two segments to be merged into one with no deleted documents left, as happens with the default maxThreshold of 8, and as natural merges and forceMerge do with the same setting. Instead buildSequentialMerges creates its batch list with new ArrayList<>(maxThreshold) before adding anything, so forceMergeDeletes() throws java.lang.OutOfMemoryError: Requested array size exceeds VM limit at any heap size, no merge is registered and the deleted documents stay.",
   "impact_class": "crash",
   "introduced_commit": "1596b7604b67ed47314aa648f14b91dc75ce8134 (apache/lucene#15620 'Add Temporal Merge Policy for time-series data' by churromorales, merged to main 2026-03-17; the branch_10x copy 4a2c3fd0901cbd4a31704b619e0dde15ac65f284, same author and author date, committed 2026-03-17, is the code that 10.5.0 to 10.6.0 ship) [read]. Original code, not a regression: the class and the line arrived together, and the parent 4a3cdbcd5f9 has no TemporalMergePolicy",
   "introduced_date": "2026-03-17 (author and commit date on main 2026-03-17T19:32:33Z; branch_10x copy committed 2026-03-17T21:49:06Z)",
   "first_affected_version": "10.5.0 [exec] (tag commit f6eaee8148b, 2026-06-19; the first release with TemporalMergePolicy); 10.4.0 and 9.12.3 do not have the class [exec]. CHANGES.txt lists GITHUB#15620 under the 10.4.0 heading, but the 10.4.0 core jar has no TemporalMergePolicy class, so CHANGES.txt cannot date this bug",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2 and 10.6.0 (4ae946e5a9b), plus unreleased main 5adff78bb168 (12.0.0-SNAPSHOT). [exec] fail with the same OutOfMemoryError at TemporalMergePolicy.java:957: main with -ea and -da, 10.6.0 with -ea and -da, and 10.5.2, 10.5.1 and 10.5.0 with -ea. [read] TemporalMergePolicy.java is byte-identical in 10.5.0, 10.5.1, 10.5.2, 10.6.0 and 4a2c3fd0901 (blob b3e4e927d4a); main's copy differs only in an unnamed lambda parameter. Not applicable: 10.4.0 and every earlier release, all of 9.x included (class absent; 10.4.0 and 9.12.3 executed: compile error). Not fixed upstream: main, branch_11x and branch_10_6 still have the line at :957, and no commit after #15620 touches the file (GitHub commits and contents API, 2026-11-03). Not new in 10.6 (10.5.x fails). All runs used JDK 25.0.3 on Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1213.html",
   "repro": "repro/LFV-1213/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-179",
   "priority": "low",
   "priority_rank": 934,
   "novelty": "known",
   "withheld": false,
   "area": "index / merge policies (FilterMergePolicy size unit, compound-file threshold)",
   "title": "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",
   "summary": "You wrap a LogDocMergePolicy in a FilterMergePolicy (or in SoftDeletesRetentionMergePolicy, UpgradeIndexMergePolicy or OneMergeWrappingMergePolicy) and expect the wrapper to make the same compound-file choices as the policy it wraps, as it did in 10.x. Instead, on main FilterMergePolicy.size() still returns the wrapped policy's document count while getSizeUnit() says BYTES, so the compound-file check compares a document count with the 64 MiB byte threshold: forceMerge(1) of 70,000 small documents writes a compound segment where the plain policy writes a non-compound one, and every later forceMerge(1) rewrites that already merged segment again (3 of 3 calls).",
   "impact_class": "minor",
   "introduced_commit": "6643a5dbe1ed (6643a5dbe1ed6d3a4b933c90beed60cfe44b5992, GITHUB#15295 'Switching to a fixed CFS threshold' by shubhamsrkdev, approved by stefanvodita, merged to main 2026-01-23, milestone 11.0.0, closes #14959): it removed FilterMergePolicy's delegating useCompoundFile, getNoCFSRatio, setNoCFSRatio, setMaxCFSSegmentSizeMB and getMaxCFSSegmentSizeMB overrides, added MergePolicy.getSizeUnit (default BYTES), LogDocMergePolicy.getSizeUnit (DOCS) and CompoundFormat.useCompoundFile(long, MergePolicy), and gave FilterMergePolicy getSizeUnit() { return super.getSizeUnit(); } [read] [exec]",
   "introduced_date": "2026-01-23",
   "first_affected_version": "unreleased (main only, 11.0.0-SNAPSHOT since 6643a5dbe1ed; it would first ship in 11.0.0 unless fixed; #15295 is not in branch_10x or branch_10_6, and no release tag contains it)",
   "affected_versions": "main from 6643a5dbe1ed (2026-01-23) to ea57360912ed [exec]. Not affected: parent d455fefc6b63, 9.12.3, 10.0.0 and 10.5.2 [exec]; 6.0.0, 7.0.0, 7.4.0, 8.0.0, 9.0.0, 10.3.2, 10.4.0 and 10.5.0, and upstream branch_10x and branch_10_6 [read]. Releases before 9.1.0 were not executed; executed on aarch64 with JDK 25 only",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16742",
    "https://github.com/apache/lucene/issues/15295",
    "https://github.com/apache/lucene/issues/14959",
    "https://github.com/apache/lucene/issues/15691",
    "https://issues.apache.org/jira/browse/LUCENE-7008",
    "https://github.com/apache/lucene/issues/8065"
   ],
   "doc": "",
   "repro": "repro/LFV-179/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-509",
   "priority": "low",
   "priority_rank": 935,
   "novelty": "known",
   "withheld": false,
   "area": "index / merge policies (SoftDeletesRetentionMergePolicy OneMerge wrapping); misc / BP merge-time reordering (BPReorderingMergePolicy)",
   "title": "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)",
   "summary": "You configure IndexWriter with new SoftDeletesRetentionMergePolicy(field, query, new BPReorderingMergePolicy(base, reorderer)) to keep soft-deleted history and to reorder doc IDs on merge, then call forceMerge or let natural merges run. You expect the merged segments to be reordered, as BPReorderingMergePolicy documents for all forced merges and as the reverse nesting does on the same documents. Instead the retention policy replaces each merge with a new OneMerge that forwards only wrapForMerge, so IndexWriter's call to reorder() reaches the default that returns null: the merged segment silently keeps its original doc order and carries no bp.reordered diagnostic.",
   "impact_class": "minor",
   "introduced_commit": "f7cab1645017d863331b42900581b67d3591e2da (main, first released in 10.0.0) and its branch_9x cherry-pick 6b1538b33136a4737ad0d22b3633e62f3d7f362b (first released in 9.9.0), PR #12622 'Add a merge policy wrapper that performs recursive graph bisection on merge.' (jpountz): added OneMerge#reorder and BPReorderingMergePolicy, updated IndexWriter's OneMergeWrappingMergePolicy wrapper to forward reorder ('// must delegate') and setMergeInfo, left SoftDeletesRetentionMergePolicy's wrapper unchanged [read]. The wrapper itself is older: ecc17f9023309ca2c46eaf65fd031e4af0ef5a25 (main) / 02fa5a0b059353ae5607e91211cea24974257980 (7.x line), LUCENE-8233 'Add support for soft deletes to IndexWriter' (2018-04-04, first released in 7.4.0), changed since only in formatting (2d6ad2fee6d LUCENE-9570, 2020-12-23; e59c607daf9 GITHUB#12655, 2023-10-11, a blank line)",
   "introduced_date": "2023-11-23 (#12622 merged; the wrapper dates from 2018-04-04)",
   "first_affected_version": "9.9.0 [exec]; 9.8.0 not affected [exec]",
   "affected_versions": "every release from 9.9.0 to 10.5.2 (22 releases) and main ea57360912ed. [exec] fail: 9.9.0, 9.9.2, 9.10.0, 9.11.1, 9.12.0, 9.12.3, 10.0.0, 10.5.2, main (-ea and -da) (9.9.0, 9.9.2, 9.10.0 and 9.11.1 with the 2-argument reorder variant, the rest with the unmodified repro); the independent reproduction's and the intended-behaviour check's own JUnits also fail on 9.12.3 and 10.5.2. [read] 9.9.1, 9.11.0, 9.12.1, 9.12.2, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1: SoftDeletesRetentionMergePolicy.java byte-identical (sha1 e473deb7f2...) in all 22 releases 9.9.0..10.5.2 and main; each has IndexWriter merge.reorder( call sites (2) and BPReorderingMergePolicy.java. Not affected: 9.8.0 [exec] and all earlier releases [read] (no OneMerge#reorder, no BPReorderingMergePolicy). Older latent part: the wrapper never forwarded setMergeInfo, mergeInit or mergeFinished (a callbacks-only probe fails on 9.8.0 and main [exec]), with no in-tree consumer before 9.9.0, so the user-visible effect starts in 9.9.0. Not fixed upstream: upstream main a9779ef3c193 (2026-10-26) and branch_10x keep the same wrapper (last changed 2023-10-11, formatting only); open PR #16571 would change it (upstream). No release newer than 10.5.2 on Maven Central on 2026-10-26. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16571",
    "https://github.com/apache/lucene/issues/12622",
    "https://github.com/apache/lucene/issues/13765",
    "https://github.com/apache/lucene/issues/12665",
    "https://github.com/apache/lucene/issues/13128",
    "https://github.com/apache/lucene/issues/8739"
   ],
   "doc": "",
   "repro": "repro/LFV-509/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-572",
   "priority": "low",
   "priority_rank": 936,
   "novelty": "new",
   "withheld": false,
   "area": "index / merge policy compound-file check (MergePolicy.isMerged vs CompoundFormat settings)",
   "title": "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",
   "summary": "You give IndexWriter its own codec instance, for example new Lucene104Codec(Mode.BEST_COMPRESSION), turn compound files off on it as MIGRATE.md says (iwc.getCodec().compoundFormat().setShouldUseCompoundFile(false)), use a LogByteSizeMergePolicy and force-merge the index to one segment. You expect a later forceMerge(1) to leave that already merged segment alone, as it does in the same writer session and as 10.x does with the equivalent merge-policy settings. Instead, after the writer is closed and reopened, MergePolicy.isMerged asks the codec instance the segment was read with (the shared Codec.forName instance, whose settings are the defaults), decides the non-compound segment should have been compound, and forceMerge(1) rewrites it (_3 becomes _4); the merge itself uses the writer's codec and writes a non-compound segment again, so the same rewrite happens in every later writer session.",
   "impact_class": "minor",
   "introduced_commit": "6643a5dbe1ed (6643a5dbe1ed6d3a4b933c90beed60cfe44b5992, GITHUB#15295 'Switching to a fixed CFS threshold' by shubhamsrkdev, merged to main by stefanvodita 2026-01-23, closes #14959): it moved the compound-file settings from the merge policy into per-instance CompoundFormat fields and changed the last check of MergePolicy.isMerged from the writer's merge-policy settings (useCompoundFile(infos, info, mergeContext) of this policy) to info.info.getCodec().compoundFormat(), while the merge itself asks the merged segment's codec, which IndexWriter builds with config.getCodec() [read] [exec]",
   "introduced_date": "2026-01-23",
   "first_affected_version": "unreleased (main and branch_11x, 11.0.0-SNAPSHOT since 6643a5dbe1ed; branch_11x 603af870375, created from main on 2026-10-29 by #16929, contains it [read]; it would first ship in 11.0.0 unless fixed; #15295 is not in branch_10x or branch_10_6 and no release tag contains it)",
   "affected_versions": "main 11.0.0-SNAPSHOT at 6643a5dbe1ed (introducing), ea57360912ed and a9779ef3c193 [exec]; the commits in between [read]; upstream main a95c754ee003 (2026-10-26) [read]; branch_11x 603af870375 (created from main on 2026-10-29, #16929) [read]. Not affected [exec]: the parent d455fefc6b63, branch_10x 10.7.0-SNAPSHOT, branch_10_6 10.6.0-SNAPSHOT, 10.5.2, 10.4.0, 10.3.2 and 9.12.3. Not executed: x86.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-572.html",
   "repro": "repro/LFV-572/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1017",
   "priority": "low",
   "priority_rank": 937,
   "novelty": "known",
   "withheld": false,
   "area": "codecs / compound-file settings (CompoundFormat on the shared default codec; MIGRATE.md 11.0 recipe)",
   "title": "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",
   "summary": "You follow the 11.0 MIGRATE.md recipe on one writer's fresh IndexWriterConfig (CompoundFormat cfs = iwc.getCodec().compoundFormat(); cfs.setShouldUseCompoundFile(false); cfs.setMaxCFSSegmentSizeMB(512)) and then open a second, unrelated IndexWriter on another directory with its own brand-new default IndexWriterConfig. You expect only the first writer to change, as in 10.x, where the recipe's 'Before' form set the same values on that writer's own merge policy. Instead every config that was not given a codec holds the one default codec instance (Codec.getDefault(), also what Codec.forName(\"Lucene104\") returns), whose CompoundFormat keeps the settings in mutable fields, so the second writer writes its force-merged, naturally merged and addIndexes(CodecReader) segments non-compound, and the settings stay after the first writer closes.",
   "impact_class": "minor",
   "introduced_commit": "6643a5dbe1ed (6643a5dbe1ed6d3a4b933c90beed60cfe44b5992, GITHUB#15295 'Switching to a fixed CFS threshold' by shubhamsrkdev, merged to main by stefanvodita 2026-01-23; main only): it added the mutable compound-file settings (instance fields and setters) to CompoundFormat, made IndexWriter take the merge and addIndexes(CodecReader) compound decisions from the codec's CompoundFormat, removed the per-merge-policy settings and switched lucene/benchmark CreateIndexTask to iwConf.getCodec().compoundFormat().setShouldUseCompoundFile(...) [exec]. Pre-existing ingredients that make the instance shared: one cached CompoundFormat per codec instance (eafeb664340, 2021; Lucene104Codec 00f2b01e798) and codec = Codec.getDefault() for every new config (a11013a9901, 2012). Documentation path: the MIGRATE.md recipe was added by 9c427a31717 (#15691, 2026-02-19, first in a non-compiling iwc.getConfig().getCodec() form [read]) and given its current iwc.getCodec().compoundFormat() form by 120b3bc18da (#16756, 2026-10-07). Cited as the source of the change, not as blame.",
   "introduced_date": "2026-01-23 (author and commit date of 6643a5dbe1ed; recipe text 2026-02-19, current form 2026-10-07)",
   "first_affected_version": "unreleased (main since 6643a5dbe1ed, then 11.0.0-SNAPSHOT; no release contains it; it would first ship in 11.0.0 unless fixed; branch_11x carries the same recipe [read])",
   "affected_versions": "[exec] main 6643a5dbe1ed (introducing commit, plain-javac build: JUnit fails with -ea, -da and -Dtests.codec=Lucene104) and 645d4fe14a20 (current upstream head, 2026-10-28: JUnit fails with -ea and -da, also with -Dtests.codec=Lucene104 and on 12 of 12 other seeds; a plain-JVM run without the test framework fails the same way); ea57360912ed. [read] no commit between them touches CompoundFormat.java, Codec.java, Lucene104Codec.java or the recipe; branch_11x has the identical recipe and file heads. Not affected [exec]: 9.12.3, 10.5.2, the 10.6.0 RC (branch_10_6 4ae946e5a9b9) and main's parent d455fefc6b63, where the CompoundFormat setters do not exist (the JUnit does not compile) and a port of the recipe's 'Before' form (settings on writer A's own merge policy) leaves writer B unchanged. All runs on Linux aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16938",
    "https://github.com/apache/lucene/issues/15616",
    "https://github.com/apache/lucene/issues/15295",
    "https://github.com/apache/lucene/issues/14959",
    "https://github.com/apache/lucene/issues/15691",
    "https://github.com/apache/lucene/issues/16756"
   ],
   "doc": "",
   "repro": "repro/LFV-1017/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-099",
   "priority": "low",
   "priority_rank": 938,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter NRT reader pool (readers shared with merges)",
   "title": "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)",
   "summary": "You let a merge start on segments that no NRT reader has opened yet (for example segments committed after the last refresh) and open an NRT reader with DirectoryReader.open(writer) while that merge runs. You expect that reader's searches to read the files through inputs opened for searching, as DirectIODirectory ('For all other cases (searching, writing) we delegate to the provided Directory instance') and DirectPostingsFormat ('at read time loads and stores all terms and postings directly in RAM') document. Instead the NRT reader gets the very SegmentReaders the merge opened with the MERGE IOContext, so with DirectIODirectory its searches read through the merge's direct-I/O inputs, with DirectPostingsFormat it searches the on-disk terms instead of the RAM postings, and with ADVISE_BY_CONTEXT its stored fields, vectors and HNSW graph are mapped with SEQUENTIAL advice; the hits stay correct.",
   "impact_class": "minor",
   "introduced_commit": "49684b82701b (branch_4x svn r1537832, 'LUCENE-5189: add NumericDocValues field updates', the 4.x backport of LUCENE-5189 = GitHub #6253): IndexWriter.mergeMiddle switched from rld.getMergeReader(context), a separate merge reader that NRT readers never received, to rld.getReaderForMerge(context) = getReader(context), the shared pooled reader [exec]; the design change came from trunk, LUCENE-5127 (GitHub #6191) 'nuke mergeReader' (f85ac0b6f91 on a dev branch, merged to trunk as 02a2f383b21), which first reached a release through trunk in 6.0.0 [read]",
   "introduced_date": "2013-11-01 (49684b82701, branch_4x); trunk design change 2013-07-29 (02a2f383b21)",
   "first_affected_version": "4.6.0 [exec] (last unaffected release 4.5.1 [exec])",
   "affected_versions": "every release from 4.6.0 through 10.5.2, main ea57360912ed, a9779ef3c193 and 645d4fe14a2, and branch_10x 657014b3c579 [exec]. Executed (follow-up history probe, public API, opens attributed by phase): 4.6.0 (-ea and -da), 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) fail; the finder JUnit fails on main (-ea, -da), 10.5.2 and 9.12.3 (9.x port); the independent reproduction's tests fail on main, 10.5.2, 10.2.2 and 9.12.3 [exec]. The code path is identical at all 112 release tags from 4.6.0 to 10.5.2 in the history clone [read] (8.9.0-8.11.x are not in the clone; 8.11.4 was executed). Not affected: 4.0.0 and 4.5.1 [exec], all 11 tags 4.0.0-alpha to 4.5.1 [read]. The visible consequence depends on the version: DirectIODirectory (9.0+) [exec] and its predecessor NativeUnixDirectory (4.6-8.x) [read]; DirectPostingsFormat [exec]; SEQUENTIAL advice by default on 10.0-10.2 and on 9.x with native access, opt-in (ADVISE_BY_CONTEXT) on 10.3+/main [read]. Not fixed upstream at main 645d4fe14a2 or branch_10x 657014b3c579 [exec]; #16905 (merged 2026-10-26: main 49483e82b35, branch_10_6 940768fb0cd, branch_10x 657014b3c579) covers sequential vector values only [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16905",
    "https://issues.apache.org/jira/browse/LUCENE-2793",
    "https://github.com/apache/lucene/issues/3867",
    "https://issues.apache.org/jira/browse/LUCENE-3292",
    "https://github.com/apache/lucene/issues/4365",
    "https://issues.apache.org/jira/browse/LUCENE-4998"
   ],
   "doc": "",
   "repro": "repro/LFV-099/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-585",
   "priority": "low",
   "priority_rank": 939,
   "novelty": "known",
   "withheld": false,
   "area": "misc / store: DirectIODirectory x core codecs merge-time re-open (the IndexInput#isEfficientFor gate in Lucene99FlatVectorsReader and Lucene90CompressingStoredFieldsReader, #16883/#16905)",
   "title": "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",
   "summary": "You open an index with DirectIODirectory over the default MMapDirectory, keep an NRT reader open and let IndexWriter merge the segments that reader holds. You expect the merge to read their vector (.vec) and stored fields (.fdt) data with direct I/O while searches go through the delegate, as DirectIODirectory's javadoc says and as #16905 (which names this directory as the case it restores) intends. Instead the codec readers reuse the input the search already holds whenever that input says it is efficient for the merge, DirectIODirectory's inputs never answer that question (the default answer is yes), so the merge reads through the page cache, and with an advising delegate a sequential search read after the merge goes through the merge's direct-I/O input.",
   "impact_class": "minor",
   "introduced_commit": "ea57360912ed31ae2f2c0a7a5fef422ddf4e06b0 (apache/lucene#16883 'Open files twice for sequential reads only when it helps', by jimczi, merged 2026-10-24, milestone 10.6.0): it added IndexInput#isEfficientFor (default true) and made the vectors and stored-fields readers re-open .vec/.fdt for a merge only when the held input answers false, and DirectIODirectory got no override [exec]. Kept and widened by 49483e82b35 (apache/lucene#16905 'Open merges with a merge context again', merged 2026-10-26): it restored IOContext.merge() for the re-open but kept the gate and added merge/sequential-search input sharing plus LeafReader#getFloatVectorValues(String, DataAccessHint), which introduced manifestation 3 [exec]",
   "introduced_date": "2026-10-24 (#16883); 2026-10-26 (#16905, manifestation 3)",
   "first_affected_version": "10.6.0 (released 2026-10-29) is the first release that contains #16883 (10.5.2 does not). #16883 (2763db11b0a, 1309534296e) and #16905 (940768fb0cda, 657014b3c579) are on branch_10_6 (head 4ae946e5a9b9) and branch_10x (head 657014b3c579), whose Lucene99FlatVectorsReader has the vectorDataFor gate and whose DirectIODirectory has no isEfficientFor [branch_10x executed at 657014b3c579 on 2026-10-29; branch_10_6 read through the GitHub API 2026-10-26], so 10.6.0 is the first affected release. A related symptom (manifestation 1 by another mechanism) is in every release since 9.0.0 [exec] and known upstream (see affected_versions)",
   "affected_versions": "main ea57360912ed (#16883, 2026-10-24) through a9779ef3c193 [exec]: manifestation 1 (default delegate) fails on both; manifestation 2 (advising delegate, merge after a SEQUENTIAL search read) fails on both, and on ea57360912ed the advising-delegate control fails too, because there the readers re-open with the reader's own context, which #16905 fixed; manifestation 3 (a SEQUENTIAL search read after the merge goes through the merge's DirectIOIndexInput) only since 49483e82b35 (#16905, 2026-10-26) [exec]. branch_10x 657014b3c579 (#16883 1309534296e, #16905 657014b3c579): all three manifestations [exec]; branch_10_6 carries both commits [read]. Not affected: main 7cecf795236 (2026-10-21, after #16749/#16684/#16769, before #16883) passes 3 of 3 with -ea and -da [exec]; the SEQUENTIAL-API test does not compile there (API absent). Related release-era symptom with another mechanism (merge instances read through the search inputs and never re-open, so isEfficientFor plays no part): merges of NRT-open segments never use direct I/O on 9.0.0, 9.12.3 and 10.5.2 [exec], known upstream (#13920). Not fixed on upstream main 645d4fe14a2 [exec]. All runs on JDK 25, local, seed DEADBEEF unless stated",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16883",
    "https://github.com/apache/lucene/issues/16905",
    "https://github.com/apache/lucene/issues/13920",
    "https://github.com/apache/lucene/issues/16684",
    "https://github.com/apache/lucene/issues/16749",
    "https://github.com/apache/lucene/issues/3867"
   ],
   "doc": "",
   "repro": "repro/LFV-585/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-068",
   "priority": "low",
   "priority_rank": 940,
   "novelty": "new",
   "withheld": false,
   "area": "search / HNSW",
   "title": "HNSW addConnections descends from the worst upper-level candidate instead of the best",
   "summary": "During merge-time HNSW graph repair and rebalancing, addConnections descends through the upper levels to find entry points. You expect it to descend from the best candidate, as its javadoc says. Instead it pops from a min-heap and descends from the worst; the naive fixes cut distance computations by 10-30% but lowered recall in 8 of 8 region-delete configurations.",
   "impact_class": "minor",
   "introduced_commit": "#15003 (ef10476d98a) [read]",
   "introduced_date": "2025-12-01 (#15003 merged)",
   "first_affected_version": "10.4.0 [exec]",
   "affected_versions": "10.4.0, 10.5.0, 10.5.1, 10.5.2, 10.6.0 and main 645d4fe14a20 [exec]; not affected: 10.3.2 and earlier [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-068.html",
   "repro": "repro/LFV-068/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1105",
   "priority": "low",
   "priority_rank": 941,
   "novelty": "known",
   "withheld": false,
   "area": "codecs / backward-codecs Lucene99 scalar-quantized vectors (OffHeapQuantizedByteVectorValues)",
   "title": "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)",
   "summary": "With the packed int4 Lucene99 supplier scorer and scoring ordinal 1, score(1) should be the same before and after score(0); it is 0.99679184 before and 0.91709924 after, because getScoreCorrectionConstant(0) on a cache miss overwrites the correction cached for lastOrd. In 10.2.x/10.3.x graph building goes through this scorer, so a forceMerge of a compress=true 4-bit field builds a different graph; searches are not affected.",
   "impact_class": "minor",
   "introduced_commit": "#14181 (48884e76e08, 2025-02-06) [read]",
   "introduced_date": "2025-02-06 [read]",
   "first_affected_version": "10.2.0 [exec]",
   "affected_versions": "10.2.0, 10.3.2 and 10.4.0 [exec]; 10.5.2 and 10.6.0 (released) [exec]; main 645d4fe14a20 and e1faeba08bde with -ea and -da [exec]; 9.12.3 not affected [exec]; end-to-end (forceMerge) only on the 10.2.x/10.3.x writers [exec]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/pull/16830",
    "https://github.com/apache/lucene/issues/16956"
   ],
   "doc": "",
   "repro": "repro/LFV-1105/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-423",
   "priority": "low",
   "priority_rank": 942,
   "novelty": "known",
   "withheld": false,
   "area": "search / filtered kNN (ExitableDirectoryReader with the 9.x HNSW vectors readers in backward-codecs)",
   "title": "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",
   "summary": "On main you open an index whose vector segment was written by Lucene 9.8.0 (Lucene95 HNSW format), wrap the reader in ExitableDirectoryReader with a timeout that never fires, and run a KnnFloatVectorQuery (k=10) with a TermQuery filter that matches about 15% of the documents and the default search strategy. You expect the same graph walk and the same hits as on the unwrapped reader, because the wrapper only adds timeout checks and the documented threshold (60%; 0 never, 100 always) says the filtered HNSW search runs. Instead the wrapper hands the 9.x reader an anonymous Bits instead of the filter's BitSet, the reader therefore sizes the filter as 0 and never uses filtered search (even KnnSearchStrategy.Hnsw(100) returns exactly the Hnsw(0) hits), and 3 of the top 10 documents differ; every hit is still a valid, live filter match.",
   "impact_class": "minor",
   "introduced_commit": "0614fe9ebd7b46fede610f0bb59b2817de72e7c3 (GITHUB#14160 'Add new Acorn-esque filtered HNSW search heuristic', by GitHub benwtrent; branch_10x backport a5bd705c2da567942493028eb95f7e27d79ce35d) added the 4-argument HnswGraphSearcher.search overload that sets filteredDocCount only 'if (acceptOrds instanceof BitSet)' (otherwise 0, so no filtered search) and made the Lucene91/92/94/95 graphs report the stored maxConn, so the 9.x readers' existing 4-argument calls became strategy-aware [read]. Pre-existing ingredient: LUCENE-10411 / #833 (GitHub zacharymorn, main 96036bca9f6, 2022-05-12, first release 9.2.0) made ExitableDirectoryReader pass an anonymous timeout-checking Bits, harmless until #14160. #15011 (GitHub shubhamvishu, 310ef63d827, 10.3.0) moved only Lucene99HnswVectorsReader to AcceptDocs#cost() sizing and kept the 4-argument calls in the 9.x readers; #16741 (8476457b875, 2026-10-15) let main open 9.x indexes through the standard DirectoryReader.open, widening reach on main",
   "introduced_date": "2025-02-13 (0614fe9ebd7 on main and the backport a5bd705c2da on branch_10x)",
   "first_affected_version": "10.2.0 [exec] (only with an explicit KnnSearchStrategy.Hnsw(threshold > 0); the branch_10x default threshold is 0); with the default strategy only main (unreleased 11.0, default threshold 60) [exec]",
   "affected_versions": "Releases 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1 and 10.5.2 with an explicit KnnSearchStrategy.Hnsw(threshold > 0) on 9.x-format HNSW segments [exec]; on 10.2.0-10.2.2 the current Lucene99 format is also affected with an explicit strategy [exec], fixed for that format from 10.3.0 on by #15011 [exec]; main ea57360912ed and 645d4fe14a2 with the default strategy [exec]; the same releases pass with the default strategy (threshold 0) [exec]; not affected: 9.x (9.12.3), 10.0.0 and 10.1.0, which have no filtered HNSW search [exec]. Formats: Lucene95 (9.5-9.8) executed; Lucene91/92/94 make the same 4-argument call [read]; Lucene90 is not affected (its graph reports UNKNOWN_MAX_CONN). 10.6.0 (released 2026-10-29; branch_10_6 RC1 4ae946e5a9b) is affected with an explicit Hnsw(threshold > 0) [exec], and so is branch_10x 657014b3c579 [read]. Not fixed upstream as of main 645d4fe14a2 and branch_10x 657014b3c579 (2026-10-29); open PR #14996, still unmerged, would fix it",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/14996",
    "https://github.com/apache/lucene/issues/15011",
    "https://github.com/apache/lucene/issues/15498",
    "https://github.com/apache/lucene/issues/16705",
    "https://github.com/apache/lucene/issues/16586",
    "https://github.com/apache/lucene/issues/16205"
   ],
   "doc": "",
   "repro": "repro/LFV-423/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-035",
   "priority": "low",
   "priority_rank": 943,
   "novelty": "new",
   "withheld": false,
   "area": "search / sorting",
   "title": "DoubleValuesSource and LongValuesSource sort fields never equal identical ones",
   "summary": "You create two identical SortFields from the same DoubleValuesSource or LongValuesSource and compare them. You expect them to be equal. Instead equals returns false; search results are unaffected.",
   "impact_class": "minor",
   "introduced_commit": "3f24fd81c83 (LUCENE-5325 'Add LongValuesSource and DoubleValuesSource in core', Alan Woodward; branch_6x backport e2aa2b63846), which created DoubleValuesSource and LongValuesSource with sort fields around a new comparator source that has no equals/hashCode [read]; LUCENE-7609 (8b055382d6c, 2017-01-05; branch_6x 776087eef48) then routed Expression#getSortField through DoubleValuesSource#getSortField and deleted ExpressionSortField, so expression sorts lost their value equality [exec]; both first released in 6.4.0",
   "introduced_date": "2016-12-28 (3f24fd81c83 author date; committed 2016-12-29; LUCENE-7609 authored 2017-01-05)",
   "first_affected_version": "6.4.0",
   "affected_versions": "every lucene-core release from 6.4.0 to 10.6.0 (87 releases) and main 645d4fe14a20 [exec]; 6.3.0 correct [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-035.html",
   "repro": "repro/LFV-035/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1236",
   "priority": "low",
   "priority_rank": 944,
   "novelty": "new",
   "withheld": false,
   "area": "core / search: DisjunctionMaxQuery (equals and hashCode contract)",
   "title": "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)",
   "summary": "You build DisjunctionMaxQuery([f:x], 0.0f) and DisjunctionMaxQuery([f:x], -0.0f): equals returns true both ways (the constructor accepts -0.0f, and equalsTo compares the tie-breakers with ==, under which 0.0f == -0.0f), so by the Object#hashCode contract, which Query's javadoc requires so that QueryCache works, the two hash codes must be equal. Instead they differ by exactly 2^31, because hashCode adds Float.floatToIntBits(tieBreakerMultiplier), which is 0x00000000 for 0.0f and 0x80000000 for -0.0f. Hash-based structures therefore see two different queries: the query cache keeps a separate entry, a HashSet holds both and a BooleanQuery with both as FILTER clauses is not de-duplicated, while hits and scores stay the same.",
   "impact_class": "minor",
   "introduced_commit": "3c10854e00fc9387a508877dfd0aa00a3d31d053 (svn r345089, Yonik Seeley, 2005-11-16, 'new DisjunctionMaxQuery/DisjunctionMaxScorer from Chuck Williams: LUCENE-323', migrated as apache/lucene#1401): the commit that added the class wrote equals with 'this.tieBreakerMultiplier == other.tieBreakerMultiplier' and hashCode with Float.floatToIntBits(tieBreakerMultiplier), with no constructor check; the pair survived LUCENE-6590 (962313b83ba, 2015, hashCode into the 31*h form), LUCENE-7277 (e44509f2dfc, 2016, == moved into equalsTo) and the LUCENE-9570 reformat (2d6ad2fee6d, 2020); the [0, 1] range check of LUCENE-8097 (e3f90385b49, 2017-12-26, first released 8.0.0) is false for -0.0f, so it neither introduced nor closed the defect [read]",
   "introduced_date": "2005-11-16 (3c10854e00f)",
   "first_affected_version": "1.9 [read]",
   "affected_versions": "every release from 1.9 through 10.6.0 (released 2026-10-29, 4ae946e5a9b), branch_10_6 and main 5adff78bb168 (12.0.0-SNAPSHOT); not fixed anywhere (no upstream commit has touched DisjunctionMaxQuery.java since bc601411a31, author date 2026-08-19; upstream main head 1c2072f0284, author date 2026-11-02) [read]. Executed [exec], each failing for the stated reason (equal both ways, hash codes differing only in bit 31): main with -ea and -da, 10.6.0 (finder -da; history step -ea and -da; the independent reproduction -da; the cross-model review re-run -da), 10.5.2 (the independent reproduction -da), 10.0.0 and 9.12.3 (history step -da; 9.12.3 also finder and the independent reproduction), 9.0.0, 8.11.4, 8.0.0, 7.7.3 and 1.9.1 (history step -da, with a plain main() making the same check because the test framework moved packages in 9.1). The other releases by reading: all 145 release tags from 1.9 to 10.6.0 in the history clone contain both the == and the floatToIntBits line, and javap of the untagged 8.8.2-8.11.3 jars shows the same. Not affected: 1.4.3 and earlier (no DisjunctionMaxQuery). Not new in 10.6. All runs on Linux aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1236.html",
   "repro": "repro/LFV-1236/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-899",
   "priority": "low",
   "priority_rank": 945,
   "novelty": "known",
   "withheld": false,
   "area": "expressions / SimpleBindings binding resolution (add(String, Expression), getDoubleValuesSource) and the ExpressionValueSource constructor",
   "title": "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)",
   "summary": "You bind named expressions that use each other with SimpleBindings.add(String, Expression), which the class javadoc documents ('This can be used to reference expressions from other expressions'), and some of them share a sub-expression, for example X1 = L0 + R0 with L0 = X0 + 1 and R0 = X0 * 2, repeated in a chain. You expect getDoubleValuesSource to build each binding a bounded number of times, as building the same graph eagerly with add(String, DoubleValuesSource) does. Instead every reference re-applies expression::getDoubleValuesSource, so the shared graph is expanded into a tree with one ExpressionValueSource per path: 3*(2^d - 1) objects for a chain of d diamonds (196,605 for 49 bindings), and building the source of 70 or more such bindings exhausts a 1 GB heap before any document is read, while the computed values stay correct.",
   "impact_class": "minor",
   "introduced_commit": "2f169863cb4c140d96ee8dcb3daa2bcd23008c38 on trunk / 5c6664e2c39acd99b190873265e1c85d48728ad8 on branch_4x (the copy that shipped in 4.6.0): 'LUCENE-5231: better interoperability of expressions with valuesource' by rmuir, committed from a JIRA patch with no pull request (the issue is now #6295). It moved the variable lookups from ExpressionValueSource.getValues (once per segment, memoised by name in a valuesCache) into the ExpressionValueSource constructor. The other ingredient is older: since the module's first commit c73f175c71ee ('LUCENE-5207: initial patch from ryan', #6271, 2013-09-13) SimpleBindings has answered every lookup of an Expression binding by building a new source from it, which cost nothing while the constructor did no lookups. LUCENE-7609 (8b055382d6c8, 6.4.0) and LUCENE-9338 (ed3caab2d86b, 8.6.0) carried both pieces forward unchanged; git blame on main shows those refactors, not the origin [read]",
   "introduced_date": "2013-09-21 (LUCENE-5231, trunk 03:37:43Z and branch_4x 03:39:07Z; author date = commit date); ingredient 2013-09-13 (LUCENE-5207)",
   "first_affected_version": "4.6.0 [exec] (2013-11-22, the first release of the expressions module; 4.5.1 has no expressions module, the probe does not compile [exec])",
   "affected_versions": "every lucene-expressions release on Maven Central, 4.6.0 to 10.5.2 (121 releases) [exec], the branch_10_6 head 4ae946e5a9b9 (10.6.0, released 2026-10-29) [exec] and main a9779ef3c193 [exec]. Not fixed upstream: the last commit on SimpleBindings.java is 378ca8d1bbf3 (#15573, javadoc markup, author and commit date 2026-01-15) and on ExpressionValueSource.java 43c0d72b94cf (2023-09-16), checked on upstream main by author and committer date on 2026-10-28 [read]; no open PR touches either file. All runs with JDK 25 on aarch64 Linux.",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-9338",
    "https://github.com/apache/lucene-solr/pull/1444",
    "https://github.com/apache/lucene/issues/9620",
    "https://issues.apache.org/jira/browse/LUCENE-8574",
    "https://github.com/apache/lucene/issues/16880",
    "https://github.com/apache/lucene/issues/16926"
   ],
   "doc": "",
   "repro": "repro/LFV-899/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-905",
   "priority": "low",
   "priority_rank": 946,
   "novelty": "new",
   "withheld": false,
   "area": "expressions / SimpleBindings.validate() (cycle and missing-reference check, CycleDetectionBindings)",
   "title": "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)",
   "summary": "You build a chain of named expressions with SimpleBindings.add(String, Expression), each using the previous one (x1 = x0 + 1, x2 = x1 + 1, ..., x2000 = x1999 + 1), and call bindings.validate(), whose javadoc says it 'Traverses the graph of bindings, checking there are no cycles or missing references'. You expect a graph check that costs about as much as resolving every binding once, as on 8.5.2, where validate() of these 2000 bindings took about 100 ms. Instead, since 8.6.0 validate() starts a fresh walk from every binding, re-walks everything below it, and copies the whole current path into a new LinkedHashSet at every step, so its cost grows with the cube of the chain length: about 45 s for 2000 bindings and about 575 s for 4000 (at 1000 bindings it allocates 389.9 times the bytes of resolving every binding once), although the answer is still correct.",
   "impact_class": "minor",
   "introduced_commit": "ed3caab2d86b69ec4b3ed8e787827c0931b43d1b on main (squash merge of apache/lucene-solr#1444, LUCENE-9338 'Clean up type safety in SimpleBindings', now #10378, by romseygeek) and its branch_8x backport b66b970d1b06e56b0d685613855be5ef6d1a2c60, the copy that shipped in 8.6.0. It replaced the old validate() (build every Expression binding through the bindings and treat a StackOverflowError as a cycle: no path set, quadratic on a chain) with CycleDetectionBindings; the per-step path copy (new LinkedHashSet + addAll(parents)) came in PR commit f31cb0601615 'Detect recursion at more than one level', written to catch a cycle that does not pass through the origin, which a reviewer (jpountz) had found [read]",
   "introduced_date": "2020-04-24 (ed3caab2d86b: author date = commit date 2020-04-24T09:23:50Z; b66b970d1b06: same author date, committed 71 s later; PR commit f31cb0601615 authored 2020-04-23T13:44:37Z)",
   "first_affected_version": "8.6.0 [exec] (first main-line release 9.0.0 [exec]; last unaffected release 8.5.2 [exec])",
   "affected_versions": "every lucene-expressions release from 8.6.0 to 10.5.2 (49 releases: 8.6.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2), 10.6.0 (the branch_10_6 head 4ae946e5a9b9, the RC1 revision) and main a9779ef3c193 [exec]. Not affected: 4.6.0-8.5.2 (72 releases) carry the older validate(), quadratic on chains [exec]; before 4.6.0 there is no expressions module. The secondary symptom (786,308 expression builds for 49 bindings that share sub-expressions) is identical on every version tested, 5.5.5 to main [exec], so it predates the regression. Not fixed upstream: SimpleBindings.java last changed by 378ca8d1bbf3 (#15573, javadoc markup, author and committer date 2026-01-15), and the logic of validate() and CycleDetectionBindings is unchanged since ed3caab2d86b (later commits only reformatted the file or changed javadoc and lambda parameters); no open PR touches the file (checked 2026-10-28) [read]. All runs with JDK 25 on aarch64 Linux.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-905.html",
   "repro": "repro/LFV-905/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1088",
   "priority": "low",
   "priority_rank": 947,
   "novelty": "new",
   "withheld": false,
   "area": "search / field sorting: index-sort early termination (IndexSortedLeafFieldComparator) + NumericComparator points-based sort pruning (competitive iterator)",
   "title": "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)",
   "summary": "You search a MultiReader over two indexes for the top 10 by a long field f: the first index has no index sort and 2,000 hits, so the default 1,000-hit threshold is crossed there, and the second (4,096 documents) is sorted by f, so the search stops in it after a few documents. You expect that sorted segment to read no points: the new IndexSortedLeafFieldComparator says the comparator's skipping work, 'e.g. building iterators from points, is redundant work' there, and 10.6.0 reads 0. Instead, since #16857 the comparator still sees the threshold flag that the first segment set on the comparator shared by all segments, so it walks the sorted segment's BKD tree and builds a points iterator that nobody uses (512 point doc IDs here, up to about cost/7 per segment); the top 10 is still right, only the work is wasted.",
   "impact_class": "minor",
   "introduced_commit": "70a428b5ba90cdbcf3c8380e21b006a68b4dcb85 (apache/lucene#16857 'Consolidate Sort pruning logic', author romseygeek (Alan Woodward), merged to main 2026-10-29; branch_11x backport 203699279f5 the same day, same patch-id) [exec]. #16857 removed FieldComparator#disableSkipping and LeafFieldComparator#disableSkipping, which 10.6.0's TopFieldCollector called on each segment that its index sort terminates early ('Early termination handles this segment; skipping work in the comparator is redundant.'), and replaced them with IndexSortedLeafFieldComparator, which suppresses the delegate's skipping only by hiding competitiveIterator() and not forwarding setHitsThresholdReached() when not paging [read]. Older ingredients, harmless before: the comparator-wide 'protected boolean hitsThresholdReached' (99220677fe4, LUCENE-9449, 2020) [read]; per-segment index-sort early termination (#16434 / GITHUB#14399, 10.6.0) made the mixed-leaf precondition reachable but dropped the points builder per segment [read].",
   "introduced_date": "2026-10-29 (author date = commit date of 70a428b5ba9, 2026-10-29; the branch_11x backport 203699279f5 has the same author date, committed 2026-10-29)",
   "first_affected_version": "unreleased (11.0.0 would be the first release: #16857's CHANGES entry is under Lucene 11.0.0); 10.6.0, released 2026-10-29 from 4ae946e5a9b, and every earlier release are not affected; the last unaffected main commit is e0fa3535ea5",
   "affected_versions": "[exec] upstream main e1faeba08bd (native 12.0.0-SNAPSHOT build, stock jars): the one-method minimal test fails ('expected:<0> but was:<2>') with seed DEADBEEF (-ea and -da) and seeds C0FFEE and 7A11CE (-ea); the earlier counting version of the test fails with -ea and -da ('expected:<0> but was:<512>') with seeds DEADBEEF, 1, C0FFEE and 12345678 (finder), 7A11CE (the intended-behaviour check), 1234ABCD (the adjudication) and C0FFEE (registration check, 2026-11-02); main 70a428b5ba9 = #16857 (shadow over the 645d4fe jars, -ea and -da). [read] branch_11x since 203699279f5: at head da3ea39fa59 IndexSortedLeafFieldComparator, NumericComparator, TopFieldCollector and FieldValueHitQueue are identical to main; upstream main 254ce48660d (2026-11-02) and branch_11x have no commit on these files after #16857 and #16947 (check 2026-11-02). Not affected [exec]: main parent e0fa3535ea5 (-ea, -da), main 645d4fe14a2 (-ea, -da), 10.6.0 = 4ae946e5a9b (-ea, -da; the same test with the 10.x 'throws IOException' signatures). [read] branch_10_6 (the 10.6.x bugfix line) has no #16857 and still calls comparator.disableSkipping(); branch_10x was retired by #16911 before #16857. 10.5.2 and 9.12.3 also fail the test's assertion (512), but that is NOT this bug: before 10.6 the first segment decides index-sort early termination for the whole search, so the sorted segment is not terminated early (109 of 4,096 documents counted) and the 512 doc IDs build the competitive iterator it really uses; they are not affected.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1088.html",
   "repro": "repro/LFV-1088/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-126",
   "priority": "low",
   "priority_rank": 948,
   "novelty": "new",
   "withheld": false,
   "area": "store / MMapDirectory read advice (MemorySegmentIndexInput slices, compound files)",
   "title": "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())",
   "summary": "You take a slice of an MMapDirectory file with IndexInput#slice(name, offset, length, IOContext) and a context that asks for RANDOM or SEQUENTIAL read advice, as the compound-file reader does for each inner file, and you expect the madvise hint to land on the slice's own pages. When the slice starts inside an mmap chunk and crosses into the next chunk, the hint is applied from the start of that chunk instead: in the repro, a slice of [512 KiB, 1.5 MiB) with 1 MiB chunks puts the RANDOM hint on [0, 1 MiB), so other inner files of a compound file get it, and a short slice that straddles a chunk boundary can get none of its own pages advised. Reads and query results stay correct; only the operating system's readahead and caching behaviour on those pages changes.",
   "impact_class": "minor",
   "introduced_commit": "cfbf8d93df81 (apache/lucene#13467 'Honor read advice on compound files.', author jpountz, merged on main before the 10.0 branch was cut, no separate backport) added IndexInput#slice(String, long, long, ReadAdvice), the shared advise() helper and the call slice.advise(0, slice.length, ...) that advises from the start of segments[0]; the helper's segment selection was moved out of prefetch() (#13337 3003731aa942, #13363 46f1f95ceb03), which had the same missing MultiSegmentImpl offset until #14109 (d4f0a3244e5 on main, cfeba19994e on branch_10x, first released in 10.2.0) fixed it by overriding prefetch() only [read]; the compound-file path became reachable with #13907 (e2636c648df on main, b8bfffa3681 on branch_10x, 10.1.0); #14482 (bb76f0a2d98) replaced the ReadAdvice overload by slice(..., IOContext) and kept the same call",
   "introduced_date": "2024-06-21 (#13467 merged); compound-file reach 2024-10-15 (#13907); the sibling prefetch() fix #14109 on 2025-01-08 left this caller unchanged",
   "first_affected_version": "10.0.0 [exec] for direct IndexInput#slice(..., ReadAdvice) calls; 10.1.0 [exec] for the compound-file path (#13907)",
   "affected_versions": "every 10.x release: 10.0.0 through 10.6.0 (13 releases on Maven Central) and main ea57360912ed; executed failing with direct-slice repros (each with a passing single-chunk control): 10.0.0, 10.1.0, 10.2.2 (-ea and -da), 10.3.0, 10.5.2, 10.6.0 (-ea and -da, 2026-11-01) and main (-ea and -da) [exec]; a default-settings compound-file test (no setReadAdvice) fails on 10.1.0 and 10.2.2 (-ea and -da) and passes for the same index with 64 MiB chunks, while on 10.3.0, 10.5.2 and main it passes because nothing is advised without opt-in [exec]; on 10.0.0 the compound reader sliced without advice, so only direct calls are affected there [exec]; the other 10.x releases by source identity (every 10.x tag has the slice.advise(0, ...) call and no advise() override in MultiSegmentImpl) [read]; unaffected: 9.12.3 and every earlier release, which have no slice-with-advice API (the repro does not compile on 9.12.3; the compound test passes) [exec]; branch_10x and branch_10_6 have the same code [read], and 10.6.0 (released 2026-10-29) is affected [exec]; not fixed upstream [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-126.html",
   "repro": "repro/LFV-126/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-081",
   "priority": "low",
   "priority_rank": 949,
   "novelty": "new",
   "withheld": false,
   "area": "search / query cache",
   "title": "LRUQueryCache MinSegmentSizePredicate overflows maxDoc * 2, so segments of 2^30+ docs are never cached",
   "summary": "You use the query cache with its MinSegmentSizePredicate on a segment of 2^30 or more documents. You expect large segments to be cacheable. Instead maxDoc * 2 overflows int, the predicate rejects them from 2^30 docs on, and such a segment is never cached.",
   "impact_class": "minor",
   "introduced_commit": "8e15c665be9 (#12147)",
   "introduced_date": "2023-02-16",
   "first_affected_version": "9.6.0 [exec]",
   "affected_versions": "every release from 9.6.0 through 10.6.0 and main 645d4fe14a20 (`maxDoc * 2 > averageTotalDocs` is in LRUQueryCache.java at every tag from 9.6.0 on [read]); the minimal test fails on main (-ea and -da) and on the 9.6.0 (-ea and -da), 9.12.3 (-da), 10.0.0 (-da), 10.5.2 (-ea and -da) and 10.6.0 (-ea and -da) release jars (SHA-1 checked against Maven Central) [exec]; 9.5.0 and earlier are not affected (a float ratio; the same check with the 9.5.0 constructor passes) [exec]; not fixed upstream (main 2f424fd428da, 2026-10-30) [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-081.html",
   "repro": "repro/LFV-081/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-362",
   "priority": "low",
   "priority_rank": 950,
   "novelty": "known",
   "withheld": false,
   "area": "codecs / bloom (BloomFilteringPostingsFormat, DefaultBloomFilterFactory, FuzzySet sizing)",
   "title": "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)",
   "summary": "You index a primary key into a field that uses BloomFilteringPostingsFormat with the default filter factory, whose javadoc promises a filter targeting about 10% false positives sized from the segment's doc count, and you expect lookups of absent keys to be rejected quickly in every segment. For a segment of 226,279,579 docs or more, FuzzySet.createOptimalSet's int expression 2 * setSize wraps negative, the size lookup falls back to its smallest size (63) and the hash count rounds to 0, so the filter has 64 bits, never sets one and answers MAYBE for every key, and the saturation check meant to retire useless filters sees 0% saturation and saves it. Results stay correct, but every absent-key lookup on that segment goes to the terms dictionary: the repro's filter rejects 0 of 1,000 absent keys, while one doc fewer gives a 2^30-bit filter with 3 hash functions that rejected 2,000 of 2,000 in an independent test.",
   "impact_class": "minor",
   "introduced_commit": "5acca826330b on main, 'Reduce bloom filter size by using the optimal count for hash functions. (#11900)' (PR apache/lucene#11900 by GitHub jfboeuf, merged by jpountz; branch_9x backport d1e4a3a44d89 the same day, with an identical FuzzySet.java). It added FuzzySet.createOptimalSet with the int expression getNearestSetSize(2 * setSize) and optimalK = round(setSize / n * ln 2), the hashCount loops in addValue and contains, and DefaultBloomFilterFactory's call createOptimalSet(maxDoc, 0.1023f); getNearestSetSize itself (round down, smallest-size fallback) dates from LUCENE-4069 (2012) but was never passed a negative value before [read]",
   "introduced_date": "2023-02-01",
   "first_affected_version": "9.6.0 [exec] (CHANGES 9.6.0 Optimizations, GITHUB#11900). 9.5.0 [exec] and earlier are not affected by this defect, but their older sizing (createSetBasedOnQuality) already failed at these sizes in a different way: from 226,259,988 docs it returns size -1 and the first key throws (see notes)",
   "affected_versions": "every release from 9.6.0 to 9.12.3 and from 10.0.0 to 10.5.2 (25 releases) plus main ea57360912ed; not fixed. Executed: the follow-up history probe (factory and write path at 226,279,579, controls at 226,279,578 and 100,000,000) fails 2 of 6 on 9.6.0, 9.12.3, 10.5.2 and main (each -ea and -da) and on 10.0.0 (-ea); the finder repro fails on main (-ea, -da), 10.5.2, 9.12.3 and 9.6.0 (the 9.x variant); the independent reproduction's suite fails on main and 10.5.2 (8 run, 4 failed) and 9.12.3 (6 run, 3 failed), each -ea and -da [exec]. The createOptimalSet body and the 26-entry usableBitSetSizes table are byte-identical at all 25 release tags and main, and upstream main still has getNearestSetSize(2 * setSize) (FuzzySet.java:96-104) with no open PR touching FuzzySet.java or DefaultBloomFilterFactory.java [read]",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-4069",
    "https://github.com/apache/lucene/issues/11900",
    "https://github.com/apache/lucene/issues/14614",
    "https://github.com/apache/lucene/issues/14615",
    "https://github.com/apache/lucene/issues/14616",
    "https://github.com/apache/lucene/issues/15513"
   ],
   "doc": "",
   "repro": "repro/LFV-362/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-169",
   "priority": "low",
   "priority_rank": 951,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / IndexedDISI jump table (presence sets of sparse doc values, norms and vectors)",
   "title": "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)",
   "summary": "You build a segment of more than 2,147,352,576 documents with the default codec, with a doc-values, norms or vector field that some documents lack and that a document near the end of the doc-id range has. You expect the field's index-time jump table (added in 8.0 'for O(1) advance') to be used, so that advance() to a far document jumps straight to its 65,536-doc block. Instead IndexedDISI.writeBitSet writes 32,768 or 32,769 table entries but returns their count as a short (-32,768 or -32,767), the codec stores that value, and every reader treats a negative count as 'no jump table', so advance() and advanceExact() walk the block headers one by one; the documents and values returned stay correct.",
   "impact_class": "minor",
   "introduced_commit": "c13645bd4c6 (c13645bd4c65f052e7f35df8e33d3dbfe6d7cd58, LUCENE-8585 'Create jump-tables for DocValues at index-time', now apache/lucene#9631; developed in apache/lucene-solr#525 by tokee, reviewed by jpountz; committed directly to master, branch_8x cherry-pick 5bb6a5b42c4) [read] [exec]",
   "introduced_date": "2019-01-18 (master commit); branch_8x cherry-pick committed 2019-01-21",
   "first_affected_version": "8.0.0 [exec] (tagged 2019-03-13; 7.x has no jump table, so the repro does not compile on 7.7.0, 7.7.1 or 7.7.3 [exec]); the sparse-vector path from 9.2.0 (LUCENE-10502) [read]",
   "affected_versions": "every release from 8.0.0 through 10.6.0 (10.6.0 [exec]: the minimal test fails on the 10.6.0 release jars (SHA-1 checked against Maven Central) with -ea and -da), and main ea57360912ed [exec] [read]; not a regression; not fixed upstream (no open PR changes the count; #12557 keeps it a short) [read]; executed on aarch64 with JDK 25 only",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-169.html",
   "repro": "repro/LFV-169/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-168",
   "priority": "low",
   "priority_rank": 952,
   "novelty": "known",
   "withheld": false,
   "area": "join / JoinUtil global-ordinals join explain (GlobalOrdinalsQuery, GlobalOrdinalsWithScoreQuery)",
   "title": "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",
   "summary": "You build a global-ordinals join with JoinUtil.createJoinQuery(joinField, fromQuery, toQuery, searcher, scoreMode, ordinalMap), where 'from' and 'to' documents share one join field and fromQuery/toQuery tell them apart as the javadoc requires, and ask IndexSearcher.explain about a document the join does not return, for example a 'from' document whose join value was collected. You expect a non-match explanation, as upstream TestJoinUtil#testOrdinalsJoinExplainNoMatches asserts for other non-hits of this query and as CheckHits.checkNoMatchExplanations requires. Instead explain() checks only that the document's join value was collected and never consults toQuery, which the scorers do iterate, so it answers 'A match, join value X' in every ScoreMode; search results are unaffected, but BooleanQuery explanations built on it go wrong and BooleanWeight.explain can throw NullPointerException.",
   "impact_class": "minor",
   "introduced_commit": "c4d9d6b3f10d (LUCENE-6352 'Add global ordinal based query time join', GitHub mirror #7413, by martijnvg; pre-GitHub SVN r1670990, no PR; branch_5x twin 8497fc6df35, r1670991, released in 5.2.0) [read]; partly fixed by b9cc15309ce (LUCENE-7065, #8121, by martijnvg, 2016-03-04; branch_5_5 dac7ea81704, branch_6_0 ac7f15e3729; first releases 5.5.2 and 6.0.0), which added only the collected-ordinal check (foundOrds.get / collector.match) and left the toQuery condition out [read]; no later commit adds a toQuery check [read]",
   "introduced_date": "2015-04-02 (LUCENE-6352); partial fix 2016-03-04 (LUCENE-7065)",
   "first_affected_version": "5.2.0 [exec] (the first release with the global-ordinals join; 5.1.0 does not have the API, so the probe does not compile [exec]); 5.2.0..5.5.1 carry the broader pre-LUCENE-7065 explain defect, which includes this case; 5.5.2 and 6.0.0 onward carry exactly this residual [exec]",
   "affected_versions": "every release from 5.2.0 to 10.5.2 (105 releases) and main ea57360912ed. [exec] the follow-up's public-API main() probe fails on 5.2.0 (-ea and -da), 5.5.1, 5.5.2, 6.0.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da), does not compile on 5.1.0, and passes on main with the fix shadowed; the finder's JUnit fails on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da on main; it needs the 9.1+ test framework); 8.8.2..8.11.3 are not tagged there and were not executed individually (they lie between 8.8.1, source-checked, and 8.11.4, executed). History runs used only the single-segment (no OrdinalMap) path. Not fixed upstream: unchanged on main, branch_10x and branch_9x; no open PR changes the explain logic.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/8121",
    "https://issues.apache.org/jira/browse/LUCENE-7065",
    "https://github.com/apache/lucene/issues/16805",
    "https://github.com/apache/lucene/issues/13747",
    "https://github.com/apache/lucene/issues/16847"
   ],
   "doc": "",
   "repro": "repro/LFV-168/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-174",
   "priority": "low",
   "priority_rank": 953,
   "novelty": "new",
   "withheld": false,
   "area": "expressions / ExpressionRescorer explain (Expression.getRescorer, ExpressionValueSource.explain over SortRescorer)",
   "title": "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",
   "summary": "You rescore first-pass hits with an expression that reads _score, for example '_score * 100 + popularity' through Expression.getRescorer, and ask the rescorer to explain a hit. You expect what the ExpressionRescorer javadoc promises, an explanation 'showing the value of each variable': _score equal to the first-pass score the rescore used, and the expression value computed from it (107.0 for a first-pass score of 1.0 and popularity 7). Instead, since 7.0.0, ExpressionRescorer hands SortRescorer's explanation, whose value is always 0, to the expression as the score explanation, so the explanation reads '7.0 = _score * 100 + popularity' with a _score detail of 0.0, while the rescore itself (order, sort values, scores) is correct.",
   "impact_class": "minor",
   "introduced_commit": "fb24d451cc98120d5a70bd0e63a5b296ce69123c (LUCENE-7741 'Add explain() to DoubleValuesSource', now apache/lucene#8792, by romseygeek; committed to master from a JIRA patch, no PR found) [read] [exec]",
   "introduced_date": "2017-05-10",
   "first_affected_version": "7.0.0 [exec] (CHANGES.txt lists LUCENE-7741 under 7.0.0 API Changes); 6.5.1 (the last release before the commit), 6.6.0 and 6.6.6 are not affected [exec]; the 6.x line never received the change",
   "affected_versions": "every release from 7.0.0 through 10.6.0 (10.6.0 by reading), and main ea57360912ed. [exec] the follow-up's version-portable history probe (public API, core and expressions jars) finds 6 of 6 rescored hits wrong on 7.0.0, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main (-ea and -da), and passes 6 of 6 on 6.5.1, 6.6.0, 6.6.6, on 7.0.0 with the pre-commit ExpressionRescorer.java shadowed, and on main with the candidate fix shadowed; the independent reproduction's JUnit fails on main (-ea, -da), 10.5.2 and 9.12.3; the intended-behaviour check's main() fails on 7.0.0, 10.5.2 and main (-ea, -da) and passes on 6.6.6; the finder's main() fails on 8.11.4, 9.12.3 and 10.5.2. [read] all 65 release tags in the full-history clone that contain the commit (7.0.0-8.8.1, 9.0.0-10.5.2); 8.8.2-8.11.3 have no tags there (8.11.4 executed); 4.8.0-6.3.x use the older SortField/ValueSource bindings and bind the first-pass score (not run; the probe compiles only from 6.4). Not fixed upstream: the explain body is unchanged on main, branch_10x and branch_10_6 (file last changed by 945b1cb872, 2021-03-23) [read]. All runs on aarch64 with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-174.html",
   "repro": "repro/LFV-174/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-922",
   "priority": "low",
   "priority_rank": 954,
   "novelty": "new",
   "withheld": false,
   "area": "core / search similarities (DFR after effect B explanation: AfterEffectB.explain, reached through DFRSimilarity.explain)",
   "title": "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",
   "summary": "You search with DFRSimilarity(basic model, new AfterEffectB(), normalization) and call IndexSearcher.explain on a hit. The AfterEffectB node says 'computed as (F + 1) / (n * (tfn + 1)) from:' and labels its children 'F, total number of occurrences of term across all documents + 1' and 'n, number of documents containing term + 1', so for a term with totalTermFreq 6 and docFreq 3 you expect F = 7 and n = 4. Instead the children show 6 and 3 (the raw statistics) and tfn is listed twice, so the formula on the listed children gives 0.71897 while the node correctly shows 0.61626 (I(n)B2); the score is right and only the explanation's operands are wrong.",
   "impact_class": "minor",
   "introduced_commit": "6771886cf3303a9a2c3cb86c8d0329e55ee0feaa ('LUCENE-8011: Improve similarity explanations', author mayya-sharipova, committed by jpountz; apache/lucene-solr#280, landed as a squashed commit with 'Closes #280'; the JIRA issue is now apache/lucene#9059): it rewrote the node as 'computed as (F + 1) / (n * (tfn + 1)) from:', relabelled the children with '+ 1' and added a second tfn child, but kept passing the raw stats.getTotalTermFreq() and stats.getDocFreq(); scoring has used F = totalTermFreq + 1 and n = docFreq + 1 since 2011 (LUCENE-3430/LUCENE-3722), and LUCENE-8015 (63b63c57348, 2017-12-06) changed only the value computation and kept the accurate labels. [read] [exec]",
   "introduced_date": "2017-11-30 (author date 2017-11-30T20:03:39-05:00, i.e. 2017-12-01T01:03:39Z; committed 2017-12-13; PR opened 2017-12-01, closed 2017-12-13)",
   "first_affected_version": "8.0.0 [exec] (CHANGES.txt 8.0.0 'LUCENE-8011: Improved similarity explanations'; never backported to 7.x); the last unaffected release is 7.7.3 [exec] (also 7.2.0 [exec], and 5.0.0, 5.5.5 and 6.6.6 by the finder's release probe [exec]), where the node reads 'AfterEffectB, computed from:' with accurate raw labels 'totalTermFreq' and 'docFreq'; AfterEffectB itself exists since 4.0",
   "affected_versions": "Every release from 8.0.0 to 10.5.2 (the last release before 10.6.0), 10.6.0 (the branch_10_6 head 4ae946e5a9b, the RC1 revision) and main a9779ef3c193; not fixed upstream. [exec] follow-up history runs (seed DEADBEEF): 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2, branch_10_6 and main (-ea and -da) fail; 7.2.0 and 7.7.3 pass (old accurate format); the finder's JUnit fails on main (-ea and -da); the independent reproduction's JUnit on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's main() on main (-ea and -da), 10.5.2 and 8.11.4; a separate test observes the same values on main and 10.5.2 and the old accurate tree on 7.7.3; the finder's main() release probe: 8.0.0 to 10.5.2 affected, 5.0.0 to 7.7.3 not. [read] every release tag from 8.0.0 on contains 6771886cf33 (git tag --contains); 8.9.0-8.11.4 from the lucene-solr branch_8_11 commit list; upstream main c5ab3e57b9ba (2026-10-28) still passes the raw statistics (read-only contents API, re-checked 2026-10-28), and branch_10x and branch_10_6 have no later commit on the file. All runs with JDK 25.0.3 on aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-922.html",
   "repro": "repro/LFV-922/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-921",
   "priority": "low",
   "priority_rank": 955,
   "novelty": "new",
   "withheld": false,
   "area": "core / search similarities (Normalization.NoNormalization explanation; IBSimilarity and DFRSimilarity explain trees)",
   "title": "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",
   "summary": "You score a field with IBSimilarity(distribution, lambda, new Normalization.NoNormalization()) and call IndexSearcher.explain on a document where the term occurs 3 times. You expect the explanation to add up: the IB node says it is 'computed as boost * distribution.score(stats, normalization.tfn(stats, freq, docLen), lambda.lambda(stats))', NoNormalization.tfn returns tf, and Normalization.explain is documented to return 'an explanation for the normalized term frequency', so the normalization child should show 3 and the Distribution child should equal the node at boost 1. Instead NoNormalization.explain returns the value 1, IBSimilarity feeds that 1 into distribution.explain as tfn, and the Distribution child shows 0.9162907 under a node of 1.7047480 (all four IB distribution/lambda pairs), while the score itself is right.",
   "impact_class": "minor",
   "introduced_commit": "cfaf91c73981bcce5f240aba5ad1cc29d7b517e4 (LUCENE-2959 'add state of the art ranking to Lucene', apache/lucene#4033; svn trunk r1169470; git author and committer Robert Muir, CHANGES credits 'David Mark Nemeskey via Robert Muir'; no pull request, pre-GitHub). It merged the flexscoring branch, where the same code first appears in 8f73f80d1d7 (LUCENE-3220, apache/lucene#4293, 2011-07-15), and wrote both halves together with the javadoc contract they break: NoNormalization.explain returning new Explanation(1, \"no normalization\") while tfn returns tf, and IBSimilarity.explain passing normExpl.getValue() to distribution.explain [read]; executed: affected from 4.0.0-ALPHA on, not a regression",
   "introduced_date": "2011-09-11 (cfaf91c7398, trunk merge, svn r1169470); 2011-07-15 (8f73f80d1d7, flexscoring branch)",
   "first_affected_version": "4.0.0-ALPHA [exec] (tagged 2012-06-29, the first release containing cfaf91c7398; run on a plain classpath with the checksum-verified Maven Central jar); first final release 4.0.0 [exec]; no unaffected release has the API: 3.6.2 has no IB/DFR classes [exec]",
   "affected_versions": "Every release from 4.0.0-ALPHA to 10.5.2 (123 release tags contain cfaf91c7398 and the defect lines are semantically unchanged since), 10.6.0 (the branch_10_6 head 4ae946e5a9b9, the RC1 revision) and main a9779ef3c193 [exec]. In 4.0.0-ALPHA to 7.7.3, DFRSimilarity with NoNormalization also computed its BasicModel and AfterEffect children at tfn = 1 [exec]; since 8.0.0 (LUCENE-8015, 63b63c57348) only DFR's 'no normalization' child shows 1. Upstream main c5ab3e57b9b (author date 2026-10-28), branch_10_6 and branch_10x are unchanged: the last commits on Normalization.java are 2d6ad2fee6d (2020-12-23, reformat) and on IBSimilarity.java and DFRSimilarity.java dab731175c8 on main (2024-10-04, constructors) [read]; not fixed anywhere. All runs on aarch64 Linux with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-921.html",
   "repro": "repro/LFV-921/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-370",
   "priority": "low",
   "priority_rank": 956,
   "novelty": "new",
   "withheld": false,
   "area": "spatial-extras / BBoxStrategy overlap-ratio relevance (BBoxOverlapRatioValueSource.score: explanation tree)",
   "title": "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",
   "summary": "You score documents with BBoxStrategy.makeOverlapRatioValueSource and call explain, and you expect the tree to show the terms of the documented formula, queryFactor = queryRatio * queryTargetProportion and targetFactor = targetRatio * (1 - queryTargetProportion). Instead the 'ratio' child of the 'queryFactor' node, printed next to 'area of <query box>', is targetRatio, the same number as under 'targetFactor': for the query box x[0,20] y[0,10] and the document box x[10,40] y[5,15] at proportion 0.3 it shows 0.16666667 (50/300) where queryRatio is 0.25 (50/200). The score (0.19166666) and the queryFactor value (0.075) are right; one token on line 255 is wrong, a slip from the 2015 LUCENE-6446 Explanation API rewrite, and 5.1.0 still showed queryRatio.",
   "impact_class": "minor",
   "introduced_commit": "3b90a63a027a3b62aeb7b3504dacc4447880de4f (branch_5x, svn r1675114, 2015-04-21 13:23 UTC, the copy that shipped first, in 5.2.0) and its trunk original c6821e1a1941e9ed6cbe35a3cb5be831bb6cfe1a (svn r1675109, 12:55 UTC, an ancestor of every 6.x-10.x release and main), 'LUCENE-6446: Simplified Explanation API', by jpountz; no pull request (SVN + JIRA era; LUCENE-6446 is apache/lucene#7505). This mechanical rewrite of every Explanation call site for the immutable API replaced e.addDetail(new Explanation((float)queryRatio, \"ratio\")) under 'queryFactor' with Explanation.match((float)targetRatio, \"ratio\"), the same line as in the targetFactor block; the issue and its 16 comments state API goals only and never mention spatial code. [read]. A regression: the class's first version, 7e0aff8dabc4 (LUCENE-5714/5779, by dsmiley, 2014-07-08; first shipped in 4.10.0 through the branch_4x backport), showed queryRatio",
   "introduced_date": "2015-04-21 (trunk c6821e1a194 and branch_5x 3b90a63a027, the same day)",
   "first_affected_version": "5.2.0 [exec] (tag 2015-06-06; CHANGES.txt lists LUCENE-6446 under 5.2.0; fails with -ea and -da); the last unaffected release is 5.1.0 [exec]; 4.10.0-4.10.4 and 5.0.0 are also correct [exec]; no release before 4.10.0 has the class",
   "affected_versions": "Every release from 5.2.0 to 10.6.0 and main ea57360912ed; not fixed upstream. [exec] a public-API main() probe (four API spellings of one case: queryRatio 0.25, targetRatio 1/6) on all 112 Maven Central releases before 10.6.0 that ship the class (lucene-spatial 4.10.0-5.5.5, lucene-spatial-extras 6.0.0-10.5.2), -ea: 105 fail, every release from 5.2.0 to 10.5.2, showing 0.16666667 under queryFactor; 7 pass (4.10.0-4.10.4, 5.0.0, 5.1.0); 5.1.0 (pass) and 5.2.0 (fail) also with -da; main fails with -ea and -da and passes with the one-token fix shadowed; the finder's JUnit fails on main (-ea and -da), 10.5.2 and 9.12.3, the independent reproduction's JUnit on main (-ea and -da), 10.5.2 and 9.12.3, and a separate JUnit on main (-ea and -da) and 9.12.3. [read] source scan of the 103 release tags in the history clone that contain the class: queryRatio in the 7 from 4.10.0 to 5.1.0, targetRatio in the 96 from 5.2.0 to 10.5.2 (8.8.2 to 8.11.4 have no tag there and were checked by execution only); upstream main e1c4184cb983, branch_10x, branch_10_6, branch_9_12 and branch_9_11 still show targetRatio (read-only, 2026-10-26); 10.6.0 (released 2026-10-29) is affected [exec]. All runs with JDK 25.0.3 on aarch64, not the JDKs the old releases targeted (a pure-arithmetic path)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-370.html",
   "repro": "repro/LFV-370/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-920",
   "priority": "low",
   "priority_rank": 957,
   "novelty": "new",
   "withheld": false,
   "area": "core / search similarities (Axiomatic F1/F3 term-frequency explanation, tfExplain)",
   "title": "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",
   "summary": "You search with AxiomaticF1EXP (or F1LOG, F3EXP, F3LOG) and call IndexSearcher.explain on a hit. The tf node says 'tf, term frequency computed as 1 + log(1 + log(freq)) from:' and its only child is 'freq, number of occurrences of term in the document', the raw count, so you expect its value to be that formula of that child. Instead tf() first adds 1 to freq (since LUCENE-8010, 2017), so for freq = 1 the node shows 1.5265890 where the stated formula gives 1.0, and for freq = 3 it shows 1.8697417 instead of 1.7412763; the score is right and only the formula text is stale.",
   "impact_class": "minor",
   "introduced_commit": "b2f248164c1a3ddf213a56778d55c9252a022f18 ('LUCENE-8010: Fix similarities so that they pass tests', by jpountz; JIRA patch era, no pull request; LUCENE-8010 is apache/lucene#9058): added 'freq += 1; // otherwise gives negative scores for freqs < 1' to tf() in all four classes and left the four tfExplain description strings unchanged. Those strings were written one month earlier by 6771886cf3303a9a2c3cb86c8d0329e55ee0feaa ('LUCENE-8011: Improve similarity explanations', by mayya-sharipova, committed by jpountz; apache/lucene-solr#280, apache/lucene#9059), when tf() was 'if (freq <= 0.0) return 0.0; return 1 + log(1 + log(freq))' and the text was correct; 6771886cf330 never shipped without b2f248164c1. [read]",
   "introduced_date": "2017-12-28 (author date of b2f248164c1; committed 2017-12-29); the stale string itself from 6771886cf330, author date 2017-11-30 (committed 2017-12-13)",
   "first_affected_version": "8.0.0 [exec] (both commits first appear in 8.0.0; no 7.x tag contains either); the last unaffected release is 7.7.3 [exec], where the tf node is a plain 'tf' with no formula (also 7.2.0 and 6.6.6 [exec]); the Axiomatic classes exist since 6.4.0",
   "affected_versions": "Every release from 8.0.0 to 10.5.2 (the last release before 10.6.0), 10.6.0 (the branch_10_6 head 4ae946e5a9b9, the RC1 revision) and main a9779ef3c193; not fixed upstream. [exec] the follow-up's version-portable probe AxiomaticTfExplainHistoryProbe fails on 8.0.0 (-ea and -da), 8.11.4, 9.0.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da), branch_10_6 and main (-ea and -da) and passes (no formula node) on 6.6.6, 7.2.0 and 7.7.3 (-ea and -da); the finder's JUnit fails on main, 10.5.2 and 9.12.3 (each -ea and -da); the independent reproduction's JUnit fails on main (-ea and -da), 10.5.2, 9.12.3, 8.11.4 and 8.0.0; the intended-behaviour check's on main (-ea and -da), 10.5.2 and 9.12.3. [read] all 51 release tags 8.0.0-10.5.2 in the history clone contain both 'freq += 1' and the stale string in all four classes and none of the 14 7.x tags contains either (8.8.2-8.11.x are not tagged there; 8.11.4 executed); upstream main c5ab3e57b9b (2026-10-28) still has both lines (read-only GitHub contents API, re-checked 2026-10-28). All runs with JDK 25.0.3 on aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-920.html",
   "repro": "repro/LFV-920/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-231",
   "priority": "low",
   "priority_rank": 958,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / Thai (ThaiRepeatFilter offset split; ThaiAnalyzer with ThaiCharFilter, or a custom chain with HTMLStripCharFilter)",
   "title": "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)",
   "summary": "You analyze 'บ่อยๆ' + U+200B + 'ครับ' (a word written with the repetition mark ๆ, then a zero-width space) with the stock ThaiAnalyzer and expect what happens without the zero-width space, and what the filter's CHANGES entry promises ('exact OffsetAttribute and highlighter compatibility'): the base token บ่อย covers the word [0,4) and the repeated token บ่อย covers the ๆ [4,5). Instead the base token gets [0,5), which includes the ๆ, and the repeated token gets [5,6), which is only the removed zero-width space: ThaiRepeatFilter assumes that the last characters of the token's offset span are its trailing ๆ, but the CharFilter's offset correction put the removed character at the end of that span. With HTMLStripCharFilter the repeated token points at the last character of the tag after the word instead, so a highlighter writes its markup inside the tag; terms and positions are correct and nothing fails.",
   "impact_class": "minor",
   "introduced_commit": "b7c2c202ba695d8fd8cfb7081ad183b89922a462 (main; apache/lucene#16720 'Add ThaiRepeatFilter to handle Thai Maiyamok reduplication', fixes #16719, author kamthorn, squash-merged 2026-09-27 with one approving comment by rmuir and no review threads; the per-character offset split, baseEnd = origEnd - maiyamokCount, came from the PR's second commit 6223794e4021 'Fix OffsetAttribute handling in ThaiRepeatFilter and add randomized offset tests', while the PR's first commit 9b9eabd23688 had no setOffset call) and its branch_10x backport ed0288d79909 (2026-09-28), which is also on branch_10_6. The default-ThaiAnalyzer trigger also needs ThaiCharFilter in ThaiAnalyzer.initReader, added 45 minutes earlier by e64ae25dcd89 (#16717, same author); the HTMLStripCharFilter trigger needs only ThaiRepeatFilter [read]. There was never a correct earlier behaviour in a merged commit",
   "introduced_date": "2026-09-27 (main); 2026-09-28 (branch_10x backport)",
   "first_affected_version": "10.6.0 (released 2026-10-29; branch_10_6 has the identical file); no earlier release contains ThaiRepeatFilter [exec]",
   "affected_versions": "main from b7c2c202ba69 (2026-09-27) to ea57360912ed [exec]; branch_10x from ed0288d79909 and branch_10_6 [read]; in no release before 10.6.0: 10.5.2 (the last before it, released 2026-10-04 from branch_10_5), 9.12.3 and every older release lack the class [exec]; not fixed upstream. JDK caveat: the default-analyzer trigger needs the JDK word BreakIterator to keep the ๆ attached to its word; every run used JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-231.html",
   "repro": "repro/LFV-231/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b): 4 of 5 fail with -ea and -da; 10.5.2 does not have ThaiRepeatFilter."
  },
  {
   "id": "LFV-603",
   "priority": "low",
   "priority_rank": 959,
   "novelty": "known",
   "withheld": false,
   "area": "analysis / nori KoreanTokenizer (Viterbi decompound backtrace; UserDictionary and bundled-dictionary compounds)",
   "title": "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 '토그')",
   "summary": "You analyze text containing 픽토그램 ('pictogram') with the default KoreanAnalyzer, or 세종시 with the user dictionary entry '세종시 세종', and expect each decompounded part's offsets to cover the characters its text came from, as they do when the parts cover the whole word (가락지나물 gives 가락지[0,3) and 나물[3,5)). Instead nori cuts each part's text from the start of the word but counts its offsets back from the end of the word, so 픽토그램 gives 픽토[1,3), covering '토그', and 그[3,4), covering '램', and '세종시 세종' gives 세종[1,3), covering '종시'; highlighters mark the wrong characters. Lucene accepts both inputs without a check: UserDictionary rejects only a segmentation longer than the word, and 7 compounds in the bundled dictionary have parts that do not add up to the word.",
   "impact_class": "minor",
   "introduced_commit": "e851b89cbeb1f55edc0f2c1276e2ae812eca2643 (LUCENE-8231 'Add a new analysis module (nori) similar to Kuromoji but to handle Korean', GitHub issue #9278, by jimczi; JIRA patch workflow, no pull request) and its branch_7x backport 8651fbaa8bc65fdfec397ad4e7ebe2b5acf78d7b, the commit contained in 7.4.0 [read: git history; all three ingredients arrived together in that commit: KoreanTokenizer.java:877-894 'int endOffset = backWordPos + length;' with parts at [endOffset - len, endOffset), the left cut of part text in BinaryDictionary.java:207-209 and UserDictionary.java:198, and validation that rejects only a longer segmentation (UserDictionary 'offset > token.length()', BinaryDictionaryWriter.java:166 'assert compoundOffset <= entry[0].length()')]. Not a regression; later commits left the offset computation unchanged: 6f291d402b9 (LUCENE-8524, 7.6.0, drops empty parts), bd22f199dec (LUCENE-10393), 13630d361e2 and c89f8a7ea1e (LUCENE-10493, backtrace moved verbatim to Viterbi.java), 942065cc3e7 (#13328), 76c9fd4e38a (LUCENE-10416, dictionary update that kept the 7 rows)",
   "introduced_date": "2018-04-13",
   "first_affected_version": "7.4.0 [exec] (nori's first release, tagged 2018-06-22); 7.3.1 and earlier have no nori module [exec]",
   "affected_versions": "Every nori release from 7.4.0 through 10.5.2, and main a9779ef3c193; never fixed. [exec] the follow-up's version-neutral public-API probe shows the bug on 7.4.0 (-ea and -da), 7.5.0, 7.6.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main; the finder's JUnit fails 2 of 2 on main (-ea and -da), 10.5.2, 9.12.3, 10.0.0 and 9.1.0, and the finder's main() probe fails on 7.4.0, 8.11.4 and 9.12.3; the independent reproduction's JUnit fails 2 of 4 on main (-ea and -da), 10.5.2 and 9.12.3; the sentence probe fails on main and 10.5.2 with identical output. The user-dictionary trigger is present in every version. For isolated words the bundled trigger hits 7 of 7 words through 9.12.3 and 6 of 7 from 10.0.0 (mecab-ko-dic 2.1.1: 일로역 alone becomes 일 + 로역), but inside a sentence ('일로역에 도착했다.') all 7 still hit on main and 10.5.2. In 7.4.0 and 7.5.0 그레이맨 also yields an extra empty token (removed in 7.6.0 by LUCENE-8524, offsets untouched). [read] the offset code is unchanged in the releases between the executed ones; Viterbi.java, KoreanTokenizer.java, UserDictionary.java, UserMorphData.java, TokenInfoMorphData.java, TokenInfoDictionaryEntryWriter.java and the dictionary buffer are identical on upstream main a95c754ee003 and branch_10x (2026-10-26); the 7 commits ea57360912ed..a9779ef3c193 do not touch lucene/analysis/nori. All runs on JDK 25, aarch64",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9570",
    "https://issues.apache.org/jira/browse/LUCENE-8524",
    "https://github.com/apache/lucene/issues/9976",
    "https://issues.apache.org/jira/browse/LUCENE-8933",
    "https://github.com/apache/lucene/issues/8236",
    "https://issues.apache.org/jira/browse/LUCENE-7181"
   ],
   "doc": "",
   "repro": "repro/LFV-603/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-925",
   "priority": "low",
   "priority_rank": 960,
   "novelty": "known",
   "withheld": false,
   "area": "monitor / HighlightsMatch on batches (DocumentBatch: MultiDocumentBatch keeps the caller's FieldType, SingletonDocumentBatch uses MemoryIndex with offsets)",
   "title": "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",
   "summary": "You register a query with a Monitor and match a document whose text is in a plain TextField with HighlightsMatch.MATCHER; each hit carries its positions and character offsets (the phrase \"cell biology\" in 'the cell biology count' is positions 1-2, offsets 4-16). Match the same document in a batch of two or more documents with Monitor.match(Document[]) and the hits keep the right positions, but both offsets are -1, because a single document goes into a MemoryIndex that always stores offsets while a batch is indexed with the documents' own field types, and TextField indexes no offsets. The module's own test testHighlightBatches expects the real offsets in a batch (Hit(1, 4, 2, 16)) but cannot notice, because the hit set's contains() uses Hit.compareTo, which ignores offsets (the sibling bug LFV-915).",
   "impact_class": "minor",
   "introduced_commit": "633ae90d7d930c34846cb7dd9be3126d3cffaa34 on branch_8x (released in 8.6.0) and 5d5b7e14d41e00671fc938ad0db7714d56bd455e on master (first released in 9.0.0), both LUCENE-9314 = apache/lucene#10354 ('Lucene monitor module uses ByteBuffersDirectory rather than MemoryIndex when matching a single document'; authored by romseygeek, CHANGES also credits the reporter; JIRA patch committed directly, no PR). It made DocumentBatch.of return SingletonDocumentBatch (new MemoryIndex(true, true)) for a one-element array, so single documents gained offsets while batches kept the caller's FieldType [exec]. Older root, not a regression: since LUCENE-8766 (251dbe7cea81 on master / b8773d13ad8e on branch_8x, 2019-06-13, 8.2.0) the batch path has returned -1 for TextField offsets and testHighlightBatches has asserted Hit(1, 4, 2, 16) for a batch, an expectation masked by Hit.compareTo (LFV-915) [exec]",
   "introduced_date": "2020-04-27 (author date of 633ae90d7d9 and 5d5b7e14d41); older root 2019-06-13 (251dbe7cea8, the module import)",
   "first_affected_version": "8.6.0 [exec]. 8.2.0-8.5.2 are not affected: there a single document also went through MultiDocumentBatch, so both paths returned -1 for TextField [exec]; before 8.2.0 there is no monitor module",
   "affected_versions": "Every lucene-monitor release from 8.6.0 to 10.5.2, 10.6.0 (the branch_10_6 head 4ae946e5a9b, the RC1 revision) and main a9779ef3c193. [exec] The version-neutral history probe (public API, no randomness, hits compared by toString) diverges on 8.6.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da): phrase alone [1(4)->2(16)], in a batch of 2 or 3 [1(-1)->2(-1)]; term alone [2(9)->2(16)], batch [2(-1)->2(-1)]; the offsets-FieldType control gives [1(4)->2(16)] in both paths in every run. The finder's JUnit fails 2 of 2 on main (-ea, -da), branch_10_6, 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 2 of 3 on main (-ea, -da), 10.5.2, 9.12.3, 8.11.4 and 8.6.0 (control passes); the tie-breaker's test fails its 2 claim tests of 8 on main (-ea, -da) and 10.5.2. [read] 8.6.0-8.8.1 share the DocumentBatch.java blob 0ca58c9 and 9.0.0-10.5.2 the blob 2bf0dc8 (0ca58c9 reformatted); 8.8.2-8.11.3 were not run (8.11.4 was). Not affected: 8.2.0-8.5.2 (both paths -1). Not fixed upstream: no commit under lucene/monitor on main since df6f71a3729 (author date 2026-09-25, formatting), main head c5ab3e57b9b (2026-10-28), and DocumentBatch.java's last semantic change on main, branch_10x and branch_10_6 is 5d5b7e14d41 [read]. Executed on Linux aarch64 with JDK 25 only.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/10354",
    "https://issues.apache.org/jira/browse/LUCENE-9314",
    "https://github.com/apache/lucene/issues/13993",
    "https://github.com/apache/lucene/issues/12406",
    "https://github.com/apache/lucene/issues/11265",
    "https://github.com/apache/lucene/issues/16913"
   ],
   "doc": "",
   "repro": "repro/LFV-925/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-338",
   "priority": "low",
   "priority_rank": 961,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / char filters (MappingCharFilter, BaseCharFilter offset correction)",
   "title": "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",
   "summary": "You read a MappingCharFilter to the end, call reset() to rewind it (MappingCharFilter overrides reset() for this, and upstream TestMappingCharFilter.testReaderReset re-reads after it), read it again and expect correctOffset() to map the second pass's output back to the input exactly as on the first pass. Instead reset() rewinds the input and the filter's read state but not the offset-correction map it inherits from BaseCharFilter, so the second pass appends new corrections computed from the first pass's last cumulative diff: for the map a->xy over \"a\", correctOffset(2) returns 0 instead of 1, and a WhitespaceTokenizer over the re-read filter for \"a b\" gives xy[0,0] b[1,2] instead of xy[0,1] b[2,3]. For deleting or shrinking maps, with -ea the second read() trips BaseCharFilter's 'Offset ... is less than the last recorded offset' assertion, and with -da it returns offsets past the end of the input (b->'' over \"ba\": correctOffset(1) = 3 for a 2-character input).",
   "impact_class": "minor",
   "introduced_commit": "6a3752feb8f13541603e85326db997147047b2a6 (svn r791415), LUCENE-1734 'CharReader should delegate reset/mark/markSupported' (apache/lucene#2808; a JIRA patch from the svn era, no GitHub PR), committed by uschindler for an issue reported by kojisekig: it removed MappingCharFilter's reset() that threw 'mark/reset not supported' and made reset() delegate to the input, and no commit since has cleared BaseCharFilter's correction list [exec]. The current reset() override (rewinds input, buffer, replacement and inputOff, not the map) comes from LUCENE-3830 (3e9b5a9893c, apache/lucene#4903, 2012-05-06, first release 4.0.0), which made the defect visible on a plain read to EOF for most inputs [read]",
   "introduced_date": "2009-07-06 (6a3752feb8f, commit date); the current reset() override dates from 2012-05-06 (3e9b5a9893c, LUCENE-3830)",
   "first_affected_version": "2.9.0 [exec] (the first release with MappingCharFilter, and it already has the delegating reset(); there the bug shows only for reads that stop before EOF); the canonical read-to-EOF repro (a->xy over \"a\") fails from 4.0.0 on [exec]",
   "affected_versions": "Every release from 2.9.0 to 10.6.0, and main ea57360912ed; 10.6.0 [exec]: the minimal test fails on the 10.6.0 release jars (SHA-1 checked against Maven Central) with -ea and -da. [exec] the follow-up's version-portable main() probe (8 maps x 120 inputs x 3 read styles, comparing every correctOffset(i) after reset() with the first pass) fails with -ea and -da on 2.9.0, 2.9.4, 3.0.3, 3.5.0, 3.6.0, 3.6.1, 3.6.2, 4.0.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main; in 2.9.0 to 3.6.0 a plain read to EOF was mostly right by luck (0 to 9 of 960 cases fail, because a second stale counter pushed the new corrections past the output end) and only exact-length reads that never see EOF showed it (134 to 135 of 960); 3.6.1 and 3.6.2 fail 133 of 960 on read to EOF; from 4.0.0 on, read to EOF fails broadly (569 of 960 with -ea; 538 with -da up to 5.5.5 and 396 from 6.6.6 on). The finder's JUnit fails on 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) and does not compile on 9.0.0 (test-framework package missing; the probe covers it); the independent reproduction's JUnit fails 4 of 6 on main, 10.5.2 and 9.12.3 (-ea and -da); the independent reproduction's main() probe fails on 8.11.4 (-da). Not applicable: 2.4.1 and older (no MappingCharFilter: compile error) [exec]. Not fixed on upstream main (e1c4184cb983, 2026-10-26), and no open PR touches MappingCharFilter.java or BaseCharFilter.java [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-338.html",
   "repro": "repro/LFV-338/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-609",
   "priority": "low",
   "priority_rank": 962,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / matchhighlight: PassageFormatter multi-marker formatting (crossing markers with per-marker end strings; also end to end through MatchHighlighter, FieldValueHighlighters.highlighted and MatchHighlighter.QueryOffsetRange)",
   "title": "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>')",
   "summary": "You format the passage 'one two three' with two crossing markers, [0,7) written as <a>...</a> and [4,13) as <b>...</b>, using PassageFormatter's Function constructor, or you highlight the crossing phrase queries 'one two' and 'two three' with MatchHighlighter.highlight(topDocs, q1, q2) and one tag per query. You expect well-nested output, '<a>one <b>two</b></a><b> three</b>', because when a marker ends the formatter closes and re-opens the markers opened after it precisely to resolve the overlap into nested markup (Passage javadoc: markers 'can be overlapping or nested'). Instead it closes those markers in opening order rather than innermost first and returns '<a>one <b>two</a></b><b> three</b>' (end to end '<q1>one <q2>two</q1></q2><q2> three</q2>'), which an XML parser rejects.",
   "impact_class": "minor",
   "introduced_commit": "150a8dacb59712c731e66db1a56068326a0439f4 'LUCENE-9463: Query match region retrieval component, passage scoring and formatting (#1750)' (apache/lucene-solr#1750, author dweiss, merged into master only; LUCENE-9463 migrated as apache/lucene#10503), which created PassageFormatter together with its public Function-based constructor and the ascending close loop; the same loop is already in the LUCENE-9439 proof-of-concept patch (2020-07-31) [read]. The end-to-end MatchHighlighter path came in e2f3f626ee4 (LUCENE-9464, lucene-solr#1820, 2020-09-10), also first released in 9.0.0.",
   "introduced_date": "2020-08-14 (merged into master)",
   "first_affected_version": "9.0.0 [exec], the first release with the matchhighlight package; the work never reached 8.x (8.11.4 has no matchhighlight classes: compile error, API absent [exec])",
   "affected_versions": "every release from 9.0.0 through 10.6.0 (34 releases) and main a9779ef3c193; 10.6.0 [exec]: the minimal test fails on the 10.6.0 release jars (SHA-1 checked against Maven Central) with -ea and -da. [exec] the finder's JUnit fails 2 of 2 on 9.0.0 (-ea and -da, old-test-framework copy), 9.1.0, 9.12.3, 10.0.0 and 10.5.2 (-ea) and on main (-ea and -da); the independent reproduction's JUnit fails 3 of 4 (its control passes) on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's usage-pattern probe fails its per-marker-end-string case on main (-ea and -da) and 10.5.2. [read] the END block is byte-identical in all 33 9.x and 10.x release tags up to 10.5.2 and in main. Not fixed upstream: the loop is unchanged on upstream main a95c754ee003, branch_10x and branch_10_6, and no open PR touches PassageFormatter.java (407 open PRs scanned by changed file, 2026-10-26).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-609.html",
   "repro": "repro/LFV-609/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-774",
   "priority": "low",
   "priority_rank": 963,
   "novelty": "new",
   "withheld": false,
   "area": "highlighter / matchhighlight: PassageSelector passage windows and long-match truncation, BreakIteratorShrinkingAdjuster (through FieldValueHighlighters.maxLeadingCharacters and highlighted)",
   "title": "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",
   "summary": "You highlight a stored value with matchhighlight's FieldValueHighlighters, for example maxLeadingCharacters(5, '...', fields) on a value that starts with the word BOLD written in mathematical bold capitals (U+1D401 U+1D40E U+1D40B U+1D403, two UTF-16 units each), or highlighted(5, ...) with a term query that matches that word. You expect a snippet of whole characters within the 5-unit budget, for example the first two letters and '...', just as the ASCII value 'boldtext' is cut inside the word but between characters ('boldt...'). Instead the snippet ends with the first half of the third letter ('\\uD835\\uDC01\\uD835\\uDC0E\\uD835...' and '>\\uD835\\uDC01\\uD835\\uDC0E\\uD835<...'), because PassageSelector cuts windows and long matches at a raw UTF-16 offset and BreakIteratorShrinkingAdjuster keeps that raw edge when no word boundary fits in the window.",
   "impact_class": "minor",
   "introduced_commit": "150a8dacb59712c731e66db1a56068326a0439f4 (LUCENE-9463, apache/lucene-solr#1750, issue apache/lucene#10503, merged into master only): it added PassageSelector, whose default passage ends at o.from + min(window, length) in UTF-16 units, and BreakIteratorShrinkingAdjuster, which puts the raw edge back when preceding() reaches 0; neither checks for a surrogate pair. The second path, truncating a match longer than the window at from + maxPassageWindow, came with 1bb4554832027e139b0890dc0784107697e05fe6 (LUCENE-10135, apache/lucene#334, 2021-09-30); before it such a match was dropped and the default passage split the pair instead, so #334 moved the case to a second path rather than creating it [read]",
   "introduced_date": "2020-08-14 (#1750 merged); second path 2021-09-30 (#334 merged)",
   "first_affected_version": "9.0.0 [exec], the first release with the matchhighlight package (CHANGES.txt lists LUCENE-9463 and LUCENE-10135 under 9.0.0); 8.x has no matchhighlight API (8.7.0 and 8.11.4: compile error, API absent [exec])",
   "affected_versions": "every release from 9.0.0 through 10.6.0 and main a9779ef3c193 and 645d4fe14a20, never fixed. [exec] the finder's JUnit fails 2 of 2 with identical output on all 33 releases from 9.0.0 to 10.5.2 (9.0.0 also with -da) and on main (-ea and -da); the independent reproduction's JUnit fails 3 of 4 on main (-ea and -da), 10.5.2 and 9.12.3; the one-method minimal repro fails on main 645d4fe14a20 through gradle and on the 10.6.0 release jars (SHA-1 checked against Maven Central), -ea and -da (2026-11-01). [read] upstream main (f7bcc0abd816, 2026-10-27), branch_10x and branch_10_5 have not changed the package's window code since; from 9.0.0 to main PassageSelector changed only in priority-queue handling, a rename and a passage-count cap, and BreakIteratorShrinkingAdjuster is byte-identical. Not affected: 8.x and older (no matchhighlight package). Releases were run on JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-774.html",
   "repro": "repro/LFV-774/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-500",
   "priority": "low",
   "priority_rank": 964,
   "novelty": "new",
   "withheld": false,
   "area": "core / util AttributeSource (removeAllAttributes and the cached State chain, getCurrentState / currentState[0])",
   "title": "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",
   "summary": "You call removeAllAttributes() on an AttributeSource (for example a token stream you reuse with a different set of attributes) after it has been used, for example by clearAttributes(), which every Tokenizer calls for each token. You expect it to behave like a new, empty source until you add attributes again, as hasAttributes() (false) and equals() (equal to a new AttributeSource) already say. Instead the method clears its two maps but not the cached chain of attribute instances that captureState(), copyTo(), hashCode(), the impls iterator, reflection and clearAttributes()/endAttributes() walk, so until the next addAttribute() they still see the removed attributes: restoreState(captureState()) on the same source throws IllegalArgumentException, hashCode() differs from that of an equal empty source, and reflectAsString() still prints 'term=foo,...'.",
   "impact_class": "minor",
   "introduced_commit": "eb47a8b965f0da9109fc72c7fe545dd6e5fff523 (SOLR-4619 'Improve PreAnalyzedField query analysis', svn trunk r1725869; branch_5x backport 6fa0606cc8f3, r1725871, identical AttributeSource diff; svn era, no PR): it added removeAllAttributes() as 'attributes.clear(); attributeImpls.clear();' without resetting currentState[0] [read] [exec]. Not a regression: present since the method was added. The cache it skips predates it (LUCENE-1693, 31a5f0edcc4, 2009), as does the invalidation in addAttributeImpl() (LUCENE-3042, 49ab81b316c, 2011)",
   "introduced_date": "2016-01-21",
   "first_affected_version": "5.5.0 [exec] (6.0.0 on the trunk line [exec]; 5.4.1 has no removeAllAttributes() [exec])",
   "affected_versions": "5.5.0-5.5.5, 6.0.0-6.6.6, 7.0.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.6.0 and main ea57360912ed and 645d4fe14a20. [exec] the minimal repro fails 1 of 1 on main 645d4fe14a20 and on the 10.6.0 release jars (SHA-1 checked against Maven Central), -ea and -da (2026-11-01); the follow-up's main() probe (public API, core jar only) reports the same 6 violations on 5.5.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da), and its control (chain never built before removal) passes on 5.5.0, 9.12.3, 10.5.2 and main; the finder's JUnit fails 4 of 4 on main (-ea, -da), 10.5.2 and (follow-up run) 9.12.3; the independent reproduction's JUnit fails 6 of 8 on main and 10.5.2 (-ea and -da) and 9.12.3; the finder's main() probe fails on 9.12.3, 8.11.4, 7.7.3, 6.6.6 and 5.5.5; the independent reproduction's main() probe on 8.11.4 and 5.5.0. [read] 8.8.2-8.11.3 have no tags in the local history (released from the lucene-solr branch_8x line); they are affected by inference (method unchanged, 8.11.4 executed). Not fixed upstream: upstream main a9779ef3c193 (2026-10-26), branch_10x, branch_10_6 and branch_10_5 have the same method body",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-500.html",
   "repro": "repro/LFV-500/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-026",
   "priority": "low",
   "priority_rank": 965,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / flexible",
   "title": "Flexible StandardQueryParser throws ClassCastException on the input *>a",
   "summary": "You parse the query string *>a with the flexible StandardQueryParser. You expect a query or a QueryNodeException for bad syntax. Instead parse() throws an unchecked ClassCastException.",
   "impact_class": "wrong error",
   "introduced_commit": "565a6d22b5f0f6be56bc1542796ac7c831f838e4 (LUCENE-1792 'Fix new query parser to set rewrite method for multi-term queries', svn r805633, issue #2867; a JIRA-era patch, no PR): it widened MatchAllDocsQueryNodeProcessor's test from instanceof WildcardQueryNode to instanceof FieldQueryNode, so a range bound * on the field * is rewritten to a match-all node [exec]; cffd01664bc9 (2011-08-01, LUCENE-3343 and LUCENE-3338, first released in 4.0.0-ALPHA) added the < and > shorthand, which made *>a a trigger",
   "introduced_date": "2009-08-19",
   "first_affected_version": "2.9.0 [exec], the first release with the flexible parser; 2.4.1 has no flexible parser [exec]",
   "affected_versions": "every release from 2.9.0 to 10.6.0 and main 645d4fe14a20, never fixed [exec]; upstream main 2f424fd428da has the same code [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-026.html",
   "repro": "repro/LFV-026/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-355",
   "priority": "low",
   "priority_rank": 966,
   "novelty": "known",
   "withheld": false,
   "area": "queryparser / flexible (AbstractRangeQueryNode.toQueryString, PointQueryNode.getTermEscaped, the StandardSyntaxParser range lexer, the open-bound forms of OpenRangeQueryNodeProcessor and PointRangeQueryNodeProcessor, BooleanQueryNodeBuilder)",
   "title": "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",
   "summary": "You parse a range such as f:[\"a b\" TO c] or f:[a TO *] with the flexible StandardQueryParser, call toQueryString on the range node and parse the result again, as the 11.0 CHANGES entry for #7865 says you can. Instead a bound with a space, ']' or '}' prints backslash-escaped (f:[a\\ b TO c]), which the range lexer rejects even for the syntax parser's own node; a processed open term bound prints as nothing (f:[a TO ]); and a processed open point bound (i:[1 TO *] with a PointsConfig) makes toQueryString and toString throw IllegalArgumentException 'Cannot format given Object as a Number'. Because BooleanQueryNodeBuilder builds its too-many-clauses message with toQueryString, a query over the clause limit that contains such an open point range makes StandardQueryParser.parse throw that IllegalArgumentException instead of the documented QueryNodeException, in every release since 4.0.",
   "impact_class": "wrong error",
   "introduced_commit": "Round-trip failures: 17ca89d52fa96138518182b32d5de48940a2d977 (apache/lucene#14697 'Fix AbstractRangeQueryNode#toQueryString', by GitHub phb-ig, merged by stefanvodita, fixing #7865 / LUCENE-6807), an incomplete fix that created the parse-back promise, not a regression (before it no range round-tripped at all) [read]. Older ingredients [read]: the escape-blind range lexer token RANGE_GOOP (LUCENE-1567, 343992fcbb4, 2009; merged into one token by cffd01664bc9), the empty-text open term bound and the null open point value (cffd01664bc9; carried into PointRangeQueryNodeProcessor by 89cc676f2bf, LUCENE-7089/7075, 6.0.0). IllegalArgumentException from parse() at the clause limit: cffd01664bc96002aa733dccdbd8b3f466599e34 (svn r1152892, LUCENE-3338 and LUCENE-3343: open ranges and comparison operators for the flexible parser, by Adriano Crestani Campos), present since open numeric bounds exist [read]; BooleanQueryNodeBuilder has built its message with toQueryString since LUCENE-1567 (2.9.0) [read]",
   "introduced_date": "2025-05-29 (round-trip failures, #14697); 2011-08-01 (IllegalArgumentException at the clause limit, cffd01664bc9)",
   "first_affected_version": "4.0.0-alpha for the IllegalArgumentException from StandardQueryParser.parse at the clause limit [read]; the round-trip failures are unreleased (main only, 11.0.0-SNAPSHOT), because before #14697 every range printed the old '[f:a f:c]' format, the known #7865 bug",
   "affected_versions": "IllegalArgumentException at the clause limit: every release from 4.0.0-alpha to 10.6.0 (10.6.0 by reading) and main [exec]; not 3.6.2 and earlier, where open numeric bounds did not exist [exec]. Round-trip failures: main ea57360912ed only [exec]; not on the branch_10x or branch_10_6 heads of 2026-10-24 and in no release tag [read]; on 9.12.3 and 10.5.2 every range still prints the old pre-#7865 format, so the promise does not exist there [exec]. 10.6.0 (released 2026-10-29) very likely has only the clause-limit part [read]. Not executed: 4.0.0-alpha/beta and the LegacyNumericConfig path of 6.x-8.x. All runs: OpenJDK 25.0.3, Linux aarch64",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/7865",
    "https://issues.apache.org/jira/browse/LUCENE-6807",
    "https://github.com/apache/lucene/issues/14697",
    "https://github.com/apache/lucene/issues/13234",
    "https://github.com/apache/lucene/issues/13887",
    "https://github.com/apache/lucene/issues/13323"
   ],
   "doc": "",
   "repro": "repro/LFV-355/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-028",
   "priority": "low",
   "priority_rank": 967,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / classic and flexible",
   "title": "A boost too large for a float parses to Infinity and both query parsers throw IllegalArgumentException",
   "summary": "You parse a query whose boost literal is too large for a float (2^128 - 2^103 or more, which takes 39 digits) with the classic or flexible query parser. You expect a parse error or a usable boost. Instead the boost parses to Infinity and BoostQuery's finite check throws IllegalArgumentException out of parse().",
   "impact_class": "wrong error",
   "introduced_commit": "LUCENE-7996 (a8a63464e7da) added the isFinite check to BoostQuery",
   "introduced_date": "2017-12-06",
   "first_affected_version": "8.0.0",
   "affected_versions": "every release from 8.0.0 to 10.6.0 (61 releases) and main 645d4fe14a20 [exec]; 7.0.0-7.7.3 return (f:lucene)^Infinity instead [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-028.html",
   "repro": "repro/LFV-028/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-300",
   "priority": "low",
   "priority_rank": 968,
   "novelty": "known",
   "withheld": false,
   "area": "queryparser / classic (QueryParserBase.handleQuotedTerm and getFieldQuery, MultiFieldQueryParser.applySlop; the negative-slop check of PhraseQuery and MultiPhraseQuery.Builder)",
   "title": "Classic QueryParser and MultiFieldQueryParser: a negative phrase slop such as \"a b\"~-1 makes parse() throw IllegalArgumentException instead of ParseException",
   "summary": "You parse \"a b\"~-1, a quoted phrase with a negative proximity, with the classic QueryParser or MultiFieldQueryParser. You expect a ParseException, which parse() documents and which the same parser gives for the negative fuzzy distance a~-1 (or the slop to be ignored, as SimpleQueryParser does). Instead parse() throws IllegalArgumentException 'Slop must be >= 0, got -1' from the PhraseQuery constructor ('slop value cannot be negative' from MultiPhraseQuery.Builder when the analyzer adds synonyms), because the lexer accepts '~-1' and handleQuotedTerm passes the negative number on unchecked.",
   "impact_class": "wrong error",
   "introduced_commit": "584fda3bdf0a5b044046feb63c322ae8dee997a4 (LUCENE-5410 'add fuzzy and near to SimpleQueryParser', migrated as apache/lucene#6473; trunk svn r1563558, committed by rmuir from a patch by dakrone, 2014-02-02; SVN era, no pull request); its branch_4x backport b18fdadedecad444583eaa0eb343c35d6aa84707 (r1563562) shipped in 4.7.0. It added IllegalArgumentException('slop value cannot be negative') to PhraseQuery.setSlop and MultiPhraseQuery.setSlop and clamped a negative slop to 0 in SimpleQueryParser only. The classic parser was not touched: since LUCENE-4745 (enabling change, apache/lucene#5810, trunk 34ec469b9db / branch_4x 445e7c1267f, 2013-02-05, first in 4.2.0) its FUZZY_SLOP token admits '-', so '~-1' reaches handleQuotedTerm as slop -1, which 4.2.0-4.6.1 silently put into the PhraseQuery. [read]",
   "introduced_date": "2014-02-02 (584fda3bdf0 and its branch_4x backport b18fdadedec); enabling lexer change LUCENE-4745 2013-02-05",
   "first_affected_version": "4.7.0 [exec] (IllegalArgumentException 'slop value cannot be negative' from PhraseQuery.setSlop via handleQuotedTerm); 4.6.1, the last release before, does not throw [exec]: 4.2.0-4.6.1 silently build a PhraseQuery with slop -1, and 4.0.0-4.1.0 read ~-1 as a bare ~ plus the prohibited clause -1 [exec]",
   "affected_versions": "every release from 4.7.0 through 10.5.2 (the latest release on 2026-10-26) and main ea57360912ed; not fixed upstream. [exec] the history main() probe (QueryParser and MultiFieldQueryParser, WhitespaceAnalyzer, control \"a b\"~2) fails on 4.7.0, 4.10.4, 5.0.0, 5.2.1, 5.3.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main and passes on 4.1.0, 4.2.0 and 4.6.1; the finder's JUnit fails on 9.12.3, 10.5.2 and main (-ea and -da); the independent reproduction's JUnit fails on 9.12.3, 10.5.2 and main (-ea and -da) and the independent reproduction's main() variant on 8.11.4. The message is 'slop value cannot be negative' up to 5.2.1 and 'Slop must be >= 0, got -1' from 5.3.0 (LUCENE-6531). [read] every release tag 4.7.0-8.8.1 and 9.0.0-10.5.2 in the history clone has the PhraseQuery check, no sign check in handleQuotedTerm and no IllegalArgumentException catch in parse(); 8.9.0-8.11.3 are not tagged in the clone. The MultiPhraseQuery (synonym) path was executed on main only. All runs on JDK 25.0.3, aarch64 Linux, not each release's own JDK.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/7761",
    "https://issues.apache.org/jira/browse/LUCENE-6703",
    "https://github.com/apache/lucene/issues/2025",
    "https://issues.apache.org/jira/browse/LUCENE-950",
    "https://github.com/apache/lucene/issues/13437",
    "https://github.com/apache/lucene/issues/6473"
   ],
   "doc": "",
   "repro": "repro/LFV-300/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-715",
   "priority": "low",
   "priority_rank": 969,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / complexPhrase: ComplexPhraseQueryParser (pass-2 same-field check for clauses nested in a phrase)",
   "title": "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",
   "summary": "You parse a quoted phrase such as \"jo* id:2*\" or \"jo* id:/2/\" with ComplexPhraseQueryParser on the default field name; its class javadoc says the second pass checks that all embedded clauses refer to the same field, and it rejects \"jo* id:2\", \"jo* id:2?\", \"jo* id:2~1\" and \"jo* id:[1 TO 2]\" at parse time, so you expect a parse error. Instead parse() succeeds, because the check is wired into newTermQuery, getWildcardQuery, getRangeQuery and getFuzzyQuery but the class never overrides getPrefixQuery or getRegexpQuery, and the search then throws IllegalArgumentException 'Clauses must have same field.'. A one-clause phrase such as name:\"id:2*\" also parses, and because rewrite returns a lone multi-term query unchanged, it searches field id and returns the document whose id is 2.",
   "impact_class": "wrong error",
   "introduced_commit": "f7fa57997191 (LUCENE-1486, GitHub #2560, the initial commit of ComplexPhraseQueryParser, 2009-07-06; Subversion era, no pull request) for the prefix forms: it applied checkPhraseClauseIsForSameField in newTermQuery, getWildcardQuery, getRangeQuery and getFuzzyQuery but never overrode getPrefixQuery, although the classic grammar already sent prefix tokens there (QueryParser.jj at f7fa5799719). The regexp forms come from 838e19beae1f (LUCENE-2604, #3678, 2010-08-30), which added regexp syntax and QueryParser.getRegexpQuery without an override in this class. The one-clause search on the other field comes from LUCENE-7614 (#8665; 52f2a77b78fc on master, backport ac85a41cbefa on branch_6x, 2017-01-05), whose rewrite fast path returns a lone MultiTermQuery unchanged; before it, the one-clause form threw 'Unknown query type' at search. Not a regression: the gap is as old as the class [read]",
   "introduced_date": "2009-07-06 (prefix forms, LUCENE-1486); 2010-08-30 (regexp forms, LUCENE-2604); 2017-01-05 (one-clause search on the other field, LUCENE-7614)",
   "first_affected_version": "2.9.0 [exec] (first release with ComplexPhraseQueryParser; 2.4.1 has no such class [exec]); the regexp forms from 4.0.0-alpha [read]; the one-clause search on the other field from 6.4.0 [exec] (2.9.0 to 6.3.0 also accept the one-clause form, but its search throws 'Unknown query type' [exec])",
   "affected_versions": "Every release from 2.9.0 through 10.6.0, and main a9779ef3c193 and 645d4fe14a20 (unreleased 11.0); never fixed. [exec] the minimal repro fails on main 645d4fe14a20 and on the 10.6.0 release jars (SHA-1 checked against Maven Central), -ea and -da (2026-11-01). [exec] 2.9.0, 2.9.4, 3.0.0, 3.0.3, 3.1.0, 3.6.2, 4.0.0, 4.10.4, 5.0.0, 5.5.5, 6.3.0, 6.4.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); [exec] 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (finder's test), 10.5.2 and 9.12.3 (the independent reproducer's test), 10.5.2 (the intended-behaviour check's test). In 2.9.0-3.6.2 only the prefix forms exist (no regexp syntax: '/2/' is an ordinary term there and is rejected [exec]). Other point releases [read]. Upstream main a95c754ee003, branch_10x 1309534296e and branch_10_6 2763db11b0a still have no getPrefixQuery/getRegexpQuery override [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-715.html",
   "repro": "repro/LFV-715/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-588",
   "priority": "low",
   "priority_rank": 970,
   "novelty": "new",
   "withheld": false,
   "area": "core / util QueryBuilder token boosts on stacked tokens (newSynonymQuery; BoostAttribute from DelimitedBoostTokenFilter and weighted synonyms; reached through the classic and simple query parsers)",
   "title": "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",
   "summary": "You configure weighted synonyms ('leopard, panthera|1.5') or let users type boosts ('leopard|2'), and expect QueryBuilder to apply the weight, as it does for a word without a synonym: 'lion => simba|1.5' gives (body:simba)^1.5 and 'tiger|2' gives (body:tiger)^2.0. But when the boosted token shares its position with another token, QueryBuilder.newSynonymQuery passes the raw boost to SynonymQuery.Builder.addTerm, which accepts only (0, 1], so building the query throws IllegalArgumentException 'boost must be a positive float between 0 (exclusive) and 1 (inclusive)' and QueryParser.parse('spotted leopard') fails with it instead of returning a query or a ParseException. Weights in (0, 1] work on both paths; whether 1.5 or 0 works depends only on whether the analyzer stacked the token.",
   "impact_class": "wrong error",
   "introduced_commit": "663611c99c7d48dd31d53ea17644fcecd5e0fad7 '[SOLR-12238] Synonym Queries boost (#357)' (apache/lucene-solr#357; SOLR-12238 and LUCENE-9171 = apache/lucene#10211; branch_8x backport 2752d50dd1dc, same day) [read]. It made QueryBuilder read BoostAttribute, wrap an unstacked token's boost in a BoostQuery and pass a stacked token's boost unchanged to SynonymQuery.Builder.addTerm, whose (0, 1] check comes from LUCENE-8652 (d8cfeba912ea, 2019-03-11, first released in 8.1.0; not a defect on its own, because QueryBuilder passed no boosts before 8.5.0)",
   "introduced_date": "2020-02-24",
   "first_affected_version": "8.5.0 [exec] (8.4.1 not affected [exec]: QueryBuilder ignored BoostAttribute and DelimitedBoostTokenFilter did not exist; the weighted-synonym feature and this failure arrived together)",
   "affected_versions": "8.5.0 through 10.6.0 and main [exec]. Not affected: 8.4.1 and earlier [exec]. All runs on JDK 25, not each release's own JDK.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-588.html",
   "repro": "repro/LFV-588/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-548",
   "priority": "low",
   "priority_rank": 971,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / synonym (SolrSynonymParser; SynonymGraphFilterFactory and SynonymFilterFactory, format solr)",
   "title": "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)",
   "summary": "You load a synonyms file such as 'couch, sofa', then a line holding three spaces or a tab, then 'big, large', and expect it to parse, because the SolrSynonymParser javadoc says 'Blank lines and lines starting with '#' are comments'. Instead the whole file is rejected with ParseException 'Invalid synonym rule at line 2': the parser skips a line only when it has zero length (or starts with '#'), so the whitespace-only line is parsed as a rule whose single term trims to the empty string, which the analyzer step rejects. A truly empty line parses fine, and so did whitespace-only lines in the Solr loader this format came from before 3.4.",
   "impact_class": "wrong error",
   "introduced_commit": "015ecfa0a0255f053682bb2436b2b8dec5cb8283 (LUCENE-3233 'improve ram/perf of SynonymFilter, add wordnet parsing, nuke contrib/wordnet', trunk r1145158, @rmuir; branch_3x backport a52015db05f, r1145178; no pull request, the issue was migrated as apache/lucene#4306) [read]. Not a later regression: the class has rejected such lines since it was written; relative to the format's previous loader (Solr's SolrResourceLoader.getLines: trim, then skip empty) it is a narrowing at 3.4",
   "introduced_date": "2011-07-11",
   "first_affected_version": "3.4.0 (released 2011-09-14, the first release with SolrSynonymParser) [exec]; first 4.x release 4.0.0-alpha [read], 4.0.0 [exec]",
   "affected_versions": "every release from 3.4.0 through 10.6.0, and main ea57360912ed and 645d4fe14a20; [exec] the minimal repro fails on main 645d4fe14a20 and on the 10.6.0 release jars (SHA-1 checked against Maven Central), -ea and -da (2026-11-01); the version-portable main() probe fails (spaces-only and tab-only line rejected, empty-line control parses) on 3.4.0, 3.6.2, 4.0.0, 4.4.0, 4.5.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da), and passes on main with the one-line fix shadowed; the finder's JUnit fails 2 of 3 on main (-ea, -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 4 of 5 on main (-ea, -da), 10.5.2 and 9.12.3; the intended-behaviour check's factory-path JUnit fails 3 of 6 on main (-ea, -da), 10.5.2 and 9.12.3; [read] all 128 release tags 3.4.0..10.5.2 in the history clone carry the identical check (the 8.8.2..8.11.4 tags are not in the clone; 8.11.4 was executed), and upstream main still has it (GitHub contents API, 2026-10-26). From 3.4 to 4.10.4 a factory with luceneMatchVersion < 3.4 used the old loader, which accepts such files; that loader is gone from 5.0.0. aarch64 with JDK 25 only (pure string handling)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-548.html",
   "repro": "repro/LFV-548/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-307",
   "priority": "low",
   "priority_rank": 972,
   "novelty": "known",
   "withheld": false,
   "area": "analysis / char filters (MappingCharFilterFactory mapping-file parser)",
   "title": "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",
   "summary": "You configure the mapping char filter with a mapping file that contains one rule whose source or target is longer than 256 characters, for example \"abc\" => \"<257 x>\" or a long boilerplate phrase mapped to \"\", and expect the factory to build the map (NormalizeCharMap.Builder accepts such strings when called directly, and no limit is documented) or to reject the rule with an IllegalArgumentException that names it, as it does for other bad rules. Instead MappingCharFilterFactory.inform() throws java.lang.ArrayIndexOutOfBoundsException: Index 256 out of bounds for length 256 from parseString, which copies each unescaped rule string into a fixed 256-character instance buffer without a bounds check. A 256-character string still works, and the limit counts characters after unescaping (256 \\uNNNN escapes, 1536 raw characters, pass).",
   "impact_class": "wrong error",
   "introduced_commit": "eb0ec4a3e2bb7644c4c980cc0ee4cc35f2b1782e (Solr trunk, SVN r713902), SOLR-822 'Add CharFilter so that characters can be filtered before Tokenizer/TokenFilters' by Koji Sekiguchi, which created MappingCharFilterFactory with the instance field 'char[] out = new char[256];' and the unchecked 'out[writePos++] = c;' in parseString [read]; the code reached the Lucene analysis module unchanged through the LUCENE-2510 factory move (fe2d1194fb6 on trunk, 677846e6a0f on branch_4x), a pure rename (R100) [read]",
   "introduced_date": "2008-11-14 (eb0ec4a3e2b, commit date); moved into the Lucene analysis module 2012-07-24 (trunk) and 2012-07-25 (branch_4x)",
   "first_affected_version": "Solr 1.4.0 (2009-11, as org.apache.solr.analysis.MappingCharFilterFactory) [exec]; as a Lucene API 4.0.0-BETA (2012-08), the first Lucene release that ships org.apache.lucene.analysis.charfilter.MappingCharFilterFactory [exec]; 4.0.0 is the first final Lucene release [exec]",
   "affected_versions": "Every release that has the class, through 10.5.2, and main ea57360912ed. [exec] fails (AIOOBE 'Index 256 out of bounds for length 256' in parseString, 256-character controls pass) on Solr 1.4.0 (on Lucene 2.9.1) and Lucene 4.0.0-BETA, 4.0.0, 4.2.1, 4.3.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0 and 10.5.2 (-ea and -da) and main (-ea and -da); [read] all 132 release tags in the full-history clone that contain the factory (Solr 1.4.0, lucene-solr 3.1 to 8.8.1, lucene 9.0.0 to 10.5.2) have the same buffer and write lines. Lucene/Solr 3.1 to 3.6.2 and 4.0.0-ALPHA shipped the factory only in Solr core [read]. Not applicable: Solr 1.3.0 and Lucene up to 4.0.0-ALPHA (no such class) [exec]. Not fixed on upstream main (e1c4184cb983, 2026-10-26) or branch_10x, and no open PR changes the file [read].",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-3830",
    "https://issues.apache.org/jira/browse/LUCENE-10352",
    "https://github.com/apache/lucene/issues/7591"
   ],
   "doc": "",
   "repro": "repro/LFV-307/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-345",
   "priority": "low",
   "priority_rank": 973,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / hunspell (Dictionary affix-file parsing)",
   "title": "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",
   "summary": "You load a hunspell dictionary whose .aff file ends with a REP, MAP, ICONV/OCONV, COMPOUNDRULE, BREAK or CHECKCOMPOUNDPATTERN table that announces more lines than it holds (for example 'REP 2' followed by a single REP line, as a cut-off download or a careless hand edit leaves it), and expect the parse error that the Dictionary constructors document (ParseException), which is what Lucene already throws for a PFX/SFX table cut short ('Premature end of rules') and, since 10.2.0, what the tolerateRepRuleCountMismatches() javadoc promises for a wrong REP count by default. Instead the parser passes the null that readLine() returns at end of file straight into a string method and throws NullPointerException ('Cannot invoke \"String.split(String)\" because \"line\" is null'), with no directive or line number, which also bypasses HunspellStemFilterFactory's 'Unable to load hunspell data!' wrapping of ParseException. The file is refused either way; only the error is wrong.",
   "impact_class": "wrong error",
   "introduced_commit": "Two introduction points, one root cause: each counted-table parser passed reader.readLine() to a string method without an end-of-file check from its first commit. ICONV/OCONV: 3064419624fd10622da2844399d4009fc2e62e00 (LUCENE-5224, by rmuir, svn r1574135, no GitHub PR; branch_4x backport 66368a9f904c). The other five on main in 2021, each in its own commit by donnerpeter: BREAK 939699f5509 (lucene-solr#2207, LUCENE-9667), COMPOUNDRULE d7968130c3f (lucene-solr#2228, LUCENE-9684), REP 8a34cc7afd3 (lucene-solr#2251, LUCENE-9701), CHECKCOMPOUNDPATTERN d0ae2bd2b9c (lucene-solr#2280, LUCENE-9717), MAP 653626399f1 (lucene-solr#2314, LUCENE-9736); they reached 8.x through the squashed branch_8x backport c6b964a1157 (lucene-solr#2499, LUCENE-9687). [read]. f64e7cbbda1 (LUCENE-9691) later moved the split into splitBySpace (refactor, not the origin). Not a regression: no release ever gave a ParseException for these tables",
   "introduced_date": "2014-03-04 (ICONV/OCONV, LUCENE-5224); 2021-01-20 to 2021-02-08 (BREAK, COMPOUNDRULE, REP, CHECKCOMPOUNDPATTERN, MAP on main); 2021-05-28 (branch_8x backport)",
   "first_affected_version": "4.8.0 for ICONV/OCONV [exec]; all six tables from 8.9.0 (branch_8x backport) and 9.0.0 [exec]",
   "affected_versions": "4.8.0 - 8.8.2: ICONV and OCONV only [exec]; 8.9.0 - 8.11.4, 9.0.0 - 9.12.3, 10.0.0 - 10.6.0 and main ea57360912ed: all six tables [exec]; [read] the same unguarded readLine() arguments and the null-unchecked splitBySpace are present at every 9.x and 10.x tag, and parseConversions has the unchecked read at every tag from 4.8.0 on. Up to 9.7.0 a short PFX/SFX table also threw NPE; #12468 fixed that in 9.8.0, so the PFX/SFX-vs-other-tables inconsistency exists since 9.8.0 and the REP javadoc contract since 10.2.0. Not fixed upstream: Dictionary.java on upstream main e1c4184cb983 (2026-10-26) is byte-identical to the snapshot. Not affected: 4.7.2 and older (none of the six tables parsed). All runs on aarch64 with JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-345.html",
   "repro": "repro/LFV-345/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1012",
   "priority": "low",
   "priority_rank": 974,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / hunspell Dictionary parsing (AM morphological aliases)",
   "title": "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'",
   "summary": "You load a hunspell dictionary whose affix file has an AM table, for example 'AM 1' and 'AM po:noun', and whose .dic has an entry 'foo<TAB>2' that points at an alias the table does not define (or alias 0, or 'AM 2' with only one AM line). You expect a descriptive error, as for the same mistake in the flag-alias (AF) table, which gives IllegalArgumentException 'Bad flag alias number:2' (C Hunspell's source, the reference implementation, range-checks the index and keeps the word without morphological data; its 'bad morph. alias index' warning prints only in builds with HUNSPELL_WARNING_ON). Instead every Dictionary constructor fails with java.lang.ArrayIndexOutOfBoundsException 'Index 1 out of bounds for length 1' (or NullPointerException 'Cannot invoke \"String.isBlank()\" because \"morphData\" is null') from Dictionary.splitMorphData, which reads morphAliases[alias - 1] with no range check, and has done so since AM aliases were added in 4.10.0 (LUCENE-5778).",
   "impact_class": "wrong error",
   "introduced_commit": "532d9f246b829d69b548b5716c591b925ed47ca3 (trunk; LUCENE-5778 'Support hunspell morphological description fields', migrated as apache/lucene#6840, by Robert Muir, svn r1604354, no PR: pre-GitHub), backported to branch_4x as b937174858c7978da798e86089b36c50cdb820f0 (r1604355). It added parseMorphAlias (array sized by the declared AM count) and the alias lookup 'morphData = morphAliases[alias-1]' inside a try that catches only NumberFormatException; it did not copy the range guard that the AF lookup (getAliasValue) has had since LUCENE-4079 (b4fe59532ee, 2012-05-30). No later commit added a range or null check: 2189b7a761d (LUCENE-6134, comment), 8ef6a0da568 (LUCENE-9570, reformat), 1852d7ad5ae (LUCENE-9734 / #2308, renamed parseStemException to splitMorphData, lookup copied unchanged), 2971f311a2b (#70) and ad24abfb0df (#15109) change no behaviour [read: git log -S 'morphAliases[', -G 'morphAliases\\[alias', -L on splitMorphData and parseMorphAlias, blame of Dictionary.java:1306-1314 on 645d4fe] [exec: release probe passes on 4.9.0 and 4.9.1, which have no AM support, and fails from 4.10.0]. Bisection is at release granularity; the introducing commit is the feature commit itself.",
   "introduced_date": "2014-06-21 (532d9f246b8 on trunk 13:15:57 UTC and b937174858c on branch_4x 13:19:02 UTC; LUCENE-5778 resolved the same day)",
   "first_affected_version": "4.10.0 [exec]",
   "affected_versions": "[exec] every release on Maven Central from 4.10.0 to 10.5.2 (112 releases; release-agnostic main() probe MorphAliasHistoryProbe with -ea, also -da on 4.10.0, 10.5.2 and main), 10.6.0 (4ae946e5a9b: the probe on the branch_10_6 jars; the minimal repro on the SHA-1-checked 10.6.0 release jars, -ea and -da, 2026-11-01) and main 645d4fe14a20 (-ea and -da: the finder, the independent reproducer, the intended-behaviour check, the adjudication and separate re-runs). The finder's 5-test JUnit (needs SortingStrategy, so 9.9.0 or later) fails 3 of 5 on 9.9.0, 9.12.3, 10.5.2 and main; the independent reproduction's JUnit fails 2 of 4 on main, 10.5.2 and 9.12.3; the finder's main() variant fails on 8.11.2. The NullPointerException variant (AM declares more entries than it defines) fails on every probed version too; only its message changes with the code shape (String.indexOf 4.10.0-8.8.2, String.trim 8.9.0-8.11.4, String.isBlank 9.0.0-main). Not affected: 4.9.0 and 4.9.1 [exec] and older [read], where AM aliases did not exist. Not new in 10.6. Not fixed upstream: main head is still 645d4fe and the newest commit to Dictionary.java on main is #16313 (author date 2026-07-21, a refactor) (checked 2026-10-29). All runs JDK 25 on aarch64 Linux.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1012.html",
   "repro": "repro/LFV-1012/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-372",
   "priority": "low",
   "priority_rank": 975,
   "novelty": "new",
   "withheld": false,
   "area": "util / sorters (Sorter heap sort, IntroSorter's depth fallback)",
   "title": "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)",
   "summary": "You sort a legal slice with IntroSorter, for example ArrayUtil.introSort on the last 1,000 elements of an array of length ArrayUtil.MAX_ARRAY_LENGTH (or a slice of more than 2^30 elements starting at 0), and the element order makes IntroSorter give up on quicksort and fall back to heap sort. You expect the slice [from, to) to be sorted using only slots inside it. Instead Sorter.heapChild computes 2*(i - from) + 1 + from in int, which wraps to a negative number for a node that has no child, siftDown's 'leftChild < to' check lets it through, and compare is called with a negative slot, so the array-backed sort throws ArrayIndexOutOfBoundsException ('Index -2147482757 out of bounds for length 2147483631').",
   "impact_class": "crash",
   "introduced_commit": "b895ebde4340 (LUCENE-4946 'Refactor SorterTemplate (now Sorter)', by GitHub jpountz, svn r1478785 on trunk; branch_4x backport fd331e9d5f6b, svn r1478802, which the 4.x releases contain; committed from JIRA patches, no GitHub PR; the issue is now #6010) [read] [exec]. Not a regression: LUCENE-7097 (8cbe4713775) and LUCENE-10196 (63b9e603e6f) changed IntroSorter's depth budget and partitioning but kept the heap-sort fallback, and the heap arithmetic is unchanged since 2013",
   "introduced_date": "2013-05-03 (b895ebde4340 and its backport fd331e9d5f6b)",
   "first_affected_version": "4.4.0 [exec] (release tag 2013-07-22; the first release with Sorter and IntroSorter, via the branch_4x backport); 4.3.1, the last release before, has no such API [exec], and its SorterTemplate predecessor stays inside the slice at the same slots [exec]",
   "affected_versions": "every release from 4.4.0 through 10.6.0 and main (ea57360912ed, 645d4fe14a20); no version has a fix. [exec] [read]; 8.8.2 to 8.11.3 were not executed one by one (tags not in the history clone; 8.11.4 fails); 10.6.0 (released 2026-10-29): the minimal repro fails with -ea and -da [exec], as does 9.1.0 (-da) [exec]. Caveat: every run used JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-372.html",
   "repro": "repro/LFV-372/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-335",
   "priority": "low",
   "priority_rank": 976,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / kuromoji (JapaneseCompletionFilterFactory 'mode' argument parsing, SPI name japaneseCompletion)",
   "title": "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)",
   "summary": "You configure the Japanese completion filter through its factory with mode=\"query\", for example CustomAnalyzer.builder().withTokenizer(\"japanese\", \"mode\", \"normal\").addTokenFilter(\"japaneseCompletion\", \"mode\", \"query\"), the same way the sibling Japanese tokenizer factory accepts mode=\"search\". You expect a QUERY-mode filter, because the factory's own parsing code calls toUpperCase(Locale.ROOT) on the mode. Instead the constructor throws IllegalArgumentException 'No enum constant ...JapaneseCompletionFilter.Mode.query': the toUpperCase is applied to the default name \"INDEX\", which is already upper case, so the configured value reaches the case-sensitive Enum.valueOf unchanged and only the exact names INDEX and QUERY work.",
   "impact_class": "minor",
   "introduced_commit": "4e86df96c0385a7b552434d7e2a9bee69f18bd77 (apache/lucene#297, LUCENE-10102 / GitHub issue #11140 'Add JapaneseCompletionFilter for Input Method-aware auto-completion', by GitHub mocobeta, co-authored by rmuir) [read]. Present since the factory was written, so not a regression; the other LUCENE-10102 commits (5dfbef313cf, 6c1e5920d84) touch only JapaneseCompletionFilter.java",
   "introduced_date": "2021-09-17 (authored 22:37 +0900; merged 2021-09-17T13:37:13Z)",
   "first_affected_version": "9.0.0 [exec] (the first release with JapaneseCompletionFilterFactory, tagged 2021-12-06; CHANGES.txt lists LUCENE-10102 only under 9.0.0 New Features; 8.9.0, 8.10.1 and 8.11.4 do not have the class [exec])",
   "affected_versions": "every release that has the factory: 9.0.0, 9.1.0, 9.2.0, 9.3.0, 9.4.0-9.4.2, 9.5.0, 9.6.0, 9.7.0, 9.8.0, 9.9.0-9.9.2, 9.10.0, 9.11.0, 9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2, 10.6.0 and main ea57360912ed [exec]; not applicable to 8.x and older, where the class does not exist [exec]; upstream main still has the expression (read 2026-10-26, head e1c4184cb983); not fixed anywhere. All runs used JDK 25 on Linux aarch64, which does not matter for this string parsing",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-335.html",
   "repro": "repro/LFV-335/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-439",
   "priority": "low",
   "priority_rank": 977,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / compound word factory (DictionaryCompoundWordTokenFilterFactory parameter handling)",
   "title": "DictionaryCompoundWordTokenFilterFactory (main only) warns 'onlyLongestMatch has been removed' when the key is absent and stays silent when onlyLongestMatch=\"false\" is passed",
   "summary": "You build DictionaryCompoundWordTokenFilterFactory on main without the onlyLongestMatch key, for example with only onlyLongestMatchIgnoreSubwords, and expect no message about a key you never used; instead every construction logs the WARNING 'onlyLongestMatch has been removed and replaced by onlyLongestMatchIgnoreSubwords'. A configuration that does pass onlyLongestMatch=\"false\", the one setting whose meaning is now ignored, gets no warning, because the factory reads the removed key with default true and warns when the value is true (getBoolean(args, \"onlyLongestMatch\", true); if (onlyLongestMatch) LOG.warning(...)), not when the key is present. Only the log is wrong: the tokens are the same with or without the warning.",
   "impact_class": "minor",
   "introduced_commit": "ebc63504bd627ff15974efb86c7883ecb489d10f, apache/lucene#14356 'removing constructor with deprecated attribute 'onlyLongestMatch' (author renatoh, merged by rmuir, main only) [read]",
   "introduced_date": "2025-05-10 (merged; the warning line was already in the PR on 2025-03-14, the date of the author's review comment on it)",
   "first_affected_version": "unreleased (main / 11.0.0-SNAPSHOT only: no release tag contains ebc63504bd6; would first ship in 11.0.0 unless fixed)",
   "affected_versions": "main from ebc63504bd6 (2025-05-10) through ea57360912ed and 645d4fe14a20 [exec]; upstream main c50bc9523db still has the same lines [read]; not affected: 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.4.0, 10.5.0, 10.5.2 [exec] and 10.6.0 [exec]; the factory at every release tag 9.1.0-10.5.2 and on upstream branch_10x, branch_10_5 and branch_10_6 has no LOG.warning [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-439.html",
   "repro": "repro/LFV-439/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-361",
   "priority": "low",
   "priority_rank": 978,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / xml (BooleanQueryBuilder)",
   "title": "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)",
   "summary": "You give the XML query parser (CoreParser.parse) a <BooleanQuery> whose <Clause> has no occurs attribute and expect an optional (SHOULD) clause, because LuceneCoreQuery.dtd declares occurs with the default \"should\", BooleanQueryBuilder.getOccursValue has its own 'attribute absent -> SHOULD' branch, and 5.0.0 and earlier parsed it that way. Instead the whole parse fails with ParserException 'Invalid value for \"occurs\" attribute of clause:' (nothing after the colon): org.w3c.dom.Element.getAttribute returns an empty string, never null, for an absent attribute, so the 'occs == null' default branch never runs; an explicit occurs=\"\" is rejected the same way. Explicit should, must, mustNot and filter values work as before, and writing occurs=\"should\" is a workaround.",
   "impact_class": "wrong error",
   "introduced_commit": "bed131f1808d40a4f7f79303f73e1c93aa750895 (trunk, svn r1661395) and its branch_5x backport 21fd3aa83d581add2a7a69a2def32b5b8983e4a9 (svn r1661412, the change that first shipped, in 5.1.0), LUCENE-6270 'Replace TermsFilter with TermsQuery' (migrated as GitHub #7332; by jpountz; JIRA-patch era, no PR) [read]. The rewrite of getOccursValue, done to add occurs=\"filter\", replaced the original '\"\".equals(occs)' -> SHOULD test (87768c51c63, 2006, first released in 1.9) with 'occs == null', which can never be true because Element.getAttribute returns \"\" for an absent attribute",
   "introduced_date": "2015-02-21",
   "first_affected_version": "5.1.0 [exec] (5.0.0 is the last unaffected release [exec]); on the trunk line 6.0.0 [exec]",
   "affected_versions": "every release from 5.1.0 through 10.6.0, and main ea57360912ed. Executed: main() probe rejects on 5.1.0, 6.0.0, 7.7.3, 8.11.4, 9.12.3, 10.5.2 and main (-ea); the JUnit fails on 9.12.3, 10.5.2 and main with -ea and -da [exec]. All 97 release tags 5.1.0-10.5.2 in the history clone contain 'occs == null ||' (8.8.2-8.11.4 are not tagged there; 8.11.4 executed) [read]. Not affected: 1.9 through 5.0.0 (all 49 tags have the old '\"\".equals(occs)' -> SHOULD form [read]; 4.10.4 and 5.0.0 executed, both parse the test query to 'f:a +f:b'). Upstream main unchanged on 2026-10-26 (last change to the file 2cbf261032d, a 2021 reformat) [read]. In 5.1-5.5.x BooleanFilterBuilder (CorePlusExtensionsParser) also called getOccursValue, so <BooleanFilter><Clause> without occurs is rejected too [exec]. The 10.6.0 release jars fail the one-test minimal repro with -ea and -da [exec]. All runs: OpenJDK 25.0.3, Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-361.html",
   "repro": "repro/LFV-361/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-570",
   "priority": "low",
   "priority_rank": 979,
   "novelty": "new",
   "withheld": false,
   "area": "core / geo WKT parsing (SimpleWKTShapeParser)",
   "title": "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)",
   "summary": "You call SimpleWKTShapeParser.parse(\"MULTIPOINT ((1 2), (3 4))\"), the Simple Features WKT form in which each point of a multipoint sits in its own parentheses, and expect double[][] {{1, 2}, {3, 4}}, because the class says it parses WKT in compliance with ISO/IEC 13249-3:2016 and it already accepts MULTIPOINT ((1 2)) and the bare legacy form MULTIPOINT (1 2, 3 4). Instead it throws java.text.ParseException \"expected ) but found: ','\", also inside a GEOMETRYCOLLECTION and with 3D points. The cause is in parseCoordinates: when the first point starts with '(' the code before the loop does not read that point's ')', so the loop takes that ')' as the end of the whole list and the check after the loop then finds the ',' where it wants the missing ')'; whether a parenthesized point is accepted therefore depends on where it sits (MULTIPOINT (1 2, (3 4), 5 6) parses, while MULTIPOINT (1 2, (3 4)) fails with 'expected word but found: END-OF-STREAM').",
   "impact_class": "wrong error",
   "introduced_commit": "bd714ca1edc681cd871e6d385bd98a9cb9d7ffe6 (main line, LUCENE-8538 'Add Simple WKT Shape Parser' by @nknize, migrated as apache/lucene#9584; JIRA patch era, no pull request; authored 2018-10-22, committed 2018-10-24 to master in lucene/sandbox; first shipped in 8.0.0) and its branch_7x backport 5e7858041b87fc9091b0aae7c228445ab6566231 (same day, byte-identical parser file; shipped in 7.6.0). The faulty order was born with the class and is not a regression [read]",
   "introduced_date": "2018-10-24",
   "first_affected_version": "7.6.0 [exec] (branch_7x backport; the class lived in lucene-sandbox from 7.6.0 to 8.4.1 and in lucene-core from 8.5.0, moved by LUCENE-8621 without logic changes); first main-line release 8.0.0 [exec]; 7.5.0 has no SimpleWKTShapeParser",
   "affected_versions": "every release from 7.6.0 through 10.6.0, and main ea57360912ed; the one-test minimal repro fails on the 10.6.0 release jars (SHA-1 checked against Maven Central) with -ea and -da [exec]. [exec] the finder's JUnit (2 controls, 2 bug tests) fails 2 of 4 with both controls passing on 7.6.0 (junitcore runner, because 7.6.0 pins JUnit 4.10), 7.7.3, 8.0.0, 8.4.1 (last sandbox release), 8.5.0 (first in core), 8.11.2, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da); the independent reproduction's JUnit fails 2 of 4 on main (-ea and -da), 10.5.2, 9.12.3 and 8.11.2 (sandbox jar); re-runs on main -ea and -da and 10.5.2 -da. [read] the logic is unchanged since the introducing commit, so the releases not executed are affected by inference; branch_10_6 (released as 10.6.0 on 2026-10-29) and the unreleased branch_10x carry it. Not fixed upstream: the file has no diff between ea57360912ed and upstream main a9779ef3c19 (2026-10-26). aarch64 with JDK 25 only (pure string parsing)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-570.html",
   "repro": "repro/LFV-570/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-562",
   "priority": "low",
   "priority_rank": 980,
   "novelty": "new",
   "withheld": false,
   "area": "core / geo GeoJSON parsing (Polygon.fromGeoJSON, SimpleGeoJSONPolygonParser)",
   "title": "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)",
   "summary": "You call Polygon.fromGeoJSON on a standard GeoJSON Feature whose geometry is a single Polygon and whose properties contain an ordinary data member named \"type\", for example {\"type\": \"Feature\", \"geometry\": {...Polygon...}, \"properties\": {\"type\": \"multipolygon\"}}, and expect the polygon back, because the javadoc accepts a Polygon 'optionally embedded under a \"type: Feature\"' and GeoJSON allows any JSON object as properties. Instead it throws ParseException 'can only handle type FeatureCollection (if it has a single polygon geometry), Feature, Polygon or MultiPolygon, but got multipolygon' ('type should be a string, but got: 3.0' for {\"type\": 3}), because the parser reads every \"type\" member outside crs as a GeoJSON object type, wherever it sits, while it reads \"coordinates\" only at geometry positions. The same Feature without the \"type\" property parses, and a \"coordinates\" key inside properties is ignored.",
   "impact_class": "wrong error",
   "introduced_commit": "343f374b530fa71dc6102d74725b536f5f1367f3 (main line, 2016-07-15, 'LUCENE-7380: add Polygon.fromGeoJSON', committed by @mikemccand after a +1 from @rmuir; LUCENE-7380 is apache/lucene#8433; JIRA patch era, no pull request; first shipped in 7.0.0) and its branch_6x backport 573aaf75f52f446c8b7ab915eefd420013c544a1 (same message, shipped in 6.2.0). The check was born with the file and is not a regression [read]",
   "introduced_date": "2016-07-15",
   "first_affected_version": "6.2.0 [exec] (the first release with Polygon.fromGeoJSON and SimpleGeoJSONPolygonParser; 6.1.0 has neither); first 7.x release 7.0.0 [exec], from the main-line commit",
   "affected_versions": "every release from 6.2.0 through 10.6.0, and main ea57360912ed. [exec] a sweep of all 90 releases from 6.2.0 to 10.6.0 fails the one-test minimal repro (up to 9.0.0 a copy with the old test-framework import) with -ea, and 6.2.0, 10.6.0 and main 645d4fe14a20 fail it with -da too; earlier the finder's JUnit (one control, two properties cases) fails 2 of 3 with the control passing on 6.2.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da) in the version-history runs, and on 7.7.3, 8.11.2, 9.0.0, 9.12.3 and 10.5.2 in the finder's runs (6.2.0, 6.6.6 and 7.0.0 with the junitcore runner, because their test framework pins junit 4.10; releases up to 8.0.0 print the original 'MutiPolygon' message, so each run used its own release's parser); the independent reproduction's 8-case JUnit fails 6 of 8 on main (-ea and -da), 10.5.2, 9.12.3 and 8.11.4; the intended-behaviour check's fails 4 of 8 on main (-ea and -da), 10.5.2 and 9.12.3. [read] the line is in all 80 non-RC release tags of the history clone that have the file (6.2.0-6.6.6, 7.0.0-7.7.3, 8.0.0-8.8.1, 9.0.0-9.12.3, 10.0.0-10.5.2); 8.8.2-8.11.3 are not tagged in the clone (all of them executed in the sweep). Not fixed upstream: upstream main a95c754ee003 (2026-10-26) has no newer commit on the parser. aarch64 with JDK 25 only (pure string parsing)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-562.html",
   "repro": "repro/LFV-562/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-569",
   "priority": "low",
   "priority_rank": 981,
   "novelty": "known",
   "withheld": false,
   "area": "core / geo GeoJSON parsing (Polygon.fromGeoJSON, SimpleGeoJSONPolygonParser)",
   "title": "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)",
   "summary": "You call Polygon.fromGeoJSON on valid GeoJSON in which one character of a key or of the type value is written as a JSON \\uXXXX escape, for example {\"type\": \"\\u0050olygon\", \"coordinates\": ...}, and expect the same polygon as for {\"type\": \"Polygon\", ...}, because JSON (RFC 8259 section 7) lets any string character be escaped and the parser has a branch commented '4 hex digit unicode BMP escape'. Instead that branch appends the code point with StringBuilder.append(int), that is as decimal digits, and does not skip the four hex digits, so \"\\u0050olygon\" becomes \"800050olygon\" and the call throws ParseException 'can only handle type ... but got 800050olygon' (an escaped key such as \"\\u0074ype\" gives 'did not see type: Polygon or MultiPolygon'). A malformed escape such as \\uZZZZ throws an unchecked NumberFormatException instead of ParseException, and because a garbled key no longer matches, a non-CRS84 crs whose 'name' key is escaped, or a second feature whose 'coordinates' key is escaped, is silently accepted instead of rejected.",
   "impact_class": "wrong error",
   "introduced_commit": "343f374b530fa71dc6102d74725b536f5f1367f3 (main line, 2016-07-15, 'LUCENE-7380: add Polygon.fromGeoJSON', committed by @mikemccand after a +1 from @rmuir; LUCENE-7380 is apache/lucene#8433; JIRA patch era, no pull request; first shipped in 7.0.0) and its branch_6x backport 573aaf75f52f446c8b7ab915eefd420013c544a1 (same message, shipped in 6.2.0). The escape branch was born with the file and is not a regression [read]",
   "introduced_date": "2016-07-15",
   "first_affected_version": "6.2.0 [exec] (the first release with Polygon.fromGeoJSON and SimpleGeoJSONPolygonParser; 6.1.0 has neither); first 7.x release 7.0.0 [exec], from the main-line commit",
   "affected_versions": "every release from 6.2.0 through 10.6.0 (10.6.0 by reading), and main ea57360912ed. [exec] the finder's JUnit (one control, an escaped type value, an escaped type key) fails 2 of 3 with the control passing on 6.2.0, 6.6.6 and 7.0.0 (junitcore runner, because their test framework pins junit 4.10), 7.7.3, 8.11.2, 9.0.0, 9.12.3, 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da); the independent reproduction's 7-case JUnit fails 6 of 7 on main (-ea and -da), 10.5.2 and 9.12.3, including the NumberFormatException case; the independent reproduction's crs probe (non-CRS84 crs accepted) fails 1 of 3 on main (-ea and -da) and 10.5.2; the intended-behaviour check's FeatureCollection-subset case was executed on main only (-ea and -da). [read] the line is in all 80 non-RC release tags of the history clone that have the file (6.2.0-6.6.6, 7.0.0-7.7.3, 8.0.0-8.8.1, 9.0.0-9.12.3, 10.0.0-10.5.2); 8.8.2-8.11.x are not tagged in the clone and are affected by inference (8.11.2 executed). The secondary effects are inferred for the releases where they were not executed (same line). Not fixed upstream: the line is still present on upstream main a95c754ee003 (2026-10-26), branch_10x, branch_10_6, branch_10_5 and branch_9_12. aarch64 with JDK 25 only (pure string parsing)",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-7380",
    "https://github.com/apache/lucene/issues/8433",
    "https://issues.apache.org/jira/browse/LUCENE-8964",
    "https://github.com/apache/lucene/issues/10007",
    "https://github.com/apache/lucene-solr/pull/866",
    "https://github.com/apache/lucene/issues/12295"
   ],
   "doc": "",
   "repro": "repro/LFV-569/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-953",
   "priority": "low",
   "priority_rank": 982,
   "novelty": "new",
   "withheld": false,
   "area": "core / geo GeoJSON parsing (Polygon.fromGeoJSON, SimpleGeoJSONPolygonParser)",
   "title": "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)",
   "summary": "You call Polygon.fromGeoJSON on a GeoJSON Polygon whose \"coordinates\" is null or an object, such as {\"type\":\"Polygon\",\"coordinates\":null}, or on a MultiPolygon with an object element, {\"type\":\"MultiPolygon\",\"coordinates\":[{}]}, and expect the ParseException that the parser has an explicit check for ('coordinates should be an array, but got: ...', 'elements of coordinates array should be an array, but got: ...'), as you get when coordinates is a string, a number or a boolean. Instead java.lang.NullPointerException ('Cannot invoke \"Object.getClass()\" because \"o\" is null') escapes, because SimpleGeoJSONPolygonParser stores JSON null and nested objects as Java null and both checks build their message with + o.getClass(). Every other type check in the class builds its message with + o, which is null-safe.",
   "impact_class": "wrong error",
   "introduced_commit": "343f374b530fa71dc6102d74725b536f5f1367f3 (main line, 2016-07-15, 'LUCENE-7380: add Polygon.fromGeoJSON', by mikemccand after a +1 from rmuir on the JIRA patch; LUCENE-7380 is apache/lucene#8433; JIRA-patch era, no pull request; first shipped in 7.0.0) and its branch_6x backport 573aaf75f52f446c8b7ab915eefd420013c544a1 (same message, shipped in 6.2.0). The bug was born with the API and is not a regression [read]",
   "introduced_date": "2016-07-15 (author and commit date of 343f374b530 and 573aaf75f52)",
   "first_affected_version": "6.2.0 [exec] (the first release with Polygon.fromGeoJSON and SimpleGeoJSONPolygonParser; 6.1.0 has no fromGeoJSON [exec]); first 7.x release 7.0.0 [exec], from the main-line commit",
   "affected_versions": "Every release that has Polygon.fromGeoJSON: 6.2.0-6.6.6, all 7.x, all 8.x through 8.11.4, 9.0.0-9.12.3 and 10.0.0-10.6.0 (10.6.0 run as its release revision, branch_10_6 head 4ae946e5a9b9), plus main a9779ef3c193. [exec] the history probe (three claim inputs plus a string-valued control) fails 3 of 3 with the control passing on 6.2.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2, branch_10_6 and main (-ea and -da); the finder's JUnit fails 3 of 4 (control passes) on main (-ea and -da), branch_10_6, 10.5.2 and 9.12.3 (-da); the independent reproduction's own JUnit fails 5 of 8 (3 controls pass) on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check on main (-ea and -da), 10.5.2 and 9.12.3 (-da); the adjudication on main (-ea and -da); the registration check on main (-da, seed 5EED0384, 3 of 4). [read] the other releases are inferred affected because the check lines and the null-producing lines are unchanged in behaviour from 343f374b530 to main. Not fixed upstream: upstream main 645d4fe14a20 (author date 2026-10-28) still has '+ o.getClass()' at SimpleGeoJSONPolygonParser.java:90 and :208, and its newest commit on the file is 448c7d8e241 (author date 2026-02-11, an unrelated toArray cleanup). All runs on Linux aarch64 with JDK 25.0.3; on JDKs before 15 (unless enabled on 14) the exception type is the same but the NullPointerException has no helpful message.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-953.html",
   "repro": "repro/LFV-953/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-339",
   "priority": "low",
   "priority_rank": 983,
   "novelty": "new",
   "withheld": false,
   "area": "misc / IndexMergeTool command-line tool (option parsing)",
   "title": "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",
   "summary": "You run the IndexMergeTool command line with '--' before the paths, for example 'IndexMergeTool -- -merged src1 src2', and expect the parser's dedicated '--' branch (IndexMergeTool.java:61) to end option parsing, as the usual command-line convention says, so that '-merged' is taken as the target directory. Instead the branch compares the argument with == against the literal \"--\", which is never true for a command-line argument, so '--' falls through to the option switch and the tool stops with \"unrecognized option: '--'\" and exit code 2 without merging anything. The branch is also wrong when it does fire (only when Java code passes the literal \"--\" to main()): it stops without skipping the '--', so '--' becomes the merged-index path and the intended target is read as the first source index.",
   "impact_class": "minor",
   "introduced_commit": "93b83f635dffc782dc70174e5ea377ceab6a8174 (LUCENE-9206 'Improve IndexMergeTool defaults and options', by rmuir; a JIRA patch, no GitHub PR; issue apache/lucene#10246) [read]. Original code, not a regression: '--' never ended the options in any release",
   "introduced_date": "2020-02-05 (commit to master; first released in 9.0.0, tagged 2021-12-06)",
   "first_affected_version": "9.0.0 [exec]. The change went to master only (the author wrote on LUCENE-9206 'For this command-line tool I will push to master only'; the CHANGES entry is under 9.0.0; 93b83f635df is an ancestor of releases/lucene/9.0.0 and not of releases/lucene-solr/8.5.0 or 8.8.1). 8.x has no option parser (8.4.1 and 8.11.4 executed: IndexMergeTool.Options does not exist)",
   "affected_versions": "9.0.0 through 10.6.0 and main ea57360912ed; the one-test minimal repro fails on the 10.6.0 release jars (SHA-1 checked against Maven Central) with -ea and -da [exec]. [exec] main with -ea and -da (finder's JUnit 3 of 4 fail, the independent reproduction's JUnit 4 of 5 fail, parse check 4 of 4 fail, CLI exit 2), 10.5.2 and 9.12.3 with -ea and -da (JUnit), 10.0.0 (parse check), 9.0.0 (parse check and CLI exit 2; the JUnit repros do not compile against 9.0.0's test framework). [read] the line is present at all 33 release tags from 9.0.0 to 10.5.2, and IndexMergeTool.java has the same blob (0465f4e96b98) on upstream main e1c4184cb983, branch_10x, branch_10_6 and branch_9_12 (2026-10-26). Not affected: 8.x and older (no option parser). All runs on aarch64 with JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-339.html",
   "repro": "repro/LFV-339/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1035",
   "priority": "low",
   "priority_rank": 984,
   "novelty": "new",
   "withheld": false,
   "area": "luke / Search model paging session (SearchImpl.nextPage, SearchResults.of) behind the Luke Search tab",
   "title": "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",
   "summary": "You open an index in Luke, run a search that matches more than 1,000 documents with the default settings and click 'next' up to the last page; when that page is full (for example 2,000 hits), the shown total is a lower bound ('2000+'), so 'next' stays enabled, and you expect one more click to do nothing, as Search.nextPage's javadoc says ('search results, or empty if there are no more results'). Instead nextPage() returns a page with no hits whose offset is 0: the results table empties, the range reads '1 ~ 0' and 'previous' is disabled, so the earlier pages can only be reached by running the search again. The cause is that nextPage moves its page counter before it knows the page exists and checks for the end only when the total is exact, and SearchResults.of sets the offset only inside its loop over the hits.",
   "impact_class": "minor",
   "introduced_commit": "3a78c1999a87 (master) and 9915056cbc83 (branch_8x), both 'LUCENE-2562: Add Luke as a Lucene module' by Tomoko Uchida (mocobeta), author date 2019-04-10, committed directly (issue #3636, no apache/lucene PR) [read]. The lines were written before the import in the standalone Luke repository: DmitryKey/luke#163 'Upgrade lucene 8.0.0' (commit a98e23ba8698, mocobeta, 2019-03-21) changed nextPage's end check from 'totalHits == 0 || currentPage * pageSize >= totalHits' to an EQUAL_TO-only check when Lucene 8.0 made totals a lower bound past 1,000 hits (LUCENE-8060, not a defect itself), without handling an empty next page; every test that commit updated passes exactHitsCount=true [exec].",
   "introduced_date": "2019-04-10 (LUCENE-2562 import, 3a78c1999a87 / 9915056cbc83); the code was first written 2019-03-21 in the standalone Luke repository (a98e23ba8698, DmitryKey/luke#163)",
   "first_affected_version": "8.1.0 [exec] (the first Lucene release with the Luke module; 8.0.0 and earlier have no Luke module [exec])",
   "affected_versions": "[exec] fail with the finder's test (seed DEADBEEF): 8.1.0, 8.11.4, 9.0.0, all 20 releases 9.1.0-9.12.3, all 12 releases 10.0.0-10.5.2, and main 645d4fe14a20 with -ea and -da (re-run at the registration check 2026-10-29: fails 1 of 1 with -ea, seed 5EED1A01, and -da, seed 5EED1A02; the independent reproduction's test fails 1 of 1, seed 5EED1A03). [read] 8.1.1-8.8.1 contain the import commit by tag; 8.8.2-8.11.3 lie between the failing 8.1.0 and 8.11.4 with no known change to this code; branch_10x 657014b3c57 has the same paging code as main. 10.6.0 (released from branch_10_6 4ae946e5a9b) [exec]: the one-test minimal repro fails on the release jars (SHA-1 checked against Maven Central) with -ea and -da. Not affected: 8.0.0 and earlier (no Luke module); the standalone luke-swing-7.7.0 passes. Not fixed upstream: upstream main is still 645d4fe14a20 and the newest commit under lucene/luke/.../models/search is 30c6deb8b65c (2026-04-01, #15837, a refactor) [read]. All runs: JDK 25 on aarch64 Linux; 8.1.0 and 8.11.4 use the Luke jar of the official binary distribution (Lucene 8.x published no Luke Maven artifact), and 8.x/9.0.0 use a one-line test-import port.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1035.html",
   "repro": "repro/LFV-1035/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1036",
   "priority": "low",
   "priority_rank": 985,
   "novelty": "new",
   "withheld": false,
   "area": "luke / Search model, sorted search (SearchImpl.search) behind the Luke Search tab",
   "title": "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",
   "summary": "You open an index in Luke, pick a sort field in the Sort tab (Luke then ticks and greys out 'exact hits count') and run a search that matches more than 1,000 documents; you expect the exact total, as the javadoc of the Sort overload of Search.search promises ('if set to true, the exact total hits count is returned'). Instead Luke shows a lower bound such as '1001+ hits', and there is no way to get the exact count of a sorted search. The cause is that SearchImpl.search() passes exactHitsCount only to the unsorted collector; the sorted branch calls IndexSearcher.searchAfter(after, query, pageSize, sort), which counts exactly only up to 1,000 hits.",
   "impact_class": "minor",
   "introduced_commit": "Exposed by 99220677fe40 (main, LUCENE-9449 'Skip docs with _doc sort and \"after\"', apache/lucene-solr#1725, mayya-sharipova; migrated issue #10489) and its branch_8x backport 75421682100 (apache/lucene-solr#1856), first released in 8.7.0 [exec]. The core change is intended and documented (CHANGES 8.7.0, API Changes) and touched no Luke file. The defective Luke code is older: the sorted branch without the threshold came into Lucene with LUCENE-2562 'Add Luke as a Lucene module' (3a78c1999a87 main / 9915056cbc83 branch_8x, Tomoko Uchida (mocobeta), 2019-04-10; issue #3636) and was written in the standalone Luke's DmitryKey/luke#163 (2019-03-21), which added exactHitsCount, applied it only to the unsorted branch and made the Sort pane force it on [read].",
   "introduced_date": "2020-09-08 (99220677fe40, LUCENE-9449 on main); 2020-09-17 (backport 75421682100, first release 8.7.0); the Luke code dates from 2019-04-10 (LUCENE-2562 import) and 2019-03-21 (DmitryKey/luke#163)",
   "first_affected_version": "8.7.0 [exec] for the default case (an index not sorted by the sort field); on an index sorted by the sort field, early termination already gave a lower bound from Luke's first release 8.1.0 [exec]",
   "affected_versions": "[exec] fail with the finder's test: 8.7.0 (-ea, -da), 8.11.4, 9.0.0, 9.12.3 (-ea, -da), 10.5.2 (-ea, -da) and main 645d4fe14a20 (-ea, -da; re-run at the registration check 2026-10-29: fails 1 of 1 with -ea, seed 5EED5A01, and -da, seed 5EED5A02; the independent reproduction's test fails 1 of 1, seed 5EED5A03); pass on 8.6.3 (-ea, -da). Core-only bisects of the same searchAfter call (the cross-model review, the intended-behaviour check): exact on 8.1.0-8.6.3, lower bound from 8.7.0 on. [read] 8.8.x-8.10.x and the intermediate 9.x/10.x releases (the sorted branch is unchanged since 2019 and TopFieldCollector has flipped the relation since 8.7.0); branch_10x (657014b3c579) has the same sorted branch and the same 1,000-hit IndexSearcher.searchAfter. 10.6.0 (released from branch_10_6 4ae946e5a9b) [exec]: the one-test minimal repro fails on the release jars (SHA-1 checked against Maven Central) with -ea and -da. Not affected in the default case: 8.1.0-8.6.3. Not fixed upstream: main HEAD is still 645d4fe14a20 and the newest commit under lucene/luke/.../models/search is 30c6deb8b65c (2026-04-01, #15837, a refactor) [GitHub API, 2026-10-29]. All runs: JDK 25 on aarch64 Linux; 8.x use the Luke jar of the official binary distribution (Lucene 8.x published no Luke Maven artifact) and 8.x/9.0.0 a one-line test-import port.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1036.html",
   "repro": "repro/LFV-1036/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-264",
   "priority": "low",
   "priority_rank": 986,
   "novelty": "new",
   "withheld": false,
   "area": "facet / taxonomy (SearcherTaxonomyManager.refreshIfNeeded exception path)",
   "title": "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",
   "summary": "You use SearcherTaxonomyManager, and one refresh hits two I/O failures at once: reopening the taxonomy fails, and closing the index reader that was just reopened also fails. You expect maybeRefresh() to throw the taxonomy failure as an IOException, its documented contract, with the close failure attached as a suppressed exception. Instead it throws IllegalArgumentException('Self-suppression not permitted'), because the cleanup code calls t2.addSuppressed(t2) where t1.addSuppressed(t2) was meant, so the taxonomy failure is lost entirely and callers that catch IOException do not see it.",
   "impact_class": "wrong error",
   "introduced_commit": "4fba55c864298848a07c2971738947473484006e (master), 'LUCENE-8244: Do not leak open file descriptors in SearcherTaxonomyManager's refresh on exception', mikemccand, 2018-04-28; the same-day branch_7x backport 9f2eda7a1fc6d4cec70a8a76f3401a6bd53a48b1 is the commit that 7.4.0 contains. No pull request: the change went in as LUCENE-8244.patch on JIRA LUCENE-8244 (now #9291), and the attached patch already contains t2.addSuppressed(t2) [read]. A defect in the LUCENE-8244 fix itself: before it, the same path leaked the reopened index reader (the LUCENE-8244 bug) but did propagate the taxonomy failure",
   "introduced_date": "2018-04-28",
   "first_affected_version": "7.4.0 [exec] (tag 2018-06-18; its CHANGES.txt lists LUCENE-8244 under Bug Fixes); last unaffected release 7.3.1 [exec] (tagged 2018-05-06 from branch_7_3, which never received the backport; it reports the taxonomy failure but leaks the reopened reader, the pre-existing LUCENE-8244 bug)",
   "affected_versions": "every release from 7.4.0 through 10.5.2, 10.6.0 (by reading), and main ea57360912ed [read]; not fixed upstream. All runs used JDK 25; the deciding JDK behaviour (Throwable.addSuppressed(this) throws IllegalArgumentException) is specified since Java 7, so the 2018-era outcome follows from that contract but was not executed on Java 8",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-264.html",
   "repro": "repro/LFV-264/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-549",
   "priority": "low",
   "priority_rank": 987,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / spell: SpellChecker.indexDictionary (n-gram spell index build, failure cleanup)",
   "title": "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",
   "summary": "You build a spell index with SpellChecker.indexDictionary and the build throws, for example because the word-list file is not valid UTF-8, has a line longer than 32766 bytes, or its reader hits an I/O error; you fix the input and call indexDictionary or clearIndex again. You expect the retry to work, because the failed call should close or roll back the IndexWriter it opened. Instead indexDictionary closes its writer only on the success path, so the writer, which the caller cannot reach, keeps the spell index's write lock, and every later write to that index in the same JVM throws LockObtainFailedException 'Lock held by this virtual machine' until the JVM restarts.",
   "impact_class": "crash",
   "introduced_commit": "a379a6787596e22f5f41b8515f6053be59ae51e5 (svn trunk r659013, 2008-05-22, 'LUCENE-1152 Fix for calling indexDictionary after clearIndex call', patch by Naveen Belkale via Otis Gospodnetic; JIRA LUCENE-1152 / apache/lucene#2229, no PR, it predates GitHub) [exec]. That commit removed the force-unlock ('if (IndexReader.isLocked(spellIndex)) IndexReader.unlock(spellIndex);') that indexDictionary ran before opening its writer, so from then on a writer left open by a failed build blocks every later writer. The missing close or rollback on the failure path itself is older: since the first spellchecker commit 57cd0765650d0f73db37e090eaed4748fcd2fc82 (svn r151014, 2004-11-02, 'prelim checking of spellchecker, v1.1') indexDictionary reaches writer.close() only on success [read]. Later rewrites never closed the writer on failure: LUCENE-2108 ab447b6af06 (2009), LUCENE-2391 c26fd7564a5 (2011, today's try/finally, which releases only the searcher), LUCENE-3557 369a07a196e (2011), LUCENE-4246 8559eafd99e (2014) [read].",
   "introduced_date": "2008-05-22 (a379a678759, the lock-out); the missing close or rollback on the failure path dates from 2004-11-02 (57cd0765650)",
   "first_affected_version": "2.4.0 (tag 2008-10-08) [exec]; 2.3.2 (2008-05-06) and every earlier release with the spellchecker (1.9.1-2.3.2) are not affected [exec]: the writer also stays open there, but the next indexDictionary force-unlocks the index, so the retry works. In 2.4.0 and 2.4.1 System.gc() + runFinalization() still release the lock (IndexWriter.finalize); from 2.9.0 on (LUCENE-1715 removed the finalizer) the lock survives garbage collection, except 4.8.0 on the JDK 25 runtime used here (LUCENE-5612 had dropped the JVM-wide held-lock set; LUCENE-5738 restored it in 4.9.0) [exec]; the immediate retry fails in all of them. The immense-term trigger exists only from 4.8.0 (LUCENE-5472); in 4.7.2 and earlier such a word was skipped silently [exec]",
   "affected_versions": "Every release from 2.4.0 to 10.6.0, plus main ea57360912ed. [exec] a public-API main() history probe (one source per API era; scenarios: control, PlainTextDictionary over an InputStream that fails after one word, a 40000-character word, and for 1.9-2.4 a Dictionary whose iterator throws; then a rebuild with a good dictionary) reproduces on 22 releases: 2.4.0, 2.4.1, 2.9.0, 2.9.4, 3.0.3, 3.4.0, 3.5.0, 3.6.2, 4.0.0, 4.7.2, 4.8.0, 4.9.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0 and 10.5.2 (-ea; also -da on 9.12.3 and 10.5.2) and on main (-ea and -da), and passes on main with the fix shadowed; not affected on 1.9.1, 2.0.0, 2.1.0, 2.2.0, 2.3.0, 2.3.1 and 2.3.2 (retry works through the force-unlock). The finder's JUnit fails on main (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's on main, 10.5.2 and 9.12.3 (-ea and -da each); the intended-behaviour check's (non-UTF-8 word list) on main (-ea and -da), 10.5.2 and 9.12.3; a cross-model review re-ran the finder's JUnit on main (-ea and -da) and 10.5.2 (seed 1234ABCD); the JUnit tests need the 9.x+ test framework, so 8.x ran only through the main() probe. [read] a scan of the 144 release tags that ship SpellChecker.java finds no 'unlock(' from 2.4.0 on and no 'rollback' in any tag, and in every tag from 3.1 on the only finally in indexDictionary releases the searcher; upstream origin/main a9779ef3c19, branch_10x and branch_10_6 have the same indexDictionary as ea57360912ed and 10.5.2 (javadoc markup only differs; 2026-10-26). The one-test minimal repro fails on the 10.6.0 release jars (SHA-1 checked against Maven Central) with -ea and -da, and through gradle on main 645d4fe14a20 with assertions on and off (2026-11-01). Not executed: the other point releases (same structure by the tag scan), x86, other lock factories.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-549.html",
   "repro": "repro/LFV-549/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-507",
   "priority": "low",
   "priority_rank": 988,
   "novelty": "new",
   "withheld": false,
   "area": "monitor / persistent query index (WritableQueryIndex construction, failure cleanup)",
   "title": "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",
   "summary": "You open a persistent Monitor (MonitorConfiguration.setIndexPath) and the open fails after the query index has built its IndexWriter, for example because a stored query no longer parses with the current parser (IllegalStateException 'Couldn't parse some queries from the index'), because no serializer was given for a non-empty index, or because of an I/O error while the index opens. You expect the failed constructor to release what it acquired, as IndexWriter's own constructor does for its write lock, so that you can fix the parser or the configuration and open the index again. Instead the IndexWriter, its SearcherManager and the write lock stay open with no object left to close them, so every later writable Monitor on that path in the same JVM fails with LockObtainFailedException 'Lock held by this virtual machine', even with a correct serializer, until the JVM restarts.",
   "impact_class": "crash",
   "introduced_commit": "251dbe7cea8126cb7ecadc921ba444c63d06c618 (main, 2019-06-13, 'LUCENE-8766: Add monitor subproject', by GitHub romseygeek), with the branch_8x twin b8773d13ad8e249a045862249bf476c30a444461 (same message, author and date); review PR apache/lucene-solr#648, closed on GitHub because the code was committed directly. Its QueryIndex constructor (QueryIndex.java:90-97) built the writer and the SearcherManager and then called populateQueryCache, which held both IllegalStateExceptions, with no try/finally. LUCENE-10422 / #679 (be991789564 on main, first released in 10.0.0; 72cf36a2b8d on branch_9x, first released in 9.2.0) moved the constructor into WritableQueryIndex and added the purge-executor setup after populateQueryCache, keeping the missing cleanup (git blame on main points at be991789564 for the writer and SearcherManager lines only because that refactor rewrote them). [read]. Latent since the API was added, not a regression.",
   "introduced_date": "2019-06-13 (251dbe7cea8 on main and b8773d13ad8 on branch_8x)",
   "first_affected_version": "8.2.0 [exec] (the first lucene-monitor release); there is no unaffected earlier release: 8.1.1 has no lucene/monitor module and lucene-monitor 8.1.1 is not on Maven Central (HTTP 404)",
   "affected_versions": "Every release that ships lucene-monitor, 8.2.0 to 10.6.0, plus main ea57360912ed. [exec] a framework-free public-API probe (a control plus a parse-failure and a null-serializer scenario, System.gc() before each retry) is affected, with the control passing, on 8.2.0, 8.11.4, 9.0.0, 9.1.0, 9.2.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da), and passes on main with the finder's fix shadowed; the finder's JUnit fails on main (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails on main (-ea and -da), 10.5.2 and 9.12.3, and its main() variant on main and 8.11.4; the intended-behaviour check's JUnit, including the I/O-error trigger, fails on main (-ea and -da) and 10.5.2; the one-test minimal repro fails on the 10.6.0 release jars (SHA-1 checked against Maven Central) with -ea and -da (2026-11-01). [read] the constructor body has the same shape at every release tag 8.2.0-8.8.1 and 9.0.0-10.5.2 in the history clone (the 8.9-8.11 tags are absent there; 8.11.4 was executed); upstream main and branch_10x are unchanged on 2026-10-26. Not executed: x86; the I/O-error and purge-frequency triggers on older releases (from 8.2.0 to 9.1.0 the purge executor was created in Monitor.<init> after the query index was built, so that path also leaks the writer there, by code reading).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-507.html",
   "repro": "repro/LFV-507/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-555",
   "priority": "low",
   "priority_rank": 989,
   "novelty": "new",
   "withheld": false,
   "area": "facet / taxonomy writer: DirectoryTaxonomyWriter.close() (failure cleanup)",
   "title": "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)",
   "summary": "You add categories to a DirectoryTaxonomyWriter, a commit fails with an I/O error (for example a full disk while the new segment is written), and you then call close(), whose javadoc says it 'Frees used resources as well as closes the underlying IndexWriter'. You expect close() to release the writer's resources even when it throws, as IndexWriter.close() has done since LUCENE-4246. Instead close() is 'commit(); indexWriter.close(); doClose();' with no try/finally, so it throws AlreadyClosedException from its own commit() on every call and never closes its internal near-real-time reader, whose segment file stays open; when the error is an fsync inside close(), the internal IndexWriter and the taxonomy's write lock also stay held until close() is retried or rollback() is called.",
   "impact_class": "minor",
   "introduced_commit": "No single commit [read]. The DirectoryTaxonomyWriter shape (close() commits before any cleanup, with no try/finally) dates from 242092c929d (branch_3x 0c300ae6113), LUCENE-3794 (= #4867), 2012-02-16, with a conditional form since 0780806efe6 (LUCENE-3573, 2011-11-16). It became this bug when IndexWriter changed underneath it: c064aaa4850 (branch_5x; trunk de4c6513bcb), LUCENE-5987 (= #7049) 'IndexWriter forcefully closes itself on hitting aborting exception', enables the lead (tragic-commit) variant; 2cfcdccdd29 (branch_4x, 'IW.close really closes the IndexWriter, even on exception', labelled LUCENE-5871 = #6933, the 4.x port of LUCENE-4246 = #5316; trunk 8559eafd99e, which also edited DTW.close() mechanically and left commit() outside a try/finally) is where the write-lock variant starts to diverge from IndexWriter.close()'s own contract. No PR (svn era); the #5316, #7049 and #6933 threads never mention the taxonomy writer or the facet module",
   "introduced_date": "2014-12-05 (LUCENE-5987: lead variant); 2014-08-14 (2cfcdccdd29: write-lock variant); the DirectoryTaxonomyWriter code shape 2012-02-16 (LUCENE-3794)",
   "first_affected_version": "5.0.0 for the lead (tragic-commit) variant [exec]; 4.10.0 for the secondary write-lock variant, counted from when IndexWriter.close() itself started to always close [exec]",
   "affected_versions": "Both variants on every release from 5.0.0 to 10.6.0 (10.6.0 by reading) and on main ea57360912ed [exec]; close() is 'commit(); indexWriter.close(); doClose();' at every release tag from 5.0.0 on [read]. 4.10.0-4.10.4: write-lock variant only [exec]. 3.5.0-4.9.1: not counted (the lock is kept after a failed close() commit, as IndexWriter.close() then documented; the lead variant does not occur) [exec]. Upstream main a9779ef3c19 (2026-10-26), branch_10x 1309534296e and branch_10_6 2763db11b0a have the same close() [read]. Not executed: OutOfMemoryError paths, and the 4.10.1-4.10.4 tragic-event paths beyond file-level faults. Executed only on aarch64 Linux with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-555.html",
   "repro": "repro/LFV-555/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-558",
   "priority": "low",
   "priority_rank": 990,
   "novelty": "new",
   "withheld": false,
   "area": "facet / taxonomy writer (DirectoryTaxonomyWriter construction, failure cleanup)",
   "title": "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",
   "summary": "You open a taxonomy with new DirectoryTaxonomyWriter(dir) and the constructor throws an IOException, because a file read failed after it had already opened its internal IndexWriter (while reading the latest commit of an existing taxonomy, or while opening a reader to add the root category of a new one); once the error has passed you try again. You expect the retry to work, because a constructor that throws hands the caller nothing to close and so must release what it acquired, as IndexWriter's own constructor does. Instead the constructor has no cleanup after openIndexWriter, so the unreachable IndexWriter keeps the taxonomy's write lock and every later DirectoryTaxonomyWriter on that directory in the same JVM fails with LockObtainFailedException 'Lock held by this virtual machine'.",
   "impact_class": "crash",
   "introduced_commit": "d4e1a420d525ecf022ee8c3594f3683005c5cc85 (branch_3x svn r1141060, 2011-06-29, 'LUCENE-3079: add faceting module', GitHub apache/lucene#4152; no PR, it predates GitHub; trunk port 4291f52c70d7b6324456663cc3a7ec0df855ccb7 the same day) [read]. The existing-taxonomy path, A, came with LUCENE-4532 (branch_4x b9bfc1e6b768f2ee4ea4ede5a9741d1e0d668232, trunk 2e896c4af6d9b8adc18bd9200fc2a23ac82f7f0f, 2012-11-07, GitHub apache/lucene#5598), which moved the commit-data read from before openIndexWriter to after it, so that it runs under the lock; that issue does not discuss a failing read [read]. Not bisected at commit level; release brackets executed. No version of the constructor ever had a try block (code-identity check over 126 release tags, 3.4.0 to 10.5.2).",
   "introduced_date": "2011-06-29 (d4e1a420d525, path B, new taxonomy); 2012-11-07 (LUCENE-4532, path A, existing taxonomy)",
   "first_affected_version": "3.4.0 (2011-09-14, the first release with the class) [exec]: path B (new taxonomy) leaks there. Path A (existing taxonomy) leaks from 4.1.0 (2013-01-21) [exec]; 3.4.0 and 3.5.0 read no file after the writer opens, and 3.6.2 and 4.0.0 read the commit before opening the writer, so path A does not leak there [exec]. No earlier release has the API: 3.3 has no facet module.",
   "affected_versions": "Every release from 3.4.0 to 10.6.0 (10.6.0 by reading), plus main ea57360912ed. [exec] A public-API main() history probe (FSDirectory with the default lock factory, one IOException injected at Directory.openInput, selected by call stack; scenario A existing taxonomy, scenario B new taxonomy, control C a fault inside IndexWriter's own constructor, control D no fault) reproduces on 20 releases: 3.4.0, 3.5.0, 3.6.2, 4.0.0 (path B only), 4.1.0, 4.5.1, 4.6.0, 4.10.4, 5.0.0, 5.5.5, 6.0.0, 6.6.6, 7.0.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0 and 10.5.2, and on main (-ea; also -da on 3.4.0, 4.0.0, 4.1.0, 9.12.3, 10.5.2 and main); both controls pass in every run. The finder's JUnit fails on main (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check's plain-FSDirectory test on main (-da), 10.5.2 and 9.12.3; a cross-model review's plain-FSDirectory main() check on main (-ea and -da), 10.5.2 and 9.12.3. The JUnit tests need the 9.x+ test framework, so 9.0.0 and older ran only through the main() probe. [read] A code-identity scan of the 126 release tags from 3.4.0 to 10.5.2 in the history clone finds no try block in the constructor in any tag, path B in all 126 and path A in the 120 tags from 4.1.0 on (the 8.9.0-8.11.x tags are missing from the clone; 8.11.4 was executed). Upstream main a95c754ee003 (2026-10-26), branch_10x and branch_10_6 have the same file blob as the tested copy.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-558.html",
   "repro": "repro/LFV-558/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-554",
   "priority": "low",
   "priority_rank": 991,
   "novelty": "new",
   "withheld": false,
   "area": "misc / index tools (MultiPassIndexSplitter.split, failure cleanup)",
   "title": "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",
   "summary": "You split an index with MultiPassIndexSplitter.split, the split throws while it writes one of the output parts (for example the disk fills up, a file of the source index is corrupted, or the source index was created by the previous major version), and you then retry the split or open an IndexWriter on that output directory in the same JVM. You expect this to work once the cause is gone, because the failed split should close the IndexWriter it opened on the output. Instead split() calls close() only after addIndexes succeeds, so the writer, which the caller cannot reach, keeps the output's write lock, and every later IndexWriter or split into that directory throws LockObtainFailedException 'Lock held by this virtual machine' until the JVM restarts.",
   "impact_class": "minor",
   "introduced_commit": "7d0d4ecc44c6acb60ac3cc0dbf9dc2c18d7497de (svn r824798, 2009-10-13, 'LUCENE-1959 Add MultiPassIndexSplitter.', by JIRA/GitHub sigram; JIRA LUCENE-1959 'Index Splitter', migrated as apache/lucene#3034, fix version 3.0; pre-GitHub, no PR) [read]. Present since the class was created; not a regression [exec].",
   "introduced_date": "2009-10-13",
   "first_affected_version": "3.0.0 (tag 2009-11-25, the first release with the class) [exec]; not affected: 2.9.x and earlier, where the class does not exist [exec]",
   "affected_versions": "Every release that ships MultiPassIndexSplitter, 3.0.0 through 10.6.0, plus main ea57360912ed. [exec] public-API main() history ports (one source per API era: an output directory that throws IOException from createOutput like a full disk, then a new IndexWriter on that output, with a caller-owned-writer control) reproduce on 3.0.0, 3.6.2, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main, and the control passes in each; the finder's JUnit fails on main (-ea and -da), 10.5.2, 10.0.0 and 9.12.3; the independent reproduction's main() repro on main (-ea and -da), 10.5.2, 9.12.3 and 9.0.0; the intended-behaviour check's previous-major JUnit on main (-ea and -da), 10.5.2 and 9.12.3; a cross-model review's disk-full variant on main and 10.5.2. The symptom reads 'Lock obtain timed out' up to 5.0.0 and 'Lock held by this virtual machine' from 5.5.5 on. The one-test minimal repro fails on the 10.6.0 release jars (SHA-1 checked against Maven Central) with -ea and -da (2026-11-01). [read] every other release tag in the history clone (3.0.1, 3.1-3.6.1, 4.0.0-4.10.3, 5.1.0-5.5.4, 6.0.0-6.6.5, 7.0.0-7.7.2, 8.0.0-8.8.1, 9.1.0-9.12.2, 10.1.0-10.5.1) has the same unprotected block; 3.0.2, 3.0.3 and 8.8.2-8.11.3 are neither executed nor in the clone. Whether garbage collection releases the lock was executed only on main and 10.5.2 (it does not). Not fixed upstream: main ffa9d816eeb4 and branch_10x (2026-10-26) still have the block.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-554.html",
   "repro": "repro/LFV-554/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-840",
   "priority": "low",
   "priority_rank": 992,
   "novelty": "new",
   "withheld": false,
   "area": "index / deletion policies (PersistentSnapshotDeletionPolicy save-file failure handling)",
   "title": "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",
   "summary": "You call PersistentSnapshotDeletionPolicy.snapshot() (or release()), fsync of the new save file snapshots_N fails once, the call throws and the policy undoes the change in memory; you expect the next call, with no fault, to work. Instead persist() has left the complete snapshots_N in the directory (its delete-on-failure block covers only creating and writing the file, not the sync) and has not advanced its generation, so the next snapshot() or release() writes the same name and fails with FileAlreadyExistsException; that call's cleanup deletes the leftover, and the call after it works. Secondary, contract open: a policy re-opened before that next call adopts the leftover, so a snapshot() that threw is in effect and a release() that threw has taken effect.",
   "impact_class": "wrong error",
   "introduced_commit": "8c6e38ee605494627a2f29f2de8ca3ba09bef342 (trunk, svn r1479394) and its branch_4x backport 1edbfb98ee8 (svn r1479395), 'LUCENE-4976: add missing sync / delete old save files' by Michael McCandless (svn-era commit, no pull request; issue now apache/lucene#6040, whose comments never discuss a sync failure) [read]. The headline symptom needs Lucene's write-once createOutput, LUCENE-6171 (a893c645952 / 45d2d2e7d34, #7233) and LUCENE-7345 (07920c4fdaa, #8399), both first released in 6.2.0 and intended, not defects [exec]. #589 (74698994a9b, 2022-01-10, 9.1.0) moved createOutput into the try, so from 9.1.0 the failing retry deletes the leftover and the third call works",
   "introduced_date": "2013-05-05 (author date of 8c6e38ee605; first released in 4.4.0, 2013-07)",
   "first_affected_version": "6.2.0 [exec] for the headline (the next fault-free call fails; 6.1.0 passes because its createOutput overwrote the leftover); the leftover file and the secondary re-load effect exist from 4.4.0 [exec] (4.3.1, the last release before LUCENE-4976, is not affected)",
   "affected_versions": "Headline: every release 6.2.0-10.6.0 and main a9779ef3c193 [exec]; the releases in between by a tag scan of the history clone (the sync is outside the cleanup in every tag 4.4.0-10.5.2 and createOutput is write-once in every tag from 6.2.0; 8.9-8.11.x are not tagged there, 8.11.4 was executed from release jars) [read]. 6.2.0-9.0.0: every later call fails until the policy is re-created (third call executed, later calls by reading); 9.1.0 and later: one extra failed call, then the policy recovers by itself. 4.4.0-6.1.0: headline not affected [exec], but a re-loaded policy adopts the leftover. Not fixed upstream: upstream main 20ced71c1e6e, branch_10x, branch_10_6 and branch_10_5 have no commit on the file after #14913 (2025-07-14) and open PR #16482 leaves persist() unchanged [read], so the released 10.6.0 has it too. All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-840.html",
   "repro": "repro/LFV-840/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-446",
   "priority": "low",
   "priority_rank": 993,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter merge-reader acquisition (ReadersAndUpdates.getReaderForMerge)",
   "title": "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",
   "summary": "You update a doc-values field (or use soft deletes) and open NRT readers from your IndexWriter, then delete a document, and a merge (a merge-on-commit, a merge-on-refresh, or an ordinary or forced merge) has to open a fresh copy of that segment's pooled reader with the new deletions, and opening it fails with an IOException. You expect the merge to fail cleanly and IndexWriter to give back every reader reference it took, so that once the writer is closed no file of the index is still open. Instead ReadersAndUpdates.getReaderForMerge never releases the reference it took on the pooled reader, so that segment's compound file and doc-values update files stay open after IndexWriter.close, even when the failure was not tragic and the writer went on to commit and close normally.",
   "impact_class": "minor",
   "introduced_commit": "1120e46961b242104410190b70d1f4e4e57d1a40 (trunk, svn r1523461) and its branch_4x backport 49684b82701b4196c9ae029b0c4d45fd6efdcb4a (svn r1537832, first released in 4.6.0), LUCENE-5189 'Numeric DocValues Updates' = apache/lucene#6253 (SVN-era patches on JIRA, no pull request; author shaie): it turned the core-sharing SegmentReader constructor used for the merge-reader refresh from a constructor that did no I/O and declared no exception into one that reads the field-infos generation file and sets up the doc-values update producers (throws IOException), while the caller kept taking the pooled reference before it and releasing it only after it returned [read]. The code moved into ReadersAndUpdates.getReaderForMerge in 7.0.0 (LUCENE-7868, 58105a203a1) and into createNewReaderWithLatestLiveDocs in 7.4.0 (LUCENE-8246, e99a19755c7) and kept the same order both times [read]",
   "introduced_date": "2013-09-15 (trunk commit 1120e46961b2, svn r1523461); 2013-11-01 (branch_4x backport 49684b82701b, svn r1537832)",
   "first_affected_version": "4.6.0 [exec]",
   "affected_versions": "every release from 4.6.0 through 10.6.0, and main ea57360912ed. [exec] 4.6.0, 4.10.4, 5.5.5, 6.6.6, 7.0.0, 7.7.3, 8.5.2, 8.6.0 (merge-on-commit), 8.11.4 (forced merge and merge-on-commit), 9.12.3, 10.5.2 and main leak (main also with -da), and the one-test minimal repro fails on the 10.6.0 release jars (SHA-1 checked against Maven Central, -ea, 2026-11-01); 4.5.1 does not (no doc-values update API, the refresh opened no file). [read] a tag scan of the release tags 4.6.0-10.5.2 in the history clone finds the same unguarded order in every one (the clone lacks the 8.8.2-8.11.x tags; 8.11.4 was executed). Trigger scope by version: 4.6.0-4.10.4 a failed forced merge is not tragic [exec]; by 5.5.5 it is tragic [exec]; 8.6.0 adds the non-tragic merge-on-commit path [exec] and 8.7.0 merge-on-getReader through the same code [read]. Not fixed upstream: main 49483e82b357, branch_10x and branch_10_5 have the same order [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-446.html",
   "repro": "repro/LFV-446/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1065",
   "priority": "low",
   "priority_rank": 994,
   "novelty": "new",
   "withheld": false,
   "area": "core / IndexWriter constructor failure path (reader-commit branch: IndexWriterConfig#setIndexCommit(reader.getIndexCommit()), ReaderPool pre-enrollment; LUCENE-6524, LUCENE-8260)",
   "title": "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",
   "summary": "You open a DirectoryReader, pass its getIndexCommit() to IndexWriterConfig#setIndexCommit, and the IndexWriter constructor then fails, here because your IndexDeletionPolicy's onInit throws an IOException; you expect the exception and nothing left behind once you close the reader, as the constructor's own catch intends (it releases the write lock and, since #15675, the merge scheduler) and as the same failure with a commit from DirectoryReader.listCommits behaves. Instead the constructor has already built the ReaderPool, which pre-enrolled one SegmentReader per segment, each holding a reference on the reader's segment core, and its catch never closes the pool, so after reader.close() MockDirectoryWrapper still reports the segment's compound file open.",
   "impact_class": "minor",
   "introduced_commit": "8975692953713923bd1cc67766cf92565183c2b8 (master, 'LUCENE-8260: Extract ReaderPool from IndexWriter'; LUCENE-8260 = #9307, JIRA era, no apache/lucene PR) and its branch_7x backport 1bf56037d17bc4addd63dcca4a931647130168c6, which reached 7.4.0 [exec]. A regression for the claimed trigger, a side effect of the refactor: it moved the pre-enroll loop into the new ReaderPool constructor, which IndexWriter calls before it creates the IndexFileDeleter, while the constructor's failure handler kept releasing only the write lock; the commit message describes only the extraction. Older leg, not the claimed repro: a failure inside the pre-enroll loop itself (for example an I/O error while a later segment's pooled reader reads its field infos) leaks the readers already pooled since the reader-commit branch was added by LUCENE-6524 (#7582; 2d0ac9bb7f2 trunk, 7ab3ca7d608 branch_5x, 2015-06-28, first released in 5.3.0) [exec].",
   "introduced_date": "2018-04-23 (author date 2018-04-23T10:29:10+02:00 of 8975692953 and of the backport 1bf56037d17); first release 7.4.0 tagged 2018-06-22; older in-loop leg 2015-06-28 (LUCENE-6524), first release 5.3.0",
   "first_affected_version": "7.4.0 [exec] (-ea and -da; the LUCENE-8260 backport); 7.3.1 passes [exec] because the pre-enroll ran after the IndexFileDeleter there; 5.2.1 and older have no reader-commit branch. The older in-loop leg is in every release from 5.3.0 [exec]",
   "affected_versions": "every release from 7.4.0 through 10.6.0 and main 645d4fe14a20; never fixed. [exec] the minimal JUnit TestIndexWriterFromReaderFailedOpen fails on main (-ea and -da; re-run 2026-11-01, seed DEADBEEF, 'MockDirectoryWrapper: cannot close: there are still 1 open files: {_0.cfs=1}'), on the released 10.6.0 jars (4ae946e5a9b, -ea and -da), 10.5.2 (-da) and 9.12.3 (-ea and -da); a port that differs only in the LuceneTestCase import fails on 9.0.0, 8.11.4 (-da), 7.4.0 and the branch_7x backport 1bf56037d17 (-ea and -da), and passes on 7.3.1 and the backport's parent 4cd0a0aae32 (-ea and -da); the independent reproduction's independent test fails on main (-ea, -da), 10.5.2 (-ea, -da) and 9.12.3 (-da). [read] in every local release tag from 7.4.0 to 8.8.1 and 9.0.0 to 10.6.0 the constructor builds the ReaderPool before the IndexFileDeleter and its failure handler (finally !success up to 10.6.0, catch on main) never names the pool; 8.8.2-8.11.4 by branch ancestry plus the executed 8.11.4. Upstream main f815e679bf6 (2026-11-01), branch_11x and branch_10_6 are unchanged at the fix sites. Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1065.html",
   "repro": "repro/LFV-1065/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-495",
   "priority": "low",
   "priority_rank": 995,
   "novelty": "new",
   "withheld": false,
   "area": "core / index reader reopen (FilterDirectoryReader.wrapDirectoryReader on every doOpenIfChanged path; SoftDeletesDirectoryReaderWrapper as the stock trigger)",
   "title": "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",
   "summary": "You reopen a FilterDirectoryReader, for example a SoftDeletesDirectoryReaderWrapper, with DirectoryReader.openIfChanged (directly or through SearcherManager or ReaderManager), and the call fails after the inner reader was reopened, while the wrapper wraps it: for example an I/O error while the soft-deletes wrapper reads the new segment's soft-deletes doc values. You expect the failed call to release what it opened, so that closing your old reader, the only one you hold ('The provided reader is not closed (you are responsible for doing so); if a new reader is returned you also must eventually close it'), frees every segment reader and file. Instead FilterDirectoryReader.wrapDirectoryReader neither returns nor closes the inner reader it was just given, so that reader keeps an extra reference on every shared segment (refCount 2 after the failure, still 1 after you close the old reader) and the new segments' files stay open.",
   "impact_class": "minor",
   "introduced_commit": "1923a0dd6a027c5a054d248dcc46a047bca43765 (trunk, svn r1465072, 'LUCENE-4902: Add FilterDirectoryReader', by romseygeek; CHANGES also credits jpountz and uschindler) and its branch_4x copy 33742fc0194fef8a6a91fffb4adb44f9ec4ef78c (r1465075); JIRA LUCENE-4902, mirrored as apache/lucene#5967; no PR, it predates the GitHub workflow [read]. Not a regression. The stock trigger arrived later with SoftDeletesDirectoryReaderWrapper (LUCENE-8237, ed62b990d8b, first released in 7.4.0), whose wrap step reads doc values and turns an IOException into UncheckedIOException",
   "introduced_date": "2013-04-05 (1923a0dd6a02 on trunk and 33742fc0194 on branch_4x, same day; 4.3.0 tagged 2013-05-06); stock SoftDeletesDirectoryReaderWrapper trigger from 2018-04-09 (LUCENE-8237)",
   "first_affected_version": "4.3.0 [exec] (the first release with FilterDirectoryReader: an application SubReaderWrapper that throws on reopen leaks, the no-fault control passes, and the fix shadowed into 4.3.0 removes the leak); 4.2.1 lacks the class [exec]; the stock SoftDeletesDirectoryReaderWrapper read-error trigger from 7.4.0 [exec] (7.3.1 lacks that class [exec])",
   "affected_versions": "every release from 4.3.0 to 10.6.0 and main ea57360912ed; never fixed. [exec] era-adapted history instruments (each with a no-fault control that must share segment _0 and then release it; every control passed): application-wrapper trigger leaks on 4.3.0, 4.10.4, 5.0.0, 6.6.6, 7.0.0, 7.3.1, 7.4.0, 8.11.4, 9.12.3, 10.5.2 and main; SoftDeletesDirectoryReaderWrapper read-error trigger leaks on 7.4.0, 8.11.4, 9.12.3, 10.5.2 and main (-ea and -da); main with the fix shadowed does not leak; the finder's JUnit fails 2 of 2 on main (-ea, -da), 10.5.2 and 9.12.3; the independent reproduction's fails 3 of 3 on main (-ea, -da), 10.5.2 and 9.12.3; the intended-behaviour check's fails on main and 10.5.2; the one-test minimal repro fails on the 10.6.0 release jars with -ea and -da (2026-11-01). [read] all 117 tagged releases from 4.3.0 in the history clone have the identical line 'return in == null ? null : doWrapDirectoryReader(in);' with no cleanup (8.8.2 to 8.11.4 are not tagged there; 8.11.4 executed). Not fixed upstream: main a9779ef3c193 unchanged (read 2026-10-26); no open PR changes wrapDirectoryReader. All runs: JDK 25, SHA-1-verified release jars, aarch64 Linux",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-495.html",
   "repro": "repro/LFV-495/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1061",
   "priority": "low",
   "priority_rank": 996,
   "novelty": "new",
   "withheld": false,
   "area": "core / index reader open (StandardDirectoryReader.createSegmentReaders, executor branch behind the ExecutorService overloads of DirectoryReader.open and openIfChanged, #15428)",
   "title": "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",
   "summary": "You call DirectoryReader.open(directory, executor), or openIfChanged with an executor, and the executor accepts the task for one segment but rejects the submit for the next one, as a saturated bounded pool does; you expect the RejectedExecutionException and nothing left behind, as the method's own cleanup comment intends, as the sequential path does and as upstream's rejecting-executor test requires. Instead the exception leaves the submit loop before any future is collected, so the reader the accepted task built is never decRef'd: on a two-segment index, MockDirectoryWrapper then refuses to close because the files of the accepted segment are still open.",
   "impact_class": "minor",
   "introduced_commit": "c5a4d07e5540d0c8adce0af390275c8fd731b52a (branch_10x backport, apache/lucene#15445, the commit that reached the releases) of 7d4e22454b53485a44403ac28c79cd4e5166d487 (main, 'Adding support for passing an ExecutorService into DirectoryReader.open() to enable concurrent segment reader initialization (#15428)', fixes #15387) [read]. New code that came with the API, not a regression: the unguarded submit loop and the collect loop that treats InterruptedException like a task failure were already in the PR's first commit 40de473462f (2025-11-13); openIfChanged started sharing the helper in d62b706e31d (2025-11-19), same PR.",
   "introduced_date": "2025-11-21 (author date of 7d4e22454b5 on main); backport author date 2025-11-23; first release 10.4.0 (release commit 2026-02-20, tag 2026-02-25)",
   "first_affected_version": "10.4.0 [exec] (first release with the ExecutorService overloads); 10.3.2 and every 9.x release lack DirectoryReader.open(Directory, ExecutorService) [exec]",
   "affected_versions": "10.4.0, 10.5.0, 10.5.1, 10.5.2, 10.6.0 and main 645d4fe14a20; never fixed. [exec] the minimal JUnit TestExecutorOpenRejectedSubmitLeak fails on main (-ea and -da; re-run at the registration check 2026-10-30, seed DEADBEEF, 'there are still 4 open files: {_1_MockRandom_0.doc=1, _1_MockRandom_0.tio=1, _1.fdx=1, _1.fdt=1}'), on the 10.6.0 release jars (4ae946e5a9b, -da and -ea), on 10.5.2 (-da; -ea and -da again on 2026-11-01), on 10.5.1 and 10.5.0 (-da, 2026-11-01) and on 10.4.0 (-da and -ea), and passes on main with the fix shadowed; the independent reproduction's own test fails on main (-ea, -da), 10.6.0, 10.5.2 and 10.4.0 (-da); a core-only main() port fails on 10.4.0, 10.5.2, 10.6.0 and main and passes on main with the fix shadowed; 10.3.2 and 9.12.3 do not compile (API absent). [read] 10.5.0 and 10.5.1: createSegmentReaders is textually identical and the backport is an ancestor of both tags. Upstream main 716d6f216f5 (2026-10-29) and branch_10_6 have no commit to StandardDirectoryReader.java after 2026-02-11 (author date) and none ever changed the executor branch. Not affected in any version: the overloads without an executor (sequential branch). Not new in 10.6 (present since 10.4.0).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1061.html",
   "repro": "repro/LFV-1061/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1059",
   "priority": "low",
   "priority_rank": 997,
   "novelty": "new",
   "withheld": false,
   "area": "core / index reader reopen (StandardDirectoryReader reopen factory behind every non-NRT openIfChanged, with a leaf sorter, LUCENE-9507)",
   "title": "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",
   "summary": "You open a DirectoryReader with a leaf sorter and later call DirectoryReader.openIfChanged; if the sorter throws while the new reader sorts its leaves, you expect only that exception, because the javadoc makes you responsible just for the old reader and the initial open releases its readers in exactly this case. Instead the reopen factory has already taken a reference on each reused segment reader and opened the new ones, and it builds the new reader with no try/catch, so after the failed call the shared segment reader's refCount is 2 instead of 1 (1 instead of 0 after you close the old reader) and the new segment's reader is never closed.",
   "impact_class": "minor",
   "introduced_commit": "48715fe898bf0a900e3e6b681882ecb1b6d8e1b1 (main, 'LUCENE-9507 Custom order for leaves in IndexReader and IndexWriter (#32)'; apache/lucene#32, tracker LUCENE-9507 = #10546) and its branch_8x backport 1cfd0df4e7bb6180b67abb30bd92390bc729ec3f (apache/lucene-solr#2473) [read]. The commit put the application's leaf sorter (Arrays.sort in the BaseCompositeReader constructor) inside the constructor call that the reopen factory never guarded; the initial open already had a try/catch (LUCENE-6299, 2015) and the NRT open its own handler. Not a regression: the 2025-11 refactor (#15428 on main, #15445 backport, first released in 10.4.0) kept the unguarded call.",
   "introduced_date": "2021-03-26 (author date of 48715fe898bf on main); branch_8x backport 2021-03-30; first release 8.9.0 tagged 2021-06-16",
   "first_affected_version": "8.9.0 [exec] (first release with the leaf sorter, through the branch_8x backport: the core-only port leaks); 8.8.2 lacks DirectoryReader.open(Directory, Comparator) [exec]; first 9.x release 9.0.0 [exec]",
   "affected_versions": "every release from 8.9.0 through 10.6.0 and main 645d4fe14a20; never fixed. [exec] the minimal JUnit TestReopenSorterFailureRefCount fails on main (-ea and -da; re-run at the registration check 2026-10-30, seed DEADBEEF, 'expected:<1> but was:<2>'), on the 10.6.0 release jars (4ae946e5a9b, -da), 10.5.2, 9.12.3 and 9.1.0, and passes on main with the fix shadowed; the finder's JUnit fails on main (-ea, -da), 10.6.0 (-ea, -da), 10.5.2, 10.4.0, 10.3.2, 10.0.0, 9.12.3 and 9.1.0; a core-only main() port fails on 8.9.0, 8.10.0, 8.10.1, 8.11.0-8.11.4, 9.0.0, 9.1.0, 10.3.2, 10.4.0, 10.6.0 and main (-ea, -da) and passes on main with the fix shadowed. [read] the reopen factory's final constructor call is unguarded in all 33 9.x/10.x release tags. Upstream main 716d6f216f5 (2026-10-29) and branch_10_6 have no commit to StandardDirectoryReader.java after 2026-02-11 or to BaseCompositeReader.java after 2025-07-30 (author dates). Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1059.html",
   "repro": "repro/LFV-1059/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1067",
   "priority": "low",
   "priority_rank": 998,
   "novelty": "new",
   "withheld": false,
   "area": "core / NRT reader open from IndexWriter (StandardDirectoryReader.open(IndexWriter, ...) failure path, with an IndexWriterConfig leaf sorter, LUCENE-9507)",
   "title": "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",
   "summary": "You set a leaf sorter on IndexWriterConfig and open an NRT reader from the writer; if the sorter throws while the new reader sorts its leaves, you expect only that exception and a writer left as it was, because the open's own catch releases the segment readers it took and IndexWriter.getReader keeps the writer usable after a non-Error exception. Instead the open has already called writer.incRefDeleter(segmentInfos), which only the returned reader's close undoes, and no reader is returned, so the writer keeps every segment file of that point in time referenced for the rest of its life: after forceMerge(1) and commit, the files of the merged-away segments _0 and _1 are still in the directory.",
   "impact_class": "minor",
   "introduced_commit": "48715fe898bf0a900e3e6b681882ecb1b6d8e1b1 (main, 'LUCENE-9507 Custom order for leaves in IndexReader and IndexWriter (#32)', apache/lucene#32 by mayya-sharipova, tracker LUCENE-9507 = #10546) and its branch_8x backport 1cfd0df4e7bb6180b67abb30bd92390bc729ec3f (apache/lucene-solr#2473) [read]. The commit passed the application's leaf sorter into the StandardDirectoryReader constructor that the NRT open calls right after writer.incRefDeleter(segmentInfos). The incRefDeleter placement (65274f5965b, LUCENE-5434, 2014) and the catch that releases only the segment readers (4312f3d71ab LUCENE-5262, 2e35ef2b3da LUCENE-8215) are older, but before LUCENE-9507 the constructor could throw only through BaseCompositeReader's too-many-documents check, which IndexWriter prevents [read]; so the window opens with the leaf sorter.",
   "introduced_date": "2021-03-26 (author date of 48715fe898bf on main); branch_8x backport author date 2021-03-30; first release 8.9.0",
   "first_affected_version": "8.9.0 [exec] (first release with the leaf sorter, through the branch_8x backport: a copy of the JUnit that differs only in the LuceneTestCase import fails, and a core-only port fails while its no-failure control passes); 8.8.2 lacks IndexWriterConfig#setLeafSorter [exec]; first 9.x release 9.0.0 [exec]",
   "affected_versions": "every release from 8.9.0 through 10.6.0 and main 645d4fe14a20; never fixed. [exec] the minimal JUnit TestNrtOpenLeafSorterFailureReleasesFiles fails on main (-ea and -da; re-run 2026-11-01, seed DEADBEEF, 'file of a merged-away segment was not deleted: _0.cfe') and passes with the fix shadowed (-da); it fails on the released 10.6.0 jars (4ae946e5a9b, -ea and -da), 10.5.2, 10.0.0, 9.12.3 and 9.1.0; the import-only copy fails on 9.0.0, 8.11.4 and 8.9.0 (-ea); the core-only main() port fails on 8.9.0, 9.0.0 and main and its control passes on 8.9.0 and main; the independent reproduction's independent test fails on main (-ea, -da), 10.6.0 (-ea, -da), 10.5.2 and 9.12.3. [read] the releases in between by code identity of the NRT open (no non-cosmetic change since 48715fe898bf). Upstream main f815e679bf6 (2026-11-01) and branch_10_6 have no commit to StandardDirectoryReader.java after 2026-02-11 (448c7d8e241 on main, c8b00d2ba72d on branch_10_6, author dates); no commit to BaseCompositeReader.java after 2025-07-30 or to IndexWriter.java after 2026-09-21 on main. Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1067.html",
   "repro": "repro/LFV-1067/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-626",
   "priority": "low",
   "priority_rank": 999,
   "novelty": "new",
   "withheld": false,
   "area": "core / index NRT reader open from IndexWriter (StandardDirectoryReader.open(IndexWriter, ...) keep check for fully deleted segments; SoftDeletesRetentionMergePolicy as the stock trigger)",
   "title": "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()",
   "summary": "You use soft deletes with SoftDeletesRetentionMergePolicy, open a new IndexWriter on an index whose last commit holds a fully soft-deleted segment that the retention query keeps, and call DirectoryReader.open(writer); the merge policy's keep check for that segment fails (one read error while the retention query reads the segment, or your retention-query supplier throws), so the open fails with that exception. You expect the failed open to release what it acquired, as StandardDirectoryReader.open's own catch block does for every reader already in its list (LUCENE-5262), so that closing the writer leaves no file open. Instead the SegmentReader obtained just before the keep check is neither in that list nor released, so after IndexWriter.close() the segment stays open (MockDirectoryWrapper: 'there are still 4 open files: {_0.cfs=1, _0_1_Lucene90_0.dvp=1, _0_1_Lucene90_0.dvs=1, _0_1_Lucene90_0.dvd=1}'), while the writer itself stays open and a later NRT open works.",
   "impact_class": "minor",
   "introduced_commit": "ecc17f9023309ca2c46eaf65fd031e4af0ef5a25 on master ('LUCENE-8233: Add support for soft deletes to IndexWriter', by s1monw; JIRA LUCENE-8233, mirrored as apache/lucene#9280; patch era, no pull request on the Apache repository) and its branch_7x backport 02fa5a0b059353ae5607e91211cea24974257980 the same day. In StandardDirectoryReader.open(IndexWriter, ...) it replaced the non-throwing package-private writer.getKeepFullyDeletedSegments() with the new public hook mergePolicy.keepFullyDeletedSegment(reader), declared 'throws IOException', between obtaining the reader and readers.add(reader), so an exception from the hook bypasses the release-on-failure list [read]. No earlier good version of the path exists to bisect: the window opens exactly when the throwing hook arrives. Later commits kept it: d9041124281 / branch_7x 330fd18f200 (LUCENE-8253, before 7.4.0, IOSupplier form called as () -> reader), 8294e1ae206 (LUCENE-8962, first released in 8.7.0, reader from readerFunction.apply(info)) and 2d6ad2fee6d (LUCENE-9570, reformat). The release-on-failure catch block itself is older: 4312f3d71ab (LUCENE-5262, 2013), rewritten by 2e35ef2b3da (LUCENE-8215, 2018-03-19)",
   "introduced_date": "2018-04-04 (ecc17f90233 on master and 02fa5a0b059 on branch_7x)",
   "first_affected_version": "7.4.0 [exec] (tagged 2018-06-22, via the branch_7x backport: the history test fails 2/3 with -ea and -da, its control passes); on the master line the first release is 8.0.0 [exec]; 7.3.1 is not affected [exec]",
   "affected_versions": "every release from 7.4.0 through 10.6.0 and main a9779ef3c193; never fixed. [exec] a history test (a retention-supplier throw and a FilterMergePolicy IOException, each asserted to fire inside StandardDirectoryReader.open with the writer left open and not tragic, plus a no-fault control that passes everywhere): leaks on 7.4.0 (-ea and -da), 7.7.3, 8.0.0, 8.6.3, 8.7.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main (-ea and -da), and passes 3/3 on main with the fix shadowed; the finder, the independent reproduction, the intended-behaviour check and the cross-model review re-runs also executed 10.5.2 and 9.12.3; the one-test minimal repro fails on the 10.6.0 release jars (SHA-1 checked against Maven Central) with -ea, 4 files left open (2026-11-01) [exec]. [read] all 58 release tags 7.4.0..10.5.2 in the history clone call the keep check right after obtaining the reader with no guard (8.8.2-8.11.4 are not tagged in the clone; 8.11.4 was executed); upstream main a95c754ee003 (2026-10-26), branch_10x, branch_10_6 and branch_9_12 still have the unguarded call (read-only API check). Not affected: every release up to 7.3.1 (API absent). The number of leaked files differs by version (2 on 7.4.0-10.0.0, 3 on 10.5.2, 4 on main and 10.6.0) with how many doc-values update files the codec keeps open; the leaked object is the same.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-626.html",
   "repro": "repro/LFV-626/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-440",
   "priority": "low",
   "priority_rank": 1000,
   "novelty": "new",
   "withheld": false,
   "area": "index / flush-time index sorting (SortingStoredFieldsConsumer, SortingTermVectorsConsumer)",
   "title": "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",
   "summary": "You configure an index sort, and while a flush is creating the final sorted stored-fields (or term-vectors) files, creating or opening a file fails with an IOException, for example because the process has too many open files. You expect IndexWriter to close itself, as it does after any failed flush, and to release every file it opened. Instead the reader that the flush had just opened on the temporary .fdt/.fdx (or .tvd/.tvx) files is never closed, because it is opened one statement before the try whose finally closes it, so two inputs on already-deleted temporary files stay open (on MMapDirectory, mapped) after IndexWriter and the Directory are closed.",
   "impact_class": "minor",
   "introduced_commit": "4ccb9fbd2bbc3afd075aa4bc2b6118f845ea4726 (master, first released in 7.0.0) and its branch_6x backport 7d96f9f7981d (first released in 6.5.0), LUCENE-7579 = apache/lucene#8630 'Sorting on flushed segment' (contributed by jimczi, committed by mikemccand; no pull request, reviewed on JIRA), which created both consumers with this order: open the temporary reader, create the final writer, then enter the try whose finally closes both [read]",
   "introduced_date": "2016-12-20 (master commit 4ccb9fbd2bb; the branch_6x backport 7d96f9f7981 was committed 2017-01-17)",
   "first_affected_version": "6.5.0 [exec]; first master-line release 7.0.0 [exec]",
   "affected_versions": "every release from 6.5.0 through 10.6.0, and main ea57360912ed. [exec] 6.5.0, 6.6.6, 7.0.0, 7.7.3, 8.6.3, 8.7.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main leak (-ea; also -da on 6.5.0, 10.5.2 and main); 6.4.2 does not leak (-ea and -da). [read] all 74 numeric release tags from 6.5.0 on in the history clone contain the change and none of the 77 older ones does (the clone has no 8.8.2-8.11.4 tags; 8.11.4 was executed). Trigger scope by version [exec]: 6.5.0 to 8.6.3 leak only on flushes that reorder documents (an already-sorted flush renamed the temporary files and opened no reader); from 8.7.0 (LUCENE-9510) every sorted flush with stored fields or term vectors is exposed. Not fixed upstream: upstream main cf398bfb142c and branch_10x still create the writer before the try [read]; the one-test minimal repro fails on the 10.6.0 release jars (SHA-1 checked against Maven Central) with -ea and -da (2026-11-01) [exec], and upstream main 2f424fd428da and branch_10_6 7e5aec4370e still create the writer before the try [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-440.html",
   "repro": "repro/LFV-440/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-486",
   "priority": "low",
   "priority_rank": 1001,
   "novelty": "new",
   "withheld": false,
   "area": "misc / BP reordering (BPIndexReorderer forward index; merge-time reordering through BPReorderingMergePolicy)",
   "title": "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",
   "summary": "You merge with BPReorderingMergePolicy and a BPIndexReorderer (or call BPIndexReorderer#computeDocMap yourself), and while the reorderer opens the two temp files of its on-disk forward index, the second open (the start-offsets file) fails with an IOException, for example because the process has run out of file descriptors. You expect the reorder and the merge to fail and every temp-file input the reorderer opened to be released, as the class does for its other temp inputs and as IndexWriter#close promises ('Closes all open resources'). Instead the input on the term-ids temp file, opened one statement earlier, is never closed, because the two opens and the ForwardIndex constructor sit outside any try/finally, so it stays open (on MMapDirectory, mapped, keeping the deleted file's disk space) after IndexWriter and the Directory are closed.",
   "impact_class": "minor",
   "introduced_commit": "39f3777886cd1967f41987a33c1991ddb901cec0 (main) and its branch_9x copy 7372a4ef055d39509144e421de7703b7977627c5, apache/lucene#12489 'Add support for recursive graph bisection.' (by jpountz, merged 2023-09-14, milestone 9.8.0), which added BPIndexReorderer with the three unguarded statements at the end of buildForwardIndex [read]. Not a regression; #14913 (27d1272984f, 2025-07-14, main only) rewrote computePermutation's failure cleanup without touching these lines, and neither the old cleanup (closeWhileHandlingException(postingsOutput, forwardIndex) with forwardIndex still null) nor the new one (delete files only) can close them",
   "introduced_date": "2023-09-14",
   "first_affected_version": "9.8.0 [exec] (tagged with #12489; only the direct BPIndexReorderer#reorder path exists there); the merge path through BPReorderingMergePolicy (#12622) from 9.9.0 [exec]; 9.7.0 and earlier lack the class [exec]",
   "affected_versions": "every release from 9.8.0 to 10.6.0 (10.6.0 by reading) and main ea57360912ed; never fixed. [exec] a history repro (a MockDirectoryWrapper subclass that fails the first open of a start-offsets file, with a no-injection control that passes everywhere) fails on 9.8.0, 9.9.0, 9.10.0, 9.11.1, 9.12.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) and passes on main with the fix shadowed; the finder's JUnit fails on main (-ea, -da), 10.5.2 and 9.12.3 (it does not compile on 9.9.0 and 9.10.0, whose computeDocMap has the older two-argument signature); the independent reproduction's JUnit fails on main (-ea, -da), 10.5.2, 9.12.3, and in a signature-adapted copy on 9.11.1 and 9.9.0. [read] 9.9.1, 9.9.2, 9.11.0, 9.12.1, 9.12.2, 10.1.0 to 10.4.0, 10.5.0 and 10.5.1 have the identical three statements and the same caller cleanup (23 release tags checked). Not fixed upstream: main a9779ef3c193 (lines 768-770), branch_10x and branch_10_6 (lines 823-825) unchanged, read 2026-10-26; no open PR changes these lines. All runs: JDK 25, SHA-1-verified release jars from Maven Central, aarch64 Linux",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-486.html",
   "repro": "repro/LFV-486/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-456",
   "priority": "low",
   "priority_rank": 1002,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter commit failure path (prepareCommit, IndexFileDeleter reference counts, merge-on-commit)",
   "title": "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()",
   "summary": "You call commit() and it throws a non-tragic exception early, for example an IOException while Lucene opens the small segments it merges as part of the commit (on by default), or from your MergePolicy.findFullFlushMerges or doAfterFlush override; the writer stays open, as Lucene intends. You expect the writer to delete the files of that failed commit once they are no longer needed: after later merges and commits, on deleteUnusedFiles(), on rollback() (whose javadoc says it removes any temporary files) or on close(). Instead prepareCommit has already taken a reference on every file of the commit and releases it only if startCommit fails, so these files keep a positive reference count and stay on disk until a new IndexWriter opens the directory.",
   "impact_class": "minor",
   "introduced_commit": "78d186e081f5 on trunk (LUCENE-3348 'IndexWriter applies wrong deletes during concurrent flush-all', SVN r1155278, no PR), first on a release branch as 5379279c101d (LUCENE-3189 'make sure we sync on IW when invoking IFD', lucene_solr_3_4 r1166811; branch_3x twin e5fd3fde0b6c): prepareCommit takes the commit's file references inside the full flush and then calls the protected doAfterFlush hook in a finally block outside every decRef path, so then only a doAfterFlush override that throws could hit it [read]. Widened by 7f352a96659b (LUCENE-8962 'Merge small segments on commit', lucene-solr PR #1617; branch_8x 9b1c92809e73): it moved the filesToCommit assignment, the only thing the failure path decRefs, after the new merge-on-commit block, so findFullFlushMerges, merge-reader opening, MergeScheduler.merge(COMMIT) and the wait joined the window (opt-in then); by 6ba9fe5be35d (LUCENE-9406, lucene-solr PR #2342): IndexWriterEventListener callbacks inside the window; by b5795db0cf51 (LUCENE-10078, PR #921; branch_9x 7d9de759f244): merge-on-commit on by default (500 ms), so the default IndexWriterConfig reaches it; and by 3d4082ca3dcf (PR #12549): merge-on-commit also when the commit flushed nothing [read]",
   "introduced_date": "2011-08-09 on trunk (78d186e081f5); 2011-09-08 on the 3.4 branch (5379279c101d); widened 2020-06-27 (merge-on-commit), 2021-03-02 (event listener), 2022-06-07 (default configuration), 2023-10-24 (commits with no flushed changes)",
   "first_affected_version": "3.4.0 [exec], where only a throwing doAfterFlush override reaches it; 8.6.0 [exec] for the opt-in merge-on-commit triggers (an IOException opening a merge reader, a throwing findFullFlushMerges); 9.3.0 [exec] for the default IndexWriterConfig with an ordinary IOException while merge-on-commit opens its readers",
   "affected_versions": "Every release from 3.4.0 to 10.5.2 and main. Executed and affected: 3.4.0, 8.5.2 (doAfterFlush trigger only), 8.6.0 (-ea and -da), 8.11.4, 9.2.0, 9.3.0, 9.8.0, 9.12.3 (-ea and -da), 10.0.0, 10.5.2 (-ea and -da) and main ea57360912ed (-ea and -da) with the follow-up's per-version ports; main, 10.5.2, 9.12.3 and 9.0.0 also with the independent reproduction's own tests [exec]. 3.5.0-3.6.2 and 4.0.0-alpha-7.7.3 (doAfterFlush trigger only; the order was read at 3.5.0, 3.6.0, 4.0.0, 4.4.0, 5.0.0, 6.0.0 and 7.0.0), 8.7.0-8.10.x, 9.0.0-9.1.0 (plus the event-listener trigger), 9.4.0-9.7.0, 9.9.0-9.11.x and 10.1.0-10.5.1 [read]. The default IndexWriterConfig reaches it from 9.3.0 [exec]. Not affected: 3.3.0 [exec]. 10.6.0 (released 2026-10-29) not tested. Not fixed upstream: no change to IndexWriter.java on main after 2026-09-21 and no open PR changes prepareCommitInternal's reference handling (2026-10-26) [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/4445",
    "https://issues.apache.org/jira/browse/LUCENE-3372",
    "https://github.com/apache/lucene/issues/9738",
    "https://issues.apache.org/jira/browse/LUCENE-8692",
    "https://github.com/apache/lucene/issues/12228",
    "https://github.com/apache/lucene/issues/10005"
   ],
   "doc": "",
   "repro": "repro/LFV-456/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-309",
   "priority": "low",
   "priority_rank": 1003,
   "novelty": "known",
   "withheld": false,
   "area": "facet / taxonomy (SearcherTaxonomyManager.refreshIfNeeded and the NRT and Directory constructors: the taxonomy reader taken before an unguarded SearcherManager.getSearcher call)",
   "title": "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",
   "summary": "You use SearcherTaxonomyManager with a SearcherFactory that does real work in newSearcher, such as warm-up queries, and that work throws during maybeRefresh(). You expect the failed refresh to release what it took, as SearcherManager.getSearcher does for the new index reader ('this decRefs incoming reader on throwing an exception') and as the same method has done since LUCENE-8244 when the taxonomy reopen itself fails. Instead the taxonomy reader that refreshIfNeeded took just before calling the factory is never released: with an unchanged taxonomy the manager's current taxonomy reader keeps an extra reference and is never closed, not even by mgr.close(); with a changed taxonomy the newly opened taxonomy reader and its files stay open for the life of the process; and the NRT and Directory constructors leak the taxonomy reader they open in the same way when the factory throws on the first searcher.",
   "impact_class": "minor",
   "introduced_commit": "03694e7693092432701be0186607e25e4633ea2b (trunk, svn r1466548; backported to branch_4x as e9fb220401ef, svn r1466550, the commit 4.3.0 contains), 'LUCENE-3786: add SearcherTaxonomyManager' by mikemccand (JIRA LUCENE-3786, now #4859; CHANGES credits Shai Erera and Mike McCandless; no pull request) [read]. Not a regression: the defect is as old as the class. The Directory-constructor site came with 06434e5b5f8 (branch_4x a293b3afd47, LUCENE-5320, 4.7.0); LUCENE-8244 (4fba55c8642, 7.4.0) later guarded only the TaxonomyReader.openIfChanged call before it",
   "introduced_date": "2013-04-10 (03694e76930); the Directory-constructor site 2014-01-30 (06434e5b5f8)",
   "first_affected_version": "4.3.0 [exec] (jars dated 2013-04-29; the first release with SearcherTaxonomyManager: a public-API port fails 2 of 3 with its no-failure control passing, passes 3 of 3 with only the getSearcher call shadow-fixed, and the NRT-constructor probe fails too); 4.2.1 has no SearcherTaxonomyManager [exec]",
   "affected_versions": "every release from 4.3.0 through 10.6.0 (10.6.0 by reading), and main ea57360912ed; not fixed. [exec] fail with the no-failure control passing: 4.3.0, 4.6.1, 4.7.0 and 4.10.4 (-ea only; the 4.x test framework refuses to run with -da), 5.0.0, 5.5.5, 6.6.6, 7.3.1, 7.4.0 (the LUCENE-8244 release, unchanged), 8.11.4 and 9.0.0 (-ea and -da) with history ports; 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) with the finder's unchanged JUnit; the independent reproduction's JUnit on main (-ea, -da), 10.5.2 and 9.12.3. Constructor sites [exec]: the NRT constructor on 4.3.0, 4.7.0 and main, the Directory constructor on 4.7.0 and main. [read] all 117 release tags from 4.3.0 to 10.5.2 in the history clone have the unguarded getSearcher return and no tr.decRef() (the clone lacks the 8.8.2 to 8.11.x tags; 8.11.4 was executed instead); upstream main, branch_10x and branch_10_6 have no commit on the file after #14443 (2025-05-18) and still have the unguarded call (GitHub commits API, read-only, 2026-10-26)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9291",
    "https://issues.apache.org/jira/browse/LUCENE-8244",
    "https://github.com/apache/lucene/issues/4871",
    "https://issues.apache.org/jira/browse/LUCENE-3798",
    "https://github.com/apache/lucene/issues/14443",
    "https://github.com/apache/lucene/issues/15985"
   ],
   "doc": "",
   "repro": "repro/LFV-309/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-357",
   "priority": "low",
   "priority_rank": 1004,
   "novelty": "new",
   "withheld": false,
   "area": "util / OfflineSorter concurrent sort (temp-file cleanup on failure)",
   "title": "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)",
   "summary": "You give OfflineSorter your own ExecutorService so it sorts partitions in parallel, and when sort() fails (an I/O error, a truncated input file, or an interrupt of the sorting thread) you expect it to delete every temp file it created, as it does without an executor and as its own code comment says ('So we can remove any partially written temp files on exception'). Instead sort() deletes only the temp files that exist at that moment and rethrows, without waiting for or cancelling the partition-sort and merge tasks it already handed to the executor. Those tasks then run and each writes a new prefix_sort_N.tmp file that nothing ever deletes (executed: the directory holds no sorter file right after sort() throws, and foo_sort_1.tmp once the queued task has run; with exec == null the same failure leaves nothing).",
   "impact_class": "minor",
   "introduced_commit": "db92a9efc2ee (LUCENE-7792 'add optional concurrency to OfflineSorter', by GitHub mikemccand, CHANGES credit dweiss and mikemccand, master; branch_6x backport bb8dd7a9f98d; committed from JIRA patches, no GitHub PR; the issue is now #8843) [read]",
   "introduced_date": "2017-04-26",
   "first_affected_version": "6.6.0 [exec] (first release with the ExecutorService constructor, via the branch_6x backport; 7.0.0 [exec] is the first from the master line; 6.5.1 has no such constructor [exec])",
   "affected_versions": "every release that has the ExecutorService constructor, 6.6.0 through 10.6.0, plus main ea57360912ed (not fixed), and only when a non-null executor is passed. Executed with the finder repro (2 of 2 tests fail unless noted; exec == null controls pass on 6.5.1, 6.6.0 and main): 6.6.0 (-ea and -da), 6.6.6, 7.0.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3 (-da 2 of 2; -ea 1 of 2, the interrupt test did not leak in that run), 10.0.0, 10.5.2 (-ea 2 of 2; -da 1 of 2, same caveat) and main (-ea and -da) [exec]; over --iters 50: 100 of 100 executions fail on 10.5.2 and 9.12.3 (-ea and -da), 99 of 100 (-ea) and 100 of 100 (-da) on main, and 40 of 40 in 20 separate JVM launches on 10.5.2 -da [exec]; the independent reproduction's own test fails on main, 10.5.2 and 9.12.3 (-ea and -da) [exec]; the one-test minimal repro fails on the 10.6.0 release jars (SHA-1 checked against Maven Central) with -ea and -da (2026-11-01) [exec]; the releases between the executed ones are inferred from tag ancestry and an unchanged sort() body (9.x and 10.x differ only in formatting and an IOContext argument; main turned the finally block into catch blocks with the same semantics, #14913) [read]; 8.8.2 to 8.11.3, cut from the separate lucene-solr repository, inferred",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-357.html",
   "repro": "repro/LFV-357/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1011",
   "priority": "low",
   "priority_rank": 1005,
   "novelty": "new",
   "withheld": false,
   "area": "misc / index tools (IndexRearranger.execute failure path: the await loops of createRearrangedIndex and applyDeletes inside the try-with-resources)",
   "title": "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",
   "summary": "You run IndexRearranger.execute() with several segment selectors and one of the tasks fails (its selector throws an IOException, or addIndexes hits an I/O error). You expect execute() to throw that error only after the tasks it started have stopped using its input reader and output IndexWriter. Instead execute() rethrows the first failed Future.get() at once and its try-with-resources closes the reader and the writer while the other tasks still run, so their selector code keeps running after execute() has thrown and fails with AlreadyClosedException 'this IndexReader is closed', and an addIndexes merge that is still running dies on a merge thread with an uncaught MergeException.",
   "impact_class": "minor",
   "introduced_commit": "e4cede0e8c5a640586c044f45e35448ef0f1862d (apache/lucene-solr#2246, LUCENE-9694 'New tool for creating a deterministic index', by GitHub zhaih, merged 2021-01-29 by mikemccand; JIRA migrated as apache/lucene#10733; backported to lucene-solr branch_8x the same day as 3da86cb5b368) [read]. Present since the class was created; not a regression. #11815 (369a70f2894, 2022-11-22, first released in 10.0.0) moved the loop into createRearrangedIndex and added the delete phase (applyDeletes) with the same loop.",
   "introduced_date": "2021-01-29",
   "first_affected_version": "8.9.0 (tag 2021-06-16, through the branch_8x backport 3da86cb5b36) [exec]; on the main line 9.0.0 (tag 2021-12-01) [exec]. Not affected: 8.8.2 and every earlier release, where the class does not exist [exec].",
   "affected_versions": "Every release that ships IndexRearranger: 8.9.0-8.11.4, 9.0.0-9.12.3 and 10.0.0-10.5.2, plus branch_10_6 (10.6.0, released 2026-10-29), branch_10x and main up to at least 645d4fe14a20. [exec] the finder's repro fails 2 of 2 on 8.9.0 (-ea and -da), 8.11.4, 9.0.0, 9.3.0, 9.4.0, 9.12.3, 10.0.0, 10.5.2, branch_10_6 4ae946e5a9b and main (-ea, -da, 20 of 20 over 10 iterations); the independent reproduction's own test fails on main (-ea and -da, 30 of 30 over 10 iterations), 10.5.2 (-ea and -da) and 9.12.3. [read] every other release has one of the three IndexRearranger.java blobs that were executed (17fb74d2234 in 8.9.0-8.11.4 and 9.0.0, c05a1a7b959 in 9.1.0-9.12.3, 7c3bd53cece in 10.0.0-10.5.2, branch_10_6, branch_10x and main). How it shows differs: in 8.9.0-9.3.0 addIndexes merges in the task's own thread, so the closed reader and the IndexWriter.close() under the running merge show but no merge-thread exception does; from 9.4.0 (LUCENE-10216, #633) the in-flight merge also dies on a merge thread with MergePolicy.MergeException(AlreadyClosedException). The delete-phase instance exists from 10.0.0 on (executed by the independent reproduction on main and 10.5.2). Not fixed upstream: IndexRearranger.java last changed in 369a70f2894 (author date 2022-11-22).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1011.html",
   "repro": "repro/LFV-1011/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1080",
   "priority": "low",
   "priority_rank": 1006,
   "novelty": "new",
   "withheld": false,
   "area": "misc / index tools (IndexRearranger.execute: lifecycle of the method-local executor on the failure path)",
   "title": "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",
   "summary": "You run IndexRearranger.execute() and it fails after it has started its work, for example because one of your DocumentSelectors throws an IOException. You expect execute() to throw that error and to release the thread pool it created for the run, as it does when the run succeeds. Instead executor.shutdown() is only the last statement of execute(), not in a finally, so on the failure path the pool's worker threads, which are non-daemon and never time out, stay alive forever: a program whose rearrange failed does not exit, and every failed call leaves more idle threads.",
   "impact_class": "minor",
   "introduced_commit": "e4cede0e8c5a640586c044f45e35448ef0f1862d (apache/lucene-solr#2246, LUCENE-9694 'New tool for creating a deterministic index', by GitHub zhaih, merged 2021-01-29 by mikemccand; JIRA migrated as apache/lucene#10733; branch_8x backport 3da86cb5b368 the same day) [read]. Present since the class was created; not a regression. #11815 (369a70f2894, by GitHub stefanvodita, author date 2022-11-22, first released in 10.0.0) moved the pool creation to the top of execute() and shutdown() to its last line (:136) to reuse the executor for the new deletes phase, which kept the defect, made the overlapping-selector IllegalStateException (the ordering check 9.1.0 added) leak, and added a second leaking exit, a failing deletes selector; git blame on main points at that commit, but the missing finally dates from e4cede0e8c5.",
   "introduced_date": "2021-01-29",
   "first_affected_version": "8.9.0 (released 2021-06-16, through the branch_8x backport 3da86cb5b36) [exec]; on the main line 9.0.0 (released 2021-12-07) [exec]. Not affected: 8.8.2 and every earlier release, which have no IndexRearranger [exec].",
   "affected_versions": "Every release that ships IndexRearranger: 8.9.0-8.11.4, 9.0.0-9.12.3 and 10.0.0-10.6.0 (released 2026-10-29, 4ae946e5a9b), plus main e1faeba08bde (12.0.0-SNAPSHOT); not fixed upstream (IndexRearranger.java last changed in 369a70f2894, author date 2022-11-22, on main, branch_11x and branch_10_6; re-checked 2026-11-02). [exec] the one-test repro (the independent reproduction's testSegmentSelectorFailure) fails 1 of 1 on 8.9.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0 and 10.6.0 (-ea; 10.6.0 also -da) and on main (-ea and -da); the finder's test fails on main (-ea, -da) and with -da on 10.6.0, 10.5.2, 9.0.0 and 8.9.0; the independent reproduction's two-test class fails on 10.6.0 and 10.5.2 (-da) and its 9.x port on 9.12.3. The 10.6.0 runs used the released 10.6.0 jars from Maven Central (SHA-1 checked, commit 4ae946e5a9b9), because the repro needs lucene-misc. [read] every other release by identity: one IndexRearranger.java blob in 9.1.0-9.12.3, one in 10.0.0-10.6.0 equal to main, 9.0.0's execute() byte-identical to e4cede0e8c5's, and the javap bytecode of execute() in 8.10.0-8.11.3 identical to 8.9.0 and 8.11.4 (one shutdown() call, no finally copy). Which exits leak differs: in 8.9.0-9.12.3 a failing segment selector or addIndexes leaks (shutdown() ran before the segment-ordering check that 9.1.0 added, so its IllegalStateException did not leak there [read]); from 10.0.0 (#11815) the overlapping-selector IllegalStateException and a failing deletes selector leak too [exec]. Not new in 10.6.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1080.html",
   "repro": "repro/LFV-1080/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1006",
   "priority": "low",
   "priority_rank": 1007,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / hunspell Dictionary loading (SortingStrategy.offline, HunspellStemFilterFactory)",
   "title": "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",
   "summary": "You load a hunspell Dictionary with a temp Directory (or through HunspellStemFilterFactory) and the load fails while the .dic entries are being written to the offline-sort temp file, for example because the .dic InputStream throws an IOException, which the constructor documents, or a write to the temp directory fails; you expect the failed constructor to close and delete the temp file it created, as it does on success and at the neighbouring steps. Instead Dictionary calls sortingStrategy.start(), which opens the temp IndexOutput, and then mergeDictionaries(...) with no failure handling, so the output stays open: MockDirectoryWrapper refuses to close ('there are still 1 open files: {dictionary_dat_0.tmp=1}'), and 10 failed HunspellStemFilterFactory.inform() calls leave 10 descriptors open on deleted hunspell_dat_0.tmp files until GC. The open handle is a regression from #12834 (9.9.0), which moved the entry writer out of its try-with-resources; the closed temp file that the direct constructor leaves in a caller-supplied tempDir is older (6.0.0).",
   "impact_class": "minor",
   "introduced_commit": "f460d612b5e43fe5567d4f4a87a380e324b4e8ee (main; apache/lucene#12834 'hunspell: allow in-memory entry sorting for faster dictionary loading', author donnerpeter, co-authored by dweiss, approved by dweiss, merged 2023-11-24), backported to branch_9x as 41da5c0b6a976da5cb803c6ae355153a72bfcaaa (parent 778b6f85570, #12825). It moved createTempOutput into SortingStrategy.offline().start() and the writer close into finishAndSort(), and the constructor now runs mergeDictionaries(...) outside any try; before it, the entries were written inside try (ByteSequencesWriter writer = new ByteSequencesWriter(output)) (9.8.0 Dictionary.java:253-254, 992) [read] [exec]. Older layer, not this regression: a closed temp file left after a failed load exists since 4.8.0 (LUCENE-5468, 803226ece41, in java.io.tmpdir) and, since 6.0.0 (LUCENE-6829, c855dd5a33f), in the caller's tempDir, where the factory removes it with IOUtils.rm [exec].",
   "introduced_date": "2023-11-24 (author date of f460d612b5e on main and of the 9.x backport 41da5c0b6a9)",
   "first_affected_version": "9.9.0 for the open IndexOutput and the factory descriptor leak [exec]; the closed temp file that the direct constructor leaves in a caller-supplied tempDir is older (6.0.0 [exec]; 4.8.0-5.5.5 left it in java.io.tmpdir, also via the factory [exec])",
   "affected_versions": "[exec] main 645d4fe14a20 (-ea and -da: finder, the independent reproduction, the intended-behaviour check, judge and re-runs), the 10.6.0 release candidate branch_10_6 4ae946e5a9b (core and analysis-common jars: timeline probe 1 file and 1 open descriptor for the direct constructor, 3 descriptors for 3 failed factory loads; exception-safety probe 13 of 20 checks fail; fault-injection harness the same 80 leaks), 10.5.2, 10.0.0, 9.12.3 and 9.9.0 (finder JUnit 3 of 4 fail; the independent reproduction's JUnit 3 of 4 fail on 10.5.2, 9.12.3 and 9.9.0). Partial [exec]: 9.8.0, 9.0.0, 8.11.4, 7.7.3 and 6.0.0 leave only the closed temp file in tempDir (no open output, factory clean); 4.8.0 and 5.5.5 leave a closed unsorted*dat in java.io.tmpdir, also via the factory. Not affected: 4.7.2 (no Dictionary class). [read] git tag --contains: 9.9.0-9.12.3 (10 tags) and 10.0.0-10.5.2 (12 tags) carry the start() / mergeDictionaries / finishAndSort sequence. All runs JDK 25 on aarch64 Linux. Not fixed upstream: main head is still 645d4fe; branch_10x and branch_10_6 have no later change to the three files (2026-10-29).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1006.html",
   "repro": "repro/LFV-1006/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-790",
   "priority": "low",
   "priority_rank": 1008,
   "novelty": "known",
   "withheld": false,
   "area": "suggest / SortedInputIterator temp-file cleanup (used by WFSTCompletionLookup and TSTLookup)",
   "title": "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)",
   "summary": "You build a WFSTCompletionLookup or a TSTLookup and the build fails while the input is being read or sorted, for example because the dictionary's next() throws an IOException, or an entry has weight -1, which WFSTCompletionLookup documents it rejects; you expect the failed build to remove the temp files it created, as AnalyzingSuggester and FSTCompletionLookup do. Instead SortedInputIterator, which both suggesters use to sort their input, leaves its temp input file behind: its constructor copies and sorts the input in sort() without any cleanup on failure and throws before the caller has an object it could close, so three failed builds leave suggest_input_0.tmp, suggest_input_1.tmp and suggest_input_2.tmp. This is a regression from LUCENE-7113 (6.0.0), which rewrote sort() and dropped the failure cleanup that 5.5.x still had.",
   "impact_class": "minor",
   "introduced_commit": "e458385b5e94d146853fabe5a94f2c9b0af31800 (6.0 release branch, shipped in 6.0.0), with the identical SortedInputIterator hunk in 70290e89476 (branch_6x, 6.1.0 and later 6.x) and ef7a0125133 (master, 7.0.0 and later): LUCENE-7113 'OfflineSorter and BKD should verify checksums in their temp files' (a JIRA patch commit, migrated as apache/lucene#8168; no GitHub PR; no CHANGES.txt entry). It replaced sort()'s success flag plus finally -> close() failure path with a try-with-resources around the copy loop only (to add CodecUtil.writeFooter) and moved the sort and the reopen after it [read]. [exec]",
   "introduced_date": "2016-03-19",
   "first_affected_version": "6.0.0 [exec]. The Directory-based constructors (LUCENE-6829) also first shipped in 6.0.0, so no release has that API without the leak.",
   "affected_versions": "every release from 6.0.0 through 10.5.2 (the last release before 10.6.0, which was not checked) and main a9779ef3c193. [exec] 6.0.0, 6.0.1, 6.1.0, 6.6.6, 7.0.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main leak (follow-up public-API probe, JDK 25, -ea, seed DEADBEEF); the finder's JUnit fails 3 of 4 on 6.0.0, 8.11.4, 9.12.3, 10.5.2 and main, the independent reproduction's JUnit 5 of 8 on 9.12.3, 10.5.2 and main, the intended-behaviour check's checks on 6.0.0, 6.6.6, 10.5.2 and main. [read] tag scan: sort() has no failure path in any of the 83 local tags 6.0.0-10.5.2 and has one in all 29 tags 4.6.0-5.5.5; 8.8.2-8.11.3 are not in the local clone and are affected by inference. Not affected [exec]: 4.10.4, 5.5.0, 5.5.5.",
   "security": "none",
   "upstream_links": [
    "https://lists.apache.org/thread/5ctczsb71oy3l7yskjkghdczv89dk73q",
    "https://issues.apache.org/jira/browse/LUCENE-4209",
    "https://github.com/apache/lucene/issues/5281",
    "https://issues.apache.org/jira/browse/LUCENE-7113",
    "https://github.com/apache/lucene/issues/8168"
   ],
   "doc": "",
   "repro": "repro/LFV-790/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-461",
   "priority": "low",
   "priority_rank": 1009,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-opennlp / lemma dictionary loading (OpenNLPOpsFactory.getLemmatizerDictionary)",
   "title": "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)",
   "summary": "You configure the OpenNLP lemmatizer with a dictionary file (for example CustomAnalyzer.builder(dir).addTokenFilter(\"openNlpLemmatizer\", \"dictionary\", \"lemmas.dict\")) and expect Lucene to close the file once it has read it, as it does for every other OpenNLP model and as it did for this dictionary up to 9.0.0. Instead OpenNLPOpsFactory.getLemmatizerDictionary passes loader.openResource(dictionaryFile) straight to OpenNLP's DictionaryLemmatizer, which reads the stream to the end but does not close it, so the file stays open after the analyzer is built and even after Analyzer.close(), until garbage collection reclaims the stream; Lucene's own LeakFS test filesystem reports 'file handle leaks: [InputStream(.../lemmas-...dict)]'. The lemmas themselves are correct; only the file handle leaks.",
   "impact_class": "minor",
   "introduced_commit": "8afec33e747e (main, 'LUCENE-10171: OpenNLPOpsFactory should directly cache DictionaryLemmatizer objects (#380)', PR apache/lucene#380 by spyk, merged by magibney) and its branch_9x backport a0330672466 (the commit that reached 9.1.0) [exec]; the line follows a PR review suggestion to pass the stream to the constructor directly (PR commit 3b39242decb, 2021-12-09; the PR was squash-merged); a regression: LUCENE-8188 (1bf71894869, by hossman, 7.3.0) had wrapped this read in try-with-resources, and the module's first version (LUCENE-2899) had leaked the same stream before any release",
   "introduced_date": "2022-03-08 (8afec33e747 on main and a0330672466 on branch_9x; PR commit 3b39242decb 2021-12-09)",
   "first_affected_version": "9.1.0 [exec] (9.0.0, the release before, closes the stream [exec], with the same opennlp-tools 1.9.1)",
   "affected_versions": "9.1.0 through 9.12.3 and 10.0.0 through 10.5.2 (every release in those ranges, 32 releases) and main ea57360912ed [exec]; not affected: every release from 7.3.0 (the first with the OpenNLP module) through 8.11.4, and 9.0.0 (37 releases) [exec]; the 8.x line never received LUCENE-10171 [read]; branch_10x and branch_10_6 have the same unclosed line 162 [read], and so does the 10.6.0 release commit 4ae946e5a9b, so 10.6.0 (released 2026-10-29) is affected [read]; not fixed upstream (upstream main 49483e82b357, 2026-10-26, unchanged; the only later commit to the file, ce50d3a135d #14228, makes the cache fields final) [read]; every affected run leaks with each opennlp-tools version the affected releases ran with (1.9.1, 1.9.4, 2.3.2, 2.5.3, 2.5.12) [exec]",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-8188",
    "https://github.com/apache/lucene/issues/9236",
    "https://issues.apache.org/jira/browse/LUCENE-10171",
    "https://github.com/apache/lucene/issues/11208",
    "https://github.com/apache/lucene/issues/380",
    "https://github.com/apache/lucene/issues/14194"
   ],
   "doc": "",
   "repro": "repro/LFV-461/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-624",
   "priority": "low",
   "priority_rank": 1010,
   "novelty": "known",
   "withheld": false,
   "area": "misc / index tools (GetTermInfo command-line helper)",
   "title": "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)",
   "summary": "You call GetTermInfo.getTermInfo(dir, term) from Java to print a term's document frequency and total term frequency, and expect it to release the index files it opened, as its sibling HighFreqTerms.main does for its reader. Instead it opens a DirectoryReader, prints the two numbers and returns without closing the reader, which the caller never sees and so cannot close. Every call leaves that reader's files open, and closing the Directory does not release them: Lucene's own MockDirectoryWrapper then refuses to close ('cannot close: there are still 1 open files: {_0.cfs=1}'), and 20 calls left 40 descriptors (NIOFS) or 40 mappings (mmap, still there after System.gc()) where a caller-closed reader leaves 0.",
   "impact_class": "minor",
   "introduced_commit": "ee5ec3ed3230c5ca5f5931303f22e625a6716a09 on trunk (LUCENE-2393 'add total TF tracking to HighFreqTerms tool', by Michael McCandless; first release 4.0.0-alpha) and its branch_3x backport f2164406dbe (first release 3.1.0). That commit created GetTermInfo with 'IndexReader reader = IndexReader.open(dir);' and no close, while the same commit's HighFreqTerms.main closes its reader. Evidence [read]: git log --follow and git show in the history clone; none of the 30 commits on the file there (all branches, the introduction included; API migrations such as LUCENE-3562, LUCENE-4095, LUCENE-4355, LUCENE-5200, LUCENE-5945, and the LUCENE-9570 reformatting 2cbf261032d, the last change) adds a close. Not bisected by execution: the method never closed its reader, so there is no earlier good version of it.",
   "introduced_date": "2010-05-13 (trunk, ee5ec3ed323); 2010-06-24 (branch_3x backport f2164406dbe)",
   "first_affected_version": "3.1.0 [exec] (tagged 2011-03-30), the first release that contains GetTermInfo; the 3.0.0 and 3.0.1 release tags have no GetTermInfo [read]. On the trunk line the first release is 4.0.0-alpha [read]. Backfill 2026-10-26 [exec]: 3.0.3, the last release before 3.1.0, has no GetTermInfo class, and 3.1.0 leaks.",
   "affected_versions": "Every release from 3.1.0 to 10.6.0 (10.6.0 by reading), and main a9779ef3c193; never fixed. [exec] on main (-ea and -da: the finder's JUnit, the independent reproduction's JUnit and descriptor probe, the cross-model review-lens control test, the intended-behaviour check's descriptor/mapping probe, the adjudication's probe and the reruns), on 10.5.2 and 9.12.3 (finder, the independent reproduction, the intended-behaviour check), and with the history probe (NIOFSDirectory descriptor count, -da, 10 calls against a caller-closed control that leaks 0) on 8.11.4, 7.7.3, 6.6.6, 5.5.5, 5.0.0 (10 descriptors left open each), 4.10.4 (10), 4.0.0 (40) and 3.1.0 (60). [read]: all 131 release tags from 3.1 to 10.5.2 open the reader in getTermInfo and never close it. Upstream main a95c754ee003 (2026-10-26) has the same code; the file is unchanged on main, branch_10x and branch_10_6 since 2021-01-05. Backfill 2026-10-26 [exec]: 3.1.0, 4.0.0 and 8.11.4 leak under the follow-up history probe; 10.5.2, main ea57360912ed and main a9779ef3c193 fail the independent reproduction's JUnit with -ea and -da; 3.0.3 is not affected (class absent).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/3468",
    "https://issues.apache.org/jira/browse/LUCENE-2393",
    "https://github.com/apache/lucene/issues/4950",
    "https://issues.apache.org/jira/browse/LUCENE-3877",
    "https://issues.apache.org/jira/browse/LUCENE-2106",
    "https://github.com/apache/lucene/issues/3182"
   ],
   "doc": "",
   "repro": "repro/LFV-624/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1010",
   "priority": "low",
   "priority_rank": 1011,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / ICU (ICUTokenizerFactory per-script rule files: rulefiles, parseRules)",
   "title": "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)",
   "summary": "You configure ICUTokenizerFactory with rulefiles=\"Latn:latin-rules.rbbi\" and the rule file cannot be read to the end, because it is not valid UTF-8 (for example saved as ISO-8859-1 with an accented letter in a comment) or because reading it throws an IOException; you expect inform() to fail with that exception and to close the stream it opened, as it does after a successful read and as the other Lucene analysis factories do. Instead parseRules calls reader.close() only after its read loop has finished normally, so the exception skips the close and the InputStream returned by the ResourceLoader stays open: a tracking loader still holds it after inform() threw, and with a real file read through FilesystemResourceLoader the test framework's LeakFS reports 'file handle leaks: [InputStream(.../latin-rules.rbbi)]'. The descriptor is released only when the stream is garbage collected; a rule file that decodes but does not compile is closed before compiling and does not leak.",
   "impact_class": "minor",
   "introduced_commit": "9a23a0799e5e678d0233430b6e683d9b91ce6030 (branch_4x merge, svn r1416629, 2012-12-03T18:32Z, the first commit any release tag contains: 4.1.0) of trunk commit 6024e1465e02302a0c1402127a6f407194365cd8 (svn r1416617, author Steven Rowe, 2012-12-03T18:21Z): SOLR-4123 'ICUTokenizerFactory - per-script RBBI customization' (Subversion and JIRA era, no PR; first patch by Robert Muir, final patches and commit by Steven Rowe; none of its 21 JIRA comments discusses closing the stream or a failed read). It added the rulefiles argument and parseRules with openResource, a read loop and a single reader.close() after the loop, with no try/finally [read]. The only later commits on the method changed no failure handling: 2f8192f3c5a (LUCENE-5560, 2014, charset constant) and 7f8b7ffbcad (LUCENE-9570, 2021, formatting) [read]. Born with the feature, not a regression [exec]",
   "introduced_date": "2012-12-03",
   "first_affected_version": "4.1.0 [exec] (the first release with rulefiles; 4.0.0 has no inform(ResourceLoader) in this factory and never opens a rule file [exec])",
   "affected_versions": "Every release from 4.1.0 to 10.6.0 and main 645d4fe14a20; never fixed. [exec] a history main() harness (public API, a java.lang.reflect.Proxy ResourceLoader whose streams record close(); a valid UTF-8 control, the same rules as ISO-8859-1, a stream that throws after 8 bytes), -da: both failure paths leak and the control is closed on 4.1.0, 4.3.1, 4.4.0, 4.10.4, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main; the finder's JUnit fails 3 of 4 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 (-da) and main (-ea and -da); the finder also ran 10.5.2 and 9.12.3 (-ea) and a pre-9 main() variant on 7.7.3 and 8.11.2; the independent reproduction's own JUnit fails on 10.5.2 and 9.12.3 (-ea and -da) and its main() variant on 8.11.2. The bundled ICU4J versions from 49.1 to 78.3 all behave the same. [read] parseRules has no try/finally and one reader.close() at all 120 release tags of the history clone (4.1.0..8.8.1 and 9.0.0..10.5.2; 8.8.2..8.11.4 untagged there, 8.11.4 executed); branch_10_6 4ae946e5a9b and branch_10x carry the same file blob as 10.5.2, upstream main and branch_11x the same blob as 645d4fe (2026-10-29). The one-test minimal repro fails on the 10.6.0 release jars, analysis-icu included (SHA-1 checked against Maven Central), with -ea and -da (2026-11-01) [exec]; not new in 10.6. Not affected: 4.0.0 and older (no rulefiles feature). All runs JDK 25 on Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1010.html",
   "repro": "repro/LFV-1010/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-070",
   "priority": "low",
   "priority_rank": 1012,
   "novelty": "new",
   "withheld": false,
   "area": "util / FST",
   "title": "Util.shortestPaths with topN=0 throws NoSuchElementException",
   "summary": "You ask Util.shortestPaths for the top 0 paths, directly or through FreeTextSuggester.lookup(key, 0). You expect an empty result. Instead it throws NoSuchElementException; with assertions off, WFSTCompletionLookup.lookup(prefix, false, 0) throws the same for a prefix that is not itself a key (for an exact key it returns one result, an older, separate quirk).",
   "impact_class": "crash",
   "introduced_commit": "LUCENE-4480 (0e77eec4366) introduced the crash; LUCENE-4481 (dc49949558d) gave the current form [exec]",
   "introduced_date": "2012-10-12 (0e77eec4366)",
   "first_affected_version": "4.1.0 [exec]",
   "affected_versions": "every release from 4.1.0 to 10.6.0, and main [exec]; 4.0.0 is not affected [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-070.html",
   "repro": "repro/LFV-070/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-553",
   "priority": "low",
   "priority_rank": 1013,
   "novelty": "known",
   "withheld": false,
   "area": "queries / MoreLikeThis term selection (MoreLikeThis.createQueue bounded priority queue; MoreLikeThisQuery; XML query parser LikeThisQueryBuilder)",
   "title": "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)",
   "summary": "You set MoreLikeThis.setMaxQueryTerms(0), whose javadoc says only 'the maximum number of query terms that will be included in any generated query', and call like(...) or retrieveInterestingTerms(...) on text with at least one eligible term, or search with a MoreLikeThisQuery or XML <LikeThisQuery> that carries maxQueryTerms 0. You expect a query with no terms (or an up-front IllegalArgumentException). Instead createQueue sizes its priority queue to limit = min(0, #terms) = 0, finds 'queue.size() < limit' false for the first eligible term, and dereferences queue.top(), which is null for a zero-capacity queue, so the call throws 'NullPointerException: Cannot read field \"score\" because \"term\" is null' (MoreLikeThis.java:669).",
   "impact_class": "wrong error",
   "introduced_commit": "173a44e67c7c3c1a9ffbe7259ea8b45f1f53b015 (trunk, svn r1609474) and its branch_4x backport 1427d574d3dae460d638b8d6584116baf4756214 (svn r1609493), which shipped in 4.10.0: LUCENE-5795 'More Like This: ensures selection of best terms is indeed O(n)' (now apache/lucene#6857; a JIRA patch committed by s1monw; CHANGES 4.10.0 'Optimizations') [read]. It replaced the unbounded queue plus createQuery's 'if (maxQueryTerms > 0 && qterms >= maxQueryTerms) break' with a queue bounded at min(maxQueryTerms, #terms) and a hand-written fill loop whose else branch reads queue.top() without the zero-capacity guard that insertWithOverflow had; zero was not discussed in the issue thread. Later edits to these lines added no guard (LUCENE-6954 e8dac9bfdf35, LUCENE-9570 8ef6a0da5687, LUCENE-9856 945b1cb87262, #14761 a7704f5242d6)",
   "introduced_date": "2014-07-10",
   "first_affected_version": "4.10.0 [exec]",
   "affected_versions": "every release from 4.10.0 through 10.5.2 and main ea57360912ed [exec] [read]; not affected: 4.9.0 and 4.9.1 [exec]; not fixed upstream [read]",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-5795",
    "https://github.com/apache/lucene/issues/6857",
    "https://github.com/apache/lucene/issues/940",
    "https://github.com/apache/lucene/issues/8011",
    "https://github.com/apache/lucene/issues/5569",
    "https://github.com/apache/lucene/issues/9268"
   ],
   "doc": "",
   "repro": "repro/LFV-553/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-799",
   "priority": "low",
   "priority_rank": 1014,
   "novelty": "new",
   "withheld": false,
   "area": "facet / range-on-range facet counts (LongRangeOnRangeFacetCounts and DoubleRangeOnRangeFacetCounts constructors: getEncodedRanges reads ranges[0])",
   "title": "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",
   "summary": "You count range-on-range facets with new LongRangeOnRangeFacetCounts(field, hits, QueryType.INTERSECTS) (or the Double variant) and pass no ranges, a call the varargs signature accepts and no javadoc forbids, and expect an empty FacetResult, as the classic LongRangeFacetCounts returns for the same empty request, or at least an IllegalArgumentException that rejects the empty list. Instead the constructor throws 'ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0', because its private helper getEncodedRanges sizes the encoded array from ranges[0].dims without checking that the list is non-empty.",
   "impact_class": "wrong error",
   "introduced_commit": "cbfed77fd33c24ea57e9acaace2c643bc7979b33 (main; apache/lucene#11901 'Github#11869: Add RangeOnRangeFacetCounts', by mdmarshmallow, merged by gsmiller) and its branch_9x backport d9fc418914aef731eda22c2486cb318f741f7b39, the commit in the 9.5.0 release [read]. The defect came with the API; not a regression.",
   "introduced_date": "2022-12-30 (merged 2022-12-30T15:38:13Z; the branch_9x backport has the same timestamp)",
   "first_affected_version": "9.5.0 [exec]; 9.4.2 and older are not affected because the rangeonrange package does not exist there [exec]",
   "affected_versions": "every release from 9.5.0 to 10.6.0 and main a9779ef3c193 (unreleased 11.0) [exec]. branch_10_6 (head 2763db11b0a): the three files are byte-identical to 10.5.2 [read]. Not fixed upstream: upstream main 20ced71c1e6 has byte-identical files, the 4 main commits after a9779ef3c193 do not touch lucene/facet, and no open PR changes getEncodedRanges or the constructors [read]. Executed on Linux aarch64 with JDK 25 only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-799.html",
   "repro": "repro/LFV-799/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-462",
   "priority": "low",
   "priority_rank": 1015,
   "novelty": "new",
   "withheld": false,
   "area": "queries / intervals (MultiTermIntervalsSource behind Intervals.prefix, wildcard, regexp, range, fuzzyTerm and multiterm; Weight#matches / IntervalsSource#matches)",
   "title": "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)",
   "summary": "You build IntervalQuery(\"f\", Intervals.prefix(new BytesRef(\"p\"), 2)) over a document 'pa pb pc' (three terms match p*) and call Weight#matches for it, as a highlighter does. You expect the over-expansion exception (IllegalStateException; IndexSearcher.TooManyClauses on main since #16899), because the javadoc says the source throws if the prefix 'expands to more than maxExpansions terms', and searching the same query on the same segment does throw. Instead matches() tests 'count++ > maxExpansions' after adding each term, so it returns a Matches for exactly maxExpansions + 1 matching terms in the document and throws only at maxExpansions + 2; the same holds for wildcard, regexp, range, fuzzyTerm and multiterm.",
   "impact_class": "wrong error",
   "introduced_commit": "7d7ab14776b7257e09679d840182a4286928e452 (main) and its branch_8x backport ceadb5f1339fe5bf09f9818470872d4957b63ba5, both 'LUCENE-8646: Add multi-term intervals' (JIRA patch, no GitHub PR; migrated issue apache/lucene#9692; by romseygeek), which wrote 'if (count++ > maxExpansions)' in both intervals() and matches() [read]. The reported divergence (search throws at maxExpansions + 1, matches() does not) starts with e8950f4a528605f9be17c644eef4f47d0659317b (branch_8x backport 74a695ee444d195421c9e5cceeee28a813b42cea), 'LUCENE-8845: Allow maxExpansions to be set on multi-term Intervals' (JIRA patch; migrated issue apache/lucene#9889; by romseygeek), which changed only the intervals() check to '++count > maxExpansions' and added limit tests for intervals() only [read].",
   "introduced_date": "2019-01-22 (faulty matches() line, 7d7ab14776b; authored 2019-01-17); 2019-06-10 (divergence, e8950f4a528)",
   "first_affected_version": "8.0.0 for the faulty matches() line: in 8.0.0, 8.1.0 and 8.1.1 both checks used 'count++', so with the then fixed limit of 128 both the search and matches() accepted 129 terms (the two paths agreed, both one term over the javadoc limit) [exec]; 8.2.0 for the reported symptom, matches() accepting maxExpansions + 1 terms while the search throws [exec]. 7.7.3 has no MultiTermIntervalsSource and no Intervals.prefix [exec].",
   "affected_versions": "every release that has the API and main [exec]: 8.0.0, 8.1.0, 8.1.1 show both checks off by one (paths agree); 8.2.0 through 10.6.0 (58 releases) and main ea57360912ed (-ea and -da) show the reported pattern, where only matches() lets maxExpansions + 1 terms through (limit 2 with 3 terms; default limit 128 with 129 terms); 128 terms allowed and 130 rejected on both paths in every release (controls). The finder's JUnit also fails on 9.1.0, 9.12.3 and 10.5.2, the independent reproduction's on 9.12.3 and 10.5.2. Not fixed upstream: apache/lucene main 49483e82b357, branch_10x and branch_10_6 still have 'if (count++ > maxExpansions)' at line 99 [read], and so does the 10.6.0 release commit 4ae946e5a9b [read]; #16899 (merged 2026-10-26 as f4cc6ac2097) keeps it. Affected factories, each from the release that added it [read]: prefix and wildcard 8.0.0 (configurable limit since 8.2.0), multiterm 8.4.0, fuzzyTerm 9.1.0, regexp and range 9.12.0. Tags 8.8.2-8.11.4 are not in the history clone; for those the result comes from executing the release jars only.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-462.html",
   "repro": "repro/LFV-462/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-519",
   "priority": "low",
   "priority_rank": 1016,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / spell (WordBreakSpellChecker word combinations)",
   "title": "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)",
   "summary": "You call WordBreakSpellChecker.setMaxEvaluations(n), documented as 'the maximum number of word combinations to evaluate', and then suggestWordCombinations, and you expect at most n combined-term lookups and so at most n suggestions. Instead the limit cuts off only the rest of the one left term at which the counter first equals n, and every later left term is evaluated in full: with every 2-6 letter run of 'abcdef' indexed, the query [a, b, c, d, e, f], maxChanges=5 and maxEvaluations=1, 11 of the 15 combinations are evaluated and returned, and maxEvaluations=0 evaluates all 15. Nothing is thrown and the work stays bounded by the number of terms times maxChanges; only the configured cap is not applied.",
   "impact_class": "minor",
   "introduced_commit": "642b882d5a50721ab88ade17b06cd9e2927745b1 (trunk, svn r1344318; same-day branch_4x backport 99fa008a71e), LUCENE-3523 'Add WordBreakSpellChecker to suggest based on word combinations and/or breaks' (now #4597, by jdyer1; svn era, no PR) [read]; the defect is in the method's first version and was never changed (927531255d4, LUCENE-4587, and the 2021 reformatting 2cbf261032d left the limit logic alone); GITHUB#12077 (9007f746a39 on main, ef8c18b43c7 on branch_9x, 9.5.0) fixed the same symptom only in generateBreakUpSuggestions, so this is an incomplete-fix sibling of #12077, not a regression from it",
   "introduced_date": "2012-05-30",
   "first_affected_version": "4.0.0-ALPHA [exec] (the first release with WordBreakSpellChecker; first GA release 4.0.0 [exec]); 3.6.2 has no such API [exec]",
   "affected_versions": "every lucene-suggest version on Maven Central before 10.6.0 (132): 4.0.0-ALPHA, 4.0.0-BETA and all 130 releases 4.0.0 to 10.5.2, plus main ea57360912ed, fail a public-API main() probe with identical numbers (11, 13, 4 and 15 combinations evaluated where 1, 3, 1 and 0 are allowed) [exec]; 10.6.0 (released 2026-10-29) fails the one-test minimal repro on its release jars (SHA-1 checked against Maven Central, -ea, 2026-11-01) [exec]; the finder's JUnit fails on 9.1.0, 9.4.2, 9.5.0, 9.12.3, 10.0.0, 10.5.2 and main [exec]; 9.5.0 (#12077) fixed suggestWordBreaks (136 suggestions on 9.4.2, 54 on 9.5.0 at maxEvaluations=100) and left this path unchanged [exec]; not fixed upstream: the line is still on origin/main a9779ef3c19 and on the branch_10x and branch_10_6 tips [read]; unaffected: 3.x and earlier (no API) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-519.html",
   "repro": "repro/LFV-519/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-743",
   "priority": "low",
   "priority_rank": 1017,
   "novelty": "known",
   "withheld": false,
   "area": "core / index (ParallelLeafReader and ParallelCompositeReader stored fields, StoredFieldVisitor protocol)",
   "title": "ParallelLeafReader stored fields ignore StoredFieldVisitor.Status.STOP: the later parallel readers still offer and deliver fields after the visitor answered STOP",
   "summary": "You split a document over two lockstep indexes (title in index A, price in index B), open them as a ParallelLeafReader, and load the document with a StoredFieldVisitor that answers STOP at title and YES otherwise, expecting the visit to end at title, as STOP promises ('stop processing any other fields for this document') and as a single index holding the same document does. Instead the second parallel reader still asks needsField(price) and delivers price=42 after the STOP, because ParallelLeafReader.storedFields().document() hands the visitor to each parallel reader in turn and never checks its answer. ParallelCompositeReader builds ParallelLeafReaders, so it behaves the same.",
   "impact_class": "minor",
   "introduced_commit": "4dad0ba89f1d663939999be9005433dd629955f1 (2011-08-27, the trunk merge 'LUCENE-2308: cutover to FieldType' that landed LUCENE-3309's StoredFieldVisitor API, GitHub #4382 and #3384; branch commit 3adbb7e13cbb, 2011-07-14; JIRA era, no PR) [read]: ParallelReader.document(int, StoredFieldVisitor) became an unconditional loop over the parallel readers, and the stop signal of the time (a boolean callback return) was already ignored by the loop. Status.STOP came with 7877d1ff072f (2011-11-09, trunk merge of LUCENE-2621, #3695), which left the loop unchanged, so the defect exists exactly as reported from there. The current loop shape is from LUCENE-3736 (#4810, 6188bc66d7d0, 2012-02-10) and #11998 (47f8c1baa2e8, 2022-12-13). Not a regression; the per-sub-reader loop is older still (the 3.x FieldSelector LOAD_AND_BREAK had the same per-reader-only break).",
   "introduced_date": "2011-08-27 (visitor loop); 2011-11-09 (Status.STOP added, loop untouched)",
   "first_affected_version": "4.0.0-alpha [exec] (first GA release 4.0.0 [exec]); no 3.x release has StoredFieldVisitor or Status (a port does not compile against 3.6.2 [exec])",
   "affected_versions": "Every release from 4.0.0-alpha through 10.5.2 (the last release before 10.6.0) and main a9779ef3c193; never fixed. [exec] 14 version points, all failing as expected (follow-up): 4.0.0-alpha, 4.0.0 and 4.10.4 (ParallelAtomicReader port), 5.0.0, 6.6.6, 7.7.3, 8.11.4, 9.0.0 and 9.4.2 (ParallelLeafReader port), 9.5.0, 9.12.3, 10.0.0, 10.5.2 and main with -ea and -da (the finder's JUnit); upstream main f7bcc0abd816 still had the loop at search time (2026-10-27, not executed) and no open PR changes it. Context only, a different API: on 3.6.2 a FieldSelector LOAD_AND_BREAK also ends only the current sub-reader of a ParallelReader [exec]. JDK 25.0.3, aarch64; pure Java logic.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/13342",
    "https://github.com/apache/lucene/issues/16847",
    "https://github.com/apache/lucene/issues/3609",
    "https://issues.apache.org/jira/browse/LUCENE-2535",
    "https://github.com/apache/lucene/issues/6222",
    "https://issues.apache.org/jira/browse/LUCENE-5158"
   ],
   "doc": "",
   "repro": "repro/LFV-743/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-733",
   "priority": "low",
   "priority_rank": 1018,
   "novelty": "new",
   "withheld": false,
   "area": "queries / spans: SpanMultiTermQueryWrapper top-N rewrite methods vs the core IndexSearcher clause limit",
   "title": "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",
   "summary": "You wrap new FuzzyQuery(term, 2, 0, 2000, true) in SpanMultiTermQueryWrapper (for example to use it inside a SpanNearQuery) and search an index where more than 1024 terms are within two edits. FuzzyQuery documents that a maxExpansions above IndexSearcher#getMaxClauseCount is replaced by the limit, and the span top-N rewrites say they 'will not overflow the boolean max clause count', so you expect the same capped expansion the plain FuzzyQuery gets (it runs with 1024 terms). Instead the span rewrite keeps up to maxExpansions terms (TopTermsSpanBooleanQueryRewrite.getMaxSize() returns Integer.MAX_VALUE, and FrequentTermsSpanBooleanQueryRewrite sizes its queue with the caller's size only), and IndexSearcher.rewrite throws IndexSearcher$TooManyNestedClauses ('maxClauseCount is set to 1024').",
   "impact_class": "crash",
   "introduced_commit": "53f56fb7ad44afab9c78fab2e89737438093247f (LUCENE-8811 'Move max clause checks to IndexSearcher', apache/lucene#9855, committed by romseygeek with patches by atris, 2019-06-26, first released in 9.0.0) is where the failure starts: IndexSearcher.rewrite began to count every clause of the rewritten query with a QueryVisitor, span terms included, and the commit did not touch SpanMultiTermQueryWrapper. The missing cap it exposes is older: TopTermsSpanBooleanQueryRewrite.getMaxSize() returning Integer.MAX_VALUE and the mapping of a TopTermsRewrite (FuzzyQuery's) to new TopTermsSpanBooleanQueryRewrite(size) come from ac71ebc23716 (LUCENE-2754, apache/lucene#3828, uschindler, 2010-11-14; 3.x backport 7d137513808), written when SpanOrQuery had no clause limit (sibling comment 'we accept all terms as SpanOrQuery has no limits', 1d0515124e2, LUCENE-2757). The FrequentTermsSpanBooleanQueryRewrite half is 156fb97fd33 on main and 3572e2c03f0 on branch_10x / branch_10_6 (apache/lucene#16484, 2026-08-18, first released in 10.6.0). [read]",
   "introduced_date": "2019-06-26 (53f56fb7ad4; first released in 9.0.0, 2021-12); latent cap omission 2010-11-14 (ac71ebc2371); FrequentTerms half 2026-08-18 (#16484, first released in 10.6.0)",
   "first_affected_version": "9.0.0 [exec] (first release that throws; the 8.x port of LUCENE-8811, fa3bf88783a, was reverted before any 8.x release, so 8.2.0 behaves like 8.1.1 [exec]; from 3.1.0, the first release with the wrapper, to 8.11.4 the span rewrite already kept more terms than the clause limit, but silently and without an exception [exec]; the FrequentTerms half from 10.6.0, released 2026-10-29)",
   "affected_versions": "Exception (TooManyNestedClauses): every 9.x and 10.x release, 9.0.0 through 10.5.2 (33 releases) [exec], 10.6.0 [exec], and main a9779ef3c193 [exec]; never fixed: origin/main a95c754ee00, branch_10x 1309534296e and branch_10_6 2763db11b0a still return Integer.MAX_VALUE [read]. The finder's JUnit fails on 9.0.0, 9.1.0, 9.12.3, 10.0.0 and 10.5.2 (3 of 3) and on main (4 of 4, -ea and -da); the independent reproduction's tests fail on 9.0.0, 9.12.3, 10.5.2 and main. FrequentTermsSpanBooleanQueryRewrite: main, branch_10x and branch_10_6 only (10.6.0, released 2026-10-29) [exec]. Silent over-expansion without an exception, recorded as history and not claimed: 3.1.0 through 8.11.4 (105 releases) [exec]. 3.0.3 and earlier: API absent [exec]. All runs with JDK 25 on aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-733.html",
   "repro": "repro/LFV-733/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-944",
   "priority": "low",
   "priority_rank": 1019,
   "novelty": "new",
   "withheld": false,
   "area": "queries / spans (SpanMultiTermQueryWrapper.FrequentTermsSpanBooleanQueryRewrite queue sizing; core ScoringRewrite creates the top-level builder before collecting terms; util PriorityQueue pre-allocates maxSize + 1 slots)",
   "title": "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",
   "summary": "You wrap a PrefixQuery in SpanMultiTermQueryWrapper, call setRewriteMethod(new FrequentTermsSpanBooleanQueryRewrite(Integer.MAX_VALUE)), whose javadoc promises only that it 'keeps at most maxSize terms' (ranked by document frequency instead of boost, unlike TopTermsSpanBooleanQueryRewrite), and expect it to keep all 3 matching terms, as TopTermsSpanBooleanQueryRewrite(Integer.MAX_VALUE) does on the same index. Instead the constructor accepts the value and every search then throws IllegalArgumentException 'maxSize must be >= 0 and < 2147483631; got: 2147483647', because getTopLevelBuilder() returns PriorityQueue.usingComparator(maxSize, order) and ScoringRewrite.rewrite calls it before it collects any term, so the internal queue pre-allocates maxSize + 1 slots (or rejects a size it cannot allocate) instead of being sized by the terms actually found; for the same reason a large legal cap such as 2^26 allocates about 268 MB per rewrite for 3 terms. Sizing the queue lazily, by min(maxSize, collected terms), as the sibling TopTermsRewrite does with a growing queue, fixes both and leaves every result unchanged.",
   "impact_class": "crash",
   "introduced_commit": "156fb97fd33d8f2039309381ccaca4a6a7e59e14 on main, 'LUCENE-6513: Add FrequentTermsSpanBooleanQueryRewrite' (apache/lucene#16484, author dsmiley; the feature request is #7571): it added the class with getTopLevelBuilder() { return PriorityQueue.usingComparator(maxSize, order); }, so the defect was born with the API [read]. On branch_10x and branch_10_6: the cherry-pick 3572e2c03f0 plus 2bcbe3d82ed (#16532, dweiss, 'Fix API only available on main'), which replaced usingComparator with new PriorityQueue<>(maxSize) { lessThan } and kept the eager sizing. The older ingredients are unchanged: ScoringRewrite has created its builder before collecting terms since at least 2015, PriorityQueue has pre-allocated maxSize + 1 slots and rejected sizes >= ArrayUtil.MAX_ARRAY_LENGTH since at least 2018 (4c646dab3fb), and TopTermsRewrite has used Math.min(size, getMaxSize()) with a growing queue since 2010. The introducing commits were not built (disk rule); git diff 156fb97fd33..a9779ef3c193 is empty for the five relevant files, and 2bcbe3d82ed..4ae946e5a9b differs only by diamond-operator edits (#16592) [read]",
   "introduced_date": "2026-08-18 (author date of 156fb97fd33 and of the cherry-pick 3572e2c03f0, 12:02:08-04:00; #16484 merged 16:02:09Z); 2026-08-19 (2bcbe3d82ed, the 10.x API adaptation)",
   "first_affected_version": "10.6.0 (released 2026-10-29; the release revision branch_10_6 4ae946e5a9b fails the repro [exec]). No earlier release is affected: 10.5.2 and 9.12.3 do not have the class [exec]",
   "affected_versions": "main a9779ef3c193 (11.0.0-SNAPSHOT) [exec]. branch_10_6 head 4ae946e5a9b (the 10.6.0 RC1 revision, released as 10.6.0 on 2026-10-29) [exec]. branch_10x (10.7.0 development; contains 3572e2c03f0 and 2bcbe3d82ed) [read]. Not affected: every release up to 10.5.2, all 9.x included (class absent; 10.5.2 and 9.12.3 executed: compile error, while the sibling control TopTermsSpanBooleanQueryRewrite(Integer.MAX_VALUE) passes 2 of 2 there). Not fixed upstream: SpanMultiTermQueryWrapper.java last changed on main by 156fb97fd33 and on branch_10_6 by f6fce7e42c5 (#16592, build infrastructure) [read]. All runs on Linux aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-944.html",
   "repro": "repro/LFV-944/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b): 3 of 3 fail with -ea and -da; 10.5.2 does not have FrequentTermsSpanBooleanQueryRewrite."
  },
  {
   "id": "LFV-993",
   "priority": "low",
   "priority_rank": 1020,
   "novelty": "new",
   "withheld": false,
   "area": "core / search: field-sorted top-N collection (FieldValueHitQueue, TopFieldCollectorManager)",
   "title": "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)",
   "summary": "You call new TopFieldCollectorManager(sort, Integer.MAX_VALUE, null, 1).newCollector() with any built-in sort (a long field, a string field, Sort.RELEVANCE), directly or through SortRescorer.rescore(searcher, topDocs, Integer.MAX_VALUE), and expect the IllegalArgumentException 'maxSize must be >= 0 and < 2147483631' that Lucene 7.5.0 to 10.6.0 throw (main's score-ordered TopScoreDocCollectorManager still throws an IllegalArgumentException, with its own message). On main you get OutOfMemoryError 'Requested array size exceeds VM limit' instead ('Java heap space' at 2147483631 with a 1 GB heap). Since #14873, FieldValueHitQueue.create builds the sort comparators, each of which pre-allocates a numHits-sized array, before it calls the PriorityQueue constructor, whose size check exists to prevent exactly this confusing OutOfMemoryError (SOLR-5661).",
   "impact_class": "wrong error",
   "introduced_commit": "39549329509 (#14873, PR title 'Make PriorityQueue use LessThan interface by default', commit 'Change PriorityQueue to use LessThan interface by default (#14873)', by Simon Cooper (thecoop); base main, milestone 11.0.0): it turned FieldValueHitQueue from an abstract PriorityQueue subclass, whose constructor called super(size) and so reached the SOLR-5661 guard before it built the comparators, into a class built by the static create(), which builds the comparators first and only then calls the constructor [exec]. #14873 was an API refactor; its CHANGES entry (11.0.0 API Changes), MIGRATE.md and review thread say nothing about size validation. Cited as the source of the change, not as blame.",
   "introduced_date": "2025-07-03 (author and commit date of 39549329509, 16:04:41+01:00; PR merged 2025-07-03T15:04:41Z)",
   "first_affected_version": "unreleased (main [exec], 12.0.0-SNAPSHOT at e1faeba08bd, and the 11.0 release branch branch_11x [read], 11.0.0-SNAPSHOT; the first affected release would be 11.0.0); every release from 4.7.0 to 10.5.2 and 10.6.0 (released 2026-10-29 from RC 4ae946e5a9b) is unaffected",
   "affected_versions": "[exec] main from 39549329509 (2025-07-03) through a9779ef3c193 fails: the finder's JUnit 3 of 4 with -ea and -da (the control passes), the independent reproduction's JUnit 6 of 7 with -ea and -da, a history probe 0 of 3 field sorts with the IllegalArgumentException at 39549329509 and at a9779ef3c193. [exec] not affected: 4.7.0, 8.11.4, 9.10.0, 9.12.3, 10.0.0, 10.5.2, the 10.6 RC 4ae946e5a9b and main's parent commit 62e02760321 (IllegalArgumentException from PriorityQueue). [read] branch_11x 603af870375 (the 11.0 release branch, cut from main on 2026-10-28) and upstream main 2f424fd428da (2026-10-30) have the same create() order with no size check; branch_10x 657014b3c57 (decommissioned on 2026-10-29) and branch_10_6 still call super(size) first. Releases before 4.7.0 throw the OutOfMemoryError from PriorityQueue itself: that is the original SOLR-5661 bug (executed on 4.6.1), long fixed and not this regression. Not fixed upstream: through main e1faeba08bd, FieldValueHitQueue.java was changed after 39549329509 only by #16857 (70a428b5ba9) and #16947 (f6e64aa0db3), and neither changes the order in create() [read]. All runs on Linux aarch64 with JDK 25.0.3. [exec] main e1faeba08bd still fails (minimal repro 1 of 1 with -ea and -da; the OutOfMemoryError is now raised under FieldValueHitQueue.create:147). [read] branch_11x da3ea39fa59 has the same FieldValueHitQueue.java blob as main (affected); branch_10_6 91eaab4fb29 (the 10.6.1 work) keeps the 10.6.0 file, which calls super(size) first (not affected).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-993.html",
   "repro": "repro/LFV-993/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-392",
   "priority": "low",
   "priority_rank": 1021,
   "novelty": "new",
   "withheld": false,
   "area": "util / BytesRefArray (iterator(Comparator) with a null comparator)",
   "title": "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)",
   "summary": "You append two or more values (for example c, a, b) to a BytesRefArray and call iterator((Comparator<BytesRef>) null), expecting the values back in append order, as the method's javadoc promises ('Otherwise the order is the same as the values were appended') and as Lucene 8.4.1 and earlier do. Instead the call throws NullPointerException ('Cannot invoke Comparator.compare ... because this.val$cmp is null', from StringSorter$1.compare via BytesRefArray.sort), because the method now always sorts with the given comparator; with 0 or 1 values, or with the no-arg iterator(), append order still comes back. The one-line fix restores the pre-8.5 null check ('return iterator(comp == null ? null : sort(comp, false));'); a maintainer may instead prefer to correct the javadoc.",
   "impact_class": "minor",
   "introduced_commit": "a0b8f5c7c28bd897bdf48ed7af20b385a236b3a9 'LUCENE-9228: Sort dvUpdates by terms before apply' (by GitHub dnhatn; issue apache/lucene#10268; reviewed in apache/lucene-solr#1263 and committed directly; branch_8x backport 83ccb8d2a2204c78de0cf119d63ef452ef95fcc6, same diff, first released in 8.5.0): it removed 'final int[] indices = comp == null ? null : sort(comp);', made iterator(Comparator) sort unconditionally, sent iterator() to the new iterator((SortState) null) overload and left the iterator(Comparator) javadoc unchanged [read]. 3cb71436a7b (apache/lucene#12591, 9.x backport 7c1d1147beb, first in 9.9.0) rewrote the body to 'return iterator(sort(comp, false));' through StringSorter and kept the defect (the NPE frame moved from BytesRefArray$1.compare to StringSorter$1.compare, executed at 9.8.0 -> 9.9.0). The null contract itself dates from f303bcd4650 (LUCENE-3807, 2012)",
   "introduced_date": "2020-02-20 (a0b8f5c7c28 and the branch_8x backport 83ccb8d2a22)",
   "first_affected_version": "8.5.0 [exec] (8.0.0-8.4.1 iterate in append order [exec]; the first main-line release with the change is 9.0.0)",
   "affected_versions": "Every release from 8.5.0 through 10.6.0 and main ea57360912ed (10.6.0: the one-test minimal repro fails on the release jars, SHA-1 checked against Maven Central, -ea, 2026-11-01 [exec]); not fixed upstream (apache/lucene main cf398bfb142c, branch_10x and branch_10_5 still have 'return iterator(sort(comp, false));', read-only check 2026-10-26). [exec] a version sweep with a main() probe (values c, a, b appended, JDK 25, release jars SHA-1 checked): of 60 releases from 8.0.0 to 10.5.2, the 8 releases 8.0.0-8.4.1 print append order 'cab' and the 52 releases 8.5.0-8.11.4, 9.0.0-9.12.3 and 10.0.0-10.5.2 throw NullPointerException; 4.8.0 and 7.7.3 also pass. The finder's JUnit fails on main (-ea and -da), 10.5.2, 10.0.0, 9.12.3, 9.9.0 and 9.8.0; the independent reproduction's JUnit fails on main (-ea and -da), 10.5.2 and 9.12.3, and the independent reproduction's main() probe passes on 8.4.1 and fails on 8.5.0. [read] the 8.8.2-8.11.4 tags are not in the history clone, so for those releases the status comes from execution only. Arrays with 0 or 1 values are unaffected.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-392.html",
   "repro": "repro/LFV-392/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-219",
   "priority": "low",
   "priority_rank": 1022,
   "novelty": "new",
   "withheld": false,
   "area": "geo / XY shapes (XYPolygon winding order, Tessellator.tessellate(XYPolygon), XYShape.createIndexableFields and createDocValueField)",
   "title": "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'",
   "summary": "You build an XYPolygon with large but finite float coordinates, which the constructor accepts (any finite float), for example the triangle (0,0), (2^66,2^66), (2^67,2^66), and index it with XYShape.createIndexableFields; you expect it to index exactly like the same triangle at scale 1, because multiplying every coordinate by a power of two is exact and changes neither the shape nor its orientation. The constructor computes the winding sum with float products, which overflow to Infinity once coordinate differences reach about 1.8e19; Infinity minus Infinity is NaN, and a NaN sum is labelled CW. The Tessellator then links the ring the wrong way round, finds no ear to cut, and rejects the valid polygon with 'Unable to Tessellate shape. Possible malformed shape detected.'",
   "impact_class": "crash",
   "introduced_commit": "0c09481374cab029d57b0f9b45994822c0dcd39b (master; LUCENE-8632 'New XYShape Field and Queries for indexing and searching general cartesian geometries', nknize, apache/lucene-solr#726, migrated issue apache/lucene#9678; branch_8x backport 81c88e2df30428f61fad6129525d839c57e08504, shipped in 8.2.0 in the lucene-sandbox module) [read]. The float arithmetic came from the PR-internal commit 4d0c96f40b8dd9d2f5c2bb2112e55a81dd47e1cd ('change XYPolygon and XYLine API to accept floats instead of doubles', 2019-06-26): it turned the constructor parameters into float[], which shadow the double[] fields, while the loop kept reading the parameters; at its parent 1c982b90199 the sum was computed in double, and the PR was squash-merged, so no mainline commit had the double version. Later commits kept the expression: 4a54ffb553a (LUCENE-9218, 8.5.0) made the fields float[], 2d6ad2fee6d (LUCENE-9570) only reformatted the two lines. No build at 0c09481374c or its parent was made (the API does not exist before it).",
   "introduced_date": "2019-07-08 (0c09481374c on master and 81c88e2df30 on branch_8x, the same day); the PR-internal float change 4d0c96f40b8 has author date 2019-06-26",
   "first_affected_version": "8.2.0 [exec] (XYShape and XYPolygon in the lucene-sandbox module, @lucene.experimental, through 8.4.1); 8.5.0 [exec] is the first lucene-core release (LUCENE-8621 moved it to core); 8.1.1 and earlier have no XYPolygon [exec]",
   "affected_versions": "Every release with XYShape through 10.6.0: 8.2.0 to 8.4.1 (sandbox module), 8.5.0 to 10.5.2 (core) and 10.6.0 [exec], and main ea57360912ed. [exec] the finder's JUnit fails 2 of 2 on main (-ea and -da), 10.5.2 (-ea and -da), 9.12.3 (-ea and -da), 10.0.0 and 9.1.0; its framework-free main() fails on 9.0.0, 8.11.4, 8.5.0, 8.4.1 (sandbox) and 8.2.0 (sandbox, -ea and -da); the independent reproduction's JUnit fails 4 of 5 on main (-ea and -da), 10.5.2 and 9.12.3 and its main() on 8.11.4, 8.5.0 and 8.4.1 (sandbox); the intended-behaviour check's tests fail on main and 10.5.2. [read] a bytecode check of all 57 releases from 8.2.0 to 10.5.2 (jars SHA-1-checked against Maven Central) finds the float products (2 fmul, 0 dmul) in the constructor of every one, and upstream main, branch_10x and branch_10_6 have the same line (GitHub contents API, 2026-10-26). Not affected: 8.1.1 and earlier (API absent) [exec]. 10.6.0 (released 2026-10-29): the one-test minimal repro fails on the release jars (SHA-1 checked against Maven Central) with -ea and -da (2026-11-01) [exec]. All runs on aarch64 with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-219.html",
   "repro": "repro/LFV-219/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-771",
   "priority": "low",
   "priority_rank": 1023,
   "novelty": "new",
   "withheld": false,
   "area": "core / geo (Rectangle.fromPointDistance circle bounding box, used by LatLon distance and Circle queries)",
   "title": "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",
   "summary": "You run LatLonPoint.newDistanceQuery(\"p\", 0.43945312499999994, 0, 9958692.080819247), a valid centre and a finite, non-negative radius whose circle stops about 7 cm short of the north pole, and expect it to match the two indexed points inside the circle. Instead IndexSearcher.count throws IllegalArgumentException 'invalid longitude NaN; must be between -180.0 and 180.0' from Rectangle.fromPointDistance, and LatLonDocValuesField.newSlowDistanceQuery throws the same when it is built. The bounding box computes asin(sin(r) / cos(lat)) without a clamp, and SloppyMath.cos, which is not monotone across its lookup-table switches, makes the quotient 1.0000000000000002 although its exact value is below 1, so asin returns NaN.",
   "impact_class": "crash",
   "introduced_commit": "92b659ab9e1a (trunk) / 3a189ff68dec (branch_5x, shipped in 5.5.0): LUCENE-6908 (migrated as #7966) by nknize, which replaced StrictMath.asin/sin/cos with SloppyMath in the non-pole branch deltaLon = asin(sin(radDistance) / cos(radLat)) and added sin(a) = cos(a - pi/2) [read]. The unclamped quotient itself is older (d369057766ae, LUCENE-6780, 2015-10-21, sandbox, StrictMath trig), but that form threw for no input in the bounded scans. Later commits moved or renamed the code and kept the formula: 665041c52f08 (LUCENE-6997, to lucene-spatial), ce3114233bdc (LUCENE-7123, GeoUtils.sloppySin), 6c219e99e4b / 951563aa427 (LUCENE-7163, core Rectangle.fromPointDistance, 6.1.0) and 3fcc87752a42 (#14516, renamed to SloppyMath.sin, 10.3.0); 045659533cd (LUCENE-7147, the 7 cm pad, 6.1.0) only moved the witness radius. Never clamped: not a regression",
   "introduced_date": "2015-12-07",
   "first_affected_version": "5.5.0 [exec]. The API named in the title, core Rectangle.fromPointDistance, exists from 6.1.0; LatLonPoint.newDistanceQuery from 6.0.0 (sandbox module) and in core from 7.5.0",
   "affected_versions": "Every release from 5.5.0 to 10.6.0, and main a9779ef3c193; never fixed (10.6.0: the one-test minimal repro fails on the release jars, SHA-1 checked against Maven Central, -ea and -da, 2026-11-01 [exec]). [exec] 17 releases and main fail, 5.4.1 passes: the version-adapted public-API probe throws for 17,844 legal circles in each line on 5.5.0, 5.5.5, 6.0.0, 6.0.1, 6.1.0, 6.6.6, 7.4.0, 7.5.0, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 10.2.2, 10.5.2 and main (-da also on 5.5.0, 8.11.4 and main); the finder's JUnit fails 3 of 3 on 9.12.3, 10.0.0, 10.2.2, 10.3.0, 10.5.2 (-ea and -da) and main (-ea and -da); the independent reproduction's JUnit fails 5 of 6 on 9.12.3, 10.5.2 and main; the independent reproduction's main() probe fails on 8.11.4 and 7.7.3. The exact repro radius 9958692.080819247 m applies from 6.1.0 (5.5.x and 6.0.x converted radius to angle differently, so the probe finds other radii there). [read] every release tag 5.5.0..10.5.2 in the history clone contains the unclamped line; it is unchanged on upstream main f7bcc0abd816, branch_10x and branch_10_5 (2026-10-27), and no open PR touches Rectangle.java, SloppyMath.java or Circle2D.java. All runs with JDK 25.0.3 on aarch64; the code is pure Java double arithmetic, and a re-run in the interpreter with SVE off (-Xint -XX:UseSVE=0) fails the same way; x86 was not run",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-771.html",
   "repro": "repro/LFV-771/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-742",
   "priority": "low",
   "priority_rank": 1024,
   "novelty": "new",
   "withheld": false,
   "area": "spatial3d / geom path distances (GeoStandardPath and GeoDegeneratePath PathSegment foot selection; Geo3DDocValuesField.newPathSort)",
   "title": "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",
   "summary": "You build a geo3d path (GeoPathFactory.makeGeoPath, or the path of Geo3DDocValuesField.newPathSort) and ask for the distance of a point that the path reports as inside it, expecting a number (GeoDistance.computeDistance documents a distance, or +Infinity outside the shape). Instead, when the point sits at the very edge of the 1e-12 tolerance band of a segment's cutoff plane, the call throws RuntimeException(\"Can't find world intersection ...\"): on the unit sphere a point 3.4e-6 rad beside a path of width 1e-4 and 1e-12 rad past its middle point throws instead of returning about 0.1000034, the same happens for a zero-width path's nearest and centre distance, and a 500 km path sort whose middle point sits at a stored document's decoded longitude makes IndexSearcher.search throw. The cause: the segment's tolerant section test accepts the point, then the same tolerant test rejects both rounded perpendicular feet of the point on the path, and the code throws instead of picking one.",
   "impact_class": "crash",
   "introduced_commit": "688c67f8ff22b72b9df4ed2f92d26b909563b2b1 on trunk (svn r1688545) and its branch_5x backport 780e4040238713c2ff85c4b981cbc6b80aa4094f (svn r1688546), 'LUCENE-6578: Geo3D: compute the distance from a point to a shape' (JIRA LUCENE-6578, now apache/lucene#7636; svn era, no pull request; committed by dsmiley, CHANGES credits DaddyWri (Karl Wright) and David Smiley). It added computeDistance and PathSegment.pathDistance with findIntersections, a strict 'within both cutoff planes' choice of the foot and the else-throw, while SidedPlane.isWithin already accepted points up to MINIMUM_RESOLUTION outside a plane. The same block was later copied into nearestPathDistance and pathCenterDistance (LUCENE-7962, #9011, 2017-09), into GeoDegeneratePath (LUCENE-7955, #9004, 2017-09) and into pathDeltaDistance (LUCENE-8039, #9087, 2017-11-08); the user-facing newPathSort came with LUCENE-7212 (#8267, 2016-05). [read]",
   "introduced_date": "2015-07-01 (trunk and branch_5x); facets: newPathSort 2016-05-17, nearest/centre distance and GeoDegeneratePath 2017-09, computeDeltaDistance 2017-11-08",
   "first_affected_version": "5.3.0 [exec] (tag dated 2015-08-20) for computeDistance; 5.2.1, the last release before, returns the correct distance 0.10000344868558741 for the same point [exec]. Per facet: Geo3DDocValuesField.newPathSort from its first release, 6.1.0 [exec]; computeNearestDistance / computePathCenterDistance and the zero-width GeoDegeneratePath from 7.1.0 [exec] (7.0.1 rejects width 0 and has no such methods [exec]); computeDeltaDistance from 7.2.0 [exec]",
   "affected_versions": "every release from 5.3.0 through 10.5.2 (the last release before 10.6.0), 10.6.0 [exec] and main a9779ef3c193. Executed (JDK 25, -ea unless noted, version-specific public-API main() probes or the finder's JUnit), all failing at the foot-selection throw and never at the 'no intersection' throw: 5.3.0, 5.5.5, 6.0.0, 6.1.0 (computeDistance and the path sort), 6.6.6, 7.1.0 (zero-width nearest/centre), 7.2.0 (all four methods), 7.7.3, 8.11.4, 9.4.2, 9.5.0 (both sides of the 2022 GeoStandardPath refactor), 9.12.3 and 10.5.2 (finder JUnit 3 of 3; the independent reproduction's JUnit 5 of 5 with -ea and -da), main (-ea and -da). Releases not executed are inferred from unchanged throw logic [read]. Not fixed upstream: upstream main a95c754ee003, branch_10x and branch_10_6 carry the same throw sites and no open PR touches the two files [read]. Not affected: 5.2.1 and earlier [exec]. Caveat: all runs used JDK 25; the JDKs the old releases shipped for could move the exact input window by last-ulp trig differences, not the code path.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-742.html",
   "repro": "repro/LFV-742/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-080",
   "priority": "low",
   "priority_rank": 1025,
   "novelty": "new",
   "withheld": false,
   "area": "memory / MemoryIndex",
   "title": "MemoryIndex reports the total number of point dimensions as the number of index dimensions",
   "summary": "You add a selectively indexed point field (for example 2 dimensions, 1 index dimension) to a MemoryIndex and run a point query on it. You expect the query to work as on a normal index. Instead getNumIndexDimensions() returns the total dimension count and the query throws IllegalArgumentException.",
   "impact_class": "crash",
   "introduced_commit": "1118299c338 (LUCENE-8496 'Selective indexing - modify BKDReader/BKDWriter to allow users to select a fewer number of dimensions to be used for creating the index', Nicholas Knize, 2018-10-08; issue now apache/lucene#9542, PR apache/lucene-solr#451 landed as direct commits; branch_7x backport 804afbfd47c, 2018-10-18, first released in 7.6.0): it split MemoryIndex's getNumDimensions() into getNumDataDimensions() and a new getNumIndexDimensions() with the same body, in the commit that made the point queries check getNumIndexDimensions() [read]",
   "introduced_date": "2018-10-08 (1118299c338 on master; branch_7x backport 804afbfd47c 2018-10-18)",
   "first_affected_version": "7.6.0 [exec] (7.5.0 has no setDimensions(int, int, int), so the trigger cannot be written [exec])",
   "affected_versions": "every release from 7.6.0 to 10.6.0 (66 releases) and main [exec]; not fixed upstream: upstream main f815e679bf6c (2026-11-01), branch_11x and branch_10_6 have the same line [read]; unaffected: 7.5.0 and earlier (no selective indexing, the trigger cannot be written) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-080.html",
   "repro": "repro/LFV-080/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-136",
   "priority": "low",
   "priority_rank": 1026,
   "novelty": "new",
   "withheld": false,
   "area": "index / MultiDocValues merged numeric, binary and norms doc-values views (also the merged reader passed to MergePolicy.OneMerge#reorder)",
   "title": "MultiDocValues numeric, binary and norms views throw NullPointerException from advance() after advanceExact() landed on a segment without the field",
   "summary": "You read a merged doc-values view over an index with several segments (MultiDocValues.getNumericValues, getBinaryValues or getNormValues, or the merged reader that IndexWriter hands to a custom OneMerge#reorder), call advanceExact(0), which returns false because doc 0's segment has no values for the field, and then call advance(1). You expect advance(1) to return the next document that has a value (doc 2 in the repro), as the sorted-numeric view of the same index and the per-segment codec iterators do. Instead it throws NullPointerException ('this.currentValues is null'): advanceExact stored a null per-segment iterator for the segment without the field, and advance() assumes that iterator is non-null as long as the target stays in the same segment.",
   "impact_class": "minor",
   "introduced_commit": "9aca4c9d560 (9aca4c9d56089a9ac89df5fd93be76a4fe822448) 'LUCENE-7462: Give doc values APIs an advanceExact method.' by jpountz (JIRA LUCENE-7462, migrated as apache/lucene#8514; JIRA patch workflow, no GitHub PR): its advanceExact() in the numeric, binary and norms views stores currentValues = null for a segment without the field and sets nextLeaf past that segment; contributing commit f7aa200d406 (LUCENE-7407, apache/lucene#8460, mikemccand) wrote the advance() methods whose same-segment path calls currentValues.advance(...) with no null check, which was safe until advanceExact existed [read]",
   "introduced_date": "2016-10-20 (author date of 9aca4c9d560; committed to master 2016-10-24); contributing f7aa200d406 2016-09-21",
   "first_affected_version": "7.0.0 [exec]; public OneMerge#reorder path from 9.9.0 [exec]",
   "affected_versions": "every release 7.0.0 through 10.6.0 (7.x, 8.x, 9.x, 10.x; 10.6.0 [exec]) and main ea57360912ed; never fixed. Executed failing: 7.0.0, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea), main (-da) [exec]; independently re-run: main -ea/-da, 10.5.2, 9.12.3 (-ea and -da) and 8.11.4 by the independent reproduction, main -ea/-da and 10.5.2 by the intended-behaviour check, main by the adjudication [exec]; other releases by unchanged code (blame, git log -G) [read]. Public OneMerge#reorder path: 9.9.0, 9.12.3, 10.5.2 and main (-ea and -da) fail [exec]; absent in 9.8.0 [exec]. Not affected: 6.x and older (no doc-values iterator API) [exec]. Upstream main, branch_10x, branch_10_6 and branch_9_12 still have the code [read]; open PR #14475 moves the code verbatim and keeps the defect [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-136.html",
   "repro": "repro/LFV-136/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-055",
   "priority": "low",
   "priority_rank": 1027,
   "novelty": "new",
   "withheld": false,
   "area": "util / automaton",
   "title": "AutomatonTermsEnum throws ArrayIndexOutOfBoundsException for an NFA with a reachable dead state",
   "summary": "You compile an NFA that has a reachable dead end (a dead state with no transitions) on the term walk into a CompiledAutomaton and intersect it through a non-block-tree consumer such as DOC_VALUES_REWRITE, SortedSetDocValues.intersect or MemoryIndex. You expect the matching terms, which the block-tree path returns. Instead AutomatonTermsEnum throws ArrayIndexOutOfBoundsException.",
   "impact_class": "crash",
   "introduced_commit": "c972c6a7754e (LUCENE-10010 'Introduce NFARunAutomaton to run NFA directly', apache/lucene#225, by zhaih, merged 2021-12-20, first released in 10.0.0): it removed CompiledAutomaton's 'Automaton must be deterministic' check, scoped the no-dead-states rule to DFAs and wrapped NFAs as they are [exec]; the same input also threw in the sampled releases 4.0.0 to 9.12.3, where the javadoc forbade dead states (since LUCENE-3030, b7846ffaa1f, 2011)",
   "introduced_date": "2021-12-20",
   "first_affected_version": "10.0.0 [exec] (the minimal repro fails on the 10.0.0 release jars; before 10.0 the javadoc forbade dead states)",
   "affected_versions": "10.0.0 to 10.6.0 and main [exec]; not fixed upstream: upstream main f815e679bf6c has the same code [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-055.html",
   "repro": "repro/LFV-055/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-029",
   "priority": "low",
   "priority_rank": 1028,
   "novelty": "new",
   "withheld": false,
   "area": "util / automaton",
   "title": "RunAutomaton throws ArrayIndexOutOfBoundsException on a 0-state automaton",
   "summary": "You build an automaton with zero states through Automaton.Builder and create a RunAutomaton from it. You expect a run automaton that accepts nothing. Instead the constructor throws ArrayIndexOutOfBoundsException.",
   "impact_class": "crash",
   "introduced_commit": "LUCENE-5959 (0bf7d74eac7d)",
   "introduced_date": "2014-09-18",
   "first_affected_version": "5.0.0",
   "affected_versions": "5.0.0 to 10.6.0 (all 108 lucene-core releases in that range) and main 645d4fe14a20 [exec]; 4.10.0 to 4.10.4 not affected [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-029.html",
   "repro": "repro/LFV-029/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-865",
   "priority": "low",
   "priority_rank": 1029,
   "novelty": "new",
   "withheld": false,
   "area": "core / analysis: AutomatonToTokenStream (automaton to token-graph conversion)",
   "title": "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\"))",
   "summary": "You convert an automaton whose language is empty, for example Automata.makeEmpty() or Operations.intersection(Automata.makeString(\"a\"), Automata.makeString(\"b\")), with AutomatonToTokenStream.toTokenStream, whose only stated precondition is a finite DAG. You expect a TokenStream with no tokens (what the same method already returns for Automata.makeEmptyString() and for the same empty language written with one dead state) or at least a clear IllegalArgumentException. Instead it throws ArrayIndexOutOfBoundsException 'Index 0 out of bounds for length 0', because these automata have 0 states and the method reads indegree[0], the in-degree of the start state, without checking that a state exists.",
   "impact_class": "crash",
   "introduced_commit": "647255b4d29bb56ddcfdf44bdb6e7d5d0ca76a14 (apache/lucene#157, LUCENE-9963 'Improve FlattenGraphFilter's robustness when handling incoming token graphs with holes', author @glawson0, merged by @mikemccand), which created AutomatonToTokenStream as a helper for the FlattenGraphFilter tests with the unguarded 'if (indegree[0] != 0)' read and the 'new int[transitions.length]' allocation already in place; 8.x backport 75eba3892979 (apache/lucene-solr#2551, branch_8x) has the same read. [read]. Not a regression: the crashing lines never changed; the pre-10.0 Operations.isFinite pre-check did not catch the input (isFinite returns true for 0 states) and was removed by 15f3743f02c (#11813, first released in 10.0.0) without changing the outcome.",
   "introduced_date": "2021-08-09 (647255b4d29b, author date 2021-08-10 05:06:53 +0900 = 2021-08-09T20:06:53Z); 8.x backport 2021-08-16 (75eba389297)",
   "first_affected_version": "8.10.0 [exec] (the first release with AutomatonToTokenStream; lucene-core 8.9.0 has no such class [exec]); 9.0.0 on the 9.x line",
   "affected_versions": "Every release that has the class (the 40 from 8.10.0 to 10.5.2, and 10.6.0), all executed and failing with the same exception at the indegree[0] line: 8.10.0, 8.10.1, 8.11.0-8.11.4, 9.0.0-9.12.3 (21 releases), 10.0.0-10.5.2 (12 releases) [exec]; branch_10_6 head 4ae946e5a9b (10.6.0) [exec]; main a9779ef3c193 [exec]. The independent reproduction's own JUnit fails on main, 10.5.2 and 9.12.3; the intended-behaviour check's probe on main, 10.5.2 and 9.12.3. Not fixed upstream: the newest commit to the file on main is 7335eb0ad96 (#15704, author date 2026-02-26), and the file at main head c5ab3e57b9b (2026-10-28) is byte-identical to the tested one [read]. Not affected: 8.9.0 and earlier (class absent) [exec]. All runs with JDK 25 on aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-865.html",
   "repro": "repro/LFV-865/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-021",
   "priority": "low",
   "priority_rank": 1030,
   "novelty": "new",
   "withheld": false,
   "area": "util / automaton",
   "title": "FiniteStringsIterator returns the empty string twice",
   "summary": "You iterate the finite strings of an automaton that accepts the empty string with FiniteStringsIterator. You expect each accepted string once. Instead the empty string is returned twice, and size() counts the duplicate.",
   "impact_class": "silent wrong results",
   "introduced_commit": "3d8bfad40b0 (LUCENE-6365, iterator rewrite)",
   "introduced_date": "2015-07-04",
   "first_affected_version": "5.3.0 [read]",
   "affected_versions": "5.3.0+ [read]; 7.4.0, 8.11.4, 10.1.0 and main [exec]; 5.0.0 has no FiniteStringsIterator",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-021.html",
   "repro": "repro/LFV-021/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-067",
   "priority": "low",
   "priority_rank": 1031,
   "novelty": "new",
   "withheld": false,
   "area": "util / FST",
   "title": "FSTCompiler throws ArrayIndexOutOfBoundsException on BYTE4 nodes whose labels span 2^31-8 or more",
   "summary": "You build a BYTE4 FST with arbitrary int labels so that one node's labels span 2^31-8 or more. You expect the FST to build, and direct addressing to be off with a factor of -1. Instead the presence-byte count wraps and the build throws ArrayIndexOutOfBoundsException, even with factor -1.",
   "impact_class": "crash",
   "introduced_commit": "LUCENE-8920 (068b6babac3, #980)",
   "introduced_date": "2019-11-13",
   "first_affected_version": "8.4.0 [exec]; 7.7.3 and 8.0.0 to 8.3.1 build [exec]",
   "affected_versions": "8.4.0 to 10.6.0 (all 55 lucene-core releases) and main 645d4fe14a20 [exec]; 7.7.3 and 8.0.0 to 8.3.1 not affected [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-067.html",
   "repro": "repro/LFV-067/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-031",
   "priority": "low",
   "priority_rank": 1032,
   "novelty": "new",
   "withheld": false,
   "area": "store / ByteBuffersDataInput",
   "title": "ByteBuffersDataInput.readLongs and readFloats fail when blocks are smaller than 8 bytes",
   "summary": "You read longs or floats in bulk from a ByteBuffersDataInput built from blocks smaller than 8 bytes. You expect the same values as reading them one at a time. Instead readLongs/readFloats throw IllegalArgumentException.",
   "impact_class": "crash",
   "introduced_commit": "LUCENE-10150 (#11187, PR #363, 61c15c8c10f) for readLongs and LUCENE-9652 (7b9f8751456) for readFloats; LUCENE-10155 (#360, 6c6a3bd5bd5) also let ByteBuffersDataOutput produce blocks under 8 bytes [read]",
   "introduced_date": "2021-01-06 (7b9f8751456); 2021-10-09 (61c15c8c10f, 6c6a3bd5bd5)",
   "first_affected_version": "9.0.0 [exec]; 8.11.0 and 8.11.4 not affected [exec]",
   "affected_versions": "9.0.0 to 10.6.0 (all 34 releases) and main [read]; 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2, 10.6.0 and main 645d4fe14a20 [exec]; 10.1.0 in the earlier study's release runs [exec]; 8.11.0 and 8.11.4 not affected [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-031.html",
   "repro": "repro/LFV-031/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-476",
   "priority": "low",
   "priority_rank": 1033,
   "novelty": "known",
   "withheld": false,
   "area": "store / ByteBuffersDataInput sequential reads (ByteBuffersDirectory, ByteBuffersIndexInput, NRTCachingDirectory RAM tier)",
   "title": "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)",
   "summary": "You write a file of more than 1 KiB to a ByteBuffersDirectory (say 1,030 bytes), seek to 2 bytes before the end and call readInt(), and expect an EOFException: readByte() and readBytes() of the same input throw it, NIOFSDirectory and MMapDirectory throw it for the same bytes, and BaseDirectoryTestCase#testIntsUnderflow requires it of every Directory. Instead readInt() throws an unchecked IndexOutOfBoundsException (at the exact end of a 2,048-byte input an ArrayIndexOutOfBoundsException), and readShort, readLong, readShorts and readInts do the same, while a file that fits in the first 1 KiB block still gives EOFException. The cause is the fast path added in 9.0.0 (LUCENE-10149): it checks the read against the block size (blockOffset + width <= blockMask), not against the end of the data in the last block, and reads with an absolute ByteBuffer get whose exception nothing translates.",
   "impact_class": "wrong error",
   "introduced_commit": "ba75dc5e6bf7e90b8c40906ba8ca7b258a5b39c0 (LUCENE-10149 = apache/lucene#11186 'ByteBuffersDataInput should override readShort/Int/Long', rmuir; committed directly from the issue's patch, no pull request, no CHANGES entry; the commit message says LUCENE-10150 by mistake, as the author's closing comment on the issue notes) added the readShort/readInt/readLong fast paths. The NRTCachingDirectory RAM tier reaches them only since e446904c614 (PR #13146, uschindler, 2024-02-29, first released in 10.0.0), which switched it to ByteBuffersDirectory.OUTPUT_AS_MANY_BUFFERS. [exec]",
   "introduced_date": "2021-10-06 (ba75dc5e6bf); 2024-02-29 for the NRTCachingDirectory RAM-tier surface (e446904c614)",
   "first_affected_version": "9.0.0 [exec] (tagged 2021-12-06; 7.5.0, 8.0.0, 8.10.0 and 8.11.4 throw EOFException [exec], and branch_8x never received LUCENE-10149; the NRTCachingDirectory RAM tier is affected from 10.0.0 [exec])",
   "affected_versions": "every release from 9.0.0 to 10.5.2 (33 releases), 10.6.0 (by reading) and main ea57360912ed; never fixed. [exec] the follow-up's version-portable main() probe (6 bug rows, 7 controls) gets 6 of 6 rows wrong on 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea; also -da on 9.0.0, 10.5.2 and main), with every control passing, and passes on 7.5.0, 8.0.0, 8.10.0 and 8.11.4 (8.11.4 also -da); the finder's JUnit fails 5 of 5 on main (-ea, -da), 10.5.2, 10.0.0 and 9.12.3; the independent reproduction's JUnit fails 5 of 8 on main (-ea, -da), 10.5.2 and 9.12.3; the finder's and the independent reproduction's main() variants fail on 9.0.0 and main (the finder's also on 9.1.0, 9.12.3 and 10.5.2) and pass on 8.11.4. NRTCachingDirectory RAM tier: EOFException on 9.0.0 to 9.12.3, where it used OUTPUT_AS_MANY_BUFFERS_LUCENE (ByteBufferIndexInput), and IndexOutOfBoundsException on 10.0.0, 10.5.2 and main [exec]. [read] the other releases 9.2.0 to 10.5.1 contain ba75dc5e6bf (git tag --contains) with byte-identical readShort/readInt/readLong and the same ByteBuffersIndexInput delegation; upstream main, branch_10x and branch_10_6 still have the three guards (checked 2026-10-26), so 10.6.0 (released 2026-10-29) is affected [read]. All runs on JDK 25, aarch64 Linux.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/570",
    "https://github.com/apache/lucene/issues/11992",
    "https://github.com/apache/lucene/issues/12948",
    "https://github.com/apache/lucene/issues/13981",
    "https://github.com/apache/lucene/issues/16500",
    "https://github.com/apache/lucene/issues/11186"
   ],
   "doc": "",
   "repro": "repro/LFV-476/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-130",
   "priority": "low",
   "priority_rank": 1034,
   "novelty": "new",
   "withheld": false,
   "area": "store / MMapDirectory (MemorySegmentIndexInput sequential reads and seek)",
   "title": "After a read hits EOF on a multi-chunk MMapDirectory input, seek() past EOF succeeds and later reads return bytes from the wrong offset",
   "summary": "You open a file that spans more than one mmap chunk with MMapDirectory (in the repro, a 40-byte file with 16-byte chunks), read until a read throws EOFException, and then seek the same input past the end, which IndexInput#seek says must throw EOFException. Instead seek(50) succeeds, getFilePointer() returns 50 and readByte() returns 34, the byte at offset 34, because the two EOF branches leave the cached chunk index one past the last chunk and seek() then checks the target against the wrong chunk. Every target in the window that mirrors the last chunk one chunk further on (48 to 56 here) is accepted this way, and a later clone() of the input throws java.lang.AssertionError for the same reason.",
   "impact_class": "wrong error",
   "introduced_commit": "0d89f3f6cf15 (trunk, svn r1599218, 'LUCENE-5722: Speed up MMapDirectory.seek() - first small patch for multi-mmap case', author uschindler; JIRA LUCENE-5722 is GitHub issue #6784, svn era, no PR; the commit equals the issue's LUCENE-5722-multiseek.patch attachment) and its branch_4x twin 1a72ded239fb (r1599219, same day, first release 4.9.0) added the same-buffer shortcut to ByteBufferIndexInput.seek(); the EOF branches that advance the chunk index past the last chunk before throwing are older (already in 3.6.2) and were harmless while seek() always indexed the buffer array; apache/lucene#912 (uschindler, merged 2022-09-26; 3b9c728ab558 on main, 5ffd6c059046 on branch_9x, 0384b4fcad78 on branch_9_4) carried both ingredients into MemorySegmentIndexInput, and #13146 (10.0.0) removed ByteBufferIndexInput, leaving MemorySegmentIndexInput as the only mmap input [read]",
   "introduced_date": "2014-06-02 (LUCENE-5722 commits on trunk and branch_4x); carried into MemorySegmentIndexInput on 2022-09-26 (#912 merged)",
   "first_affected_version": "4.9.0 [exec] (tagged 2014-06-24; ByteBufferIndexInput); for MemorySegmentIndexInput, the only mmap input on main: 9.10.0 on JDK 22+ [exec] (the 9.4.0-9.9.2 copies are selected only on JDK 19-21 and were checked by source only [read]) and every 10.x release [exec]",
   "affected_versions": "every lucene-core release from 4.9.0 through 10.6.0 (10.6.0 by reading), and main ea57360912ed: a core-only probe ran on all 130 final releases 4.0.0-10.5.2 on Maven Central and fails on all 114 releases from 4.9.0 on with the identical symptom (seek(50) on a 40-byte file accepted, getFilePointer()=50, readByte()=34), while it passes on all 16 releases 4.0.0-4.8.1 [exec]; the JUnit repro fails on 9.1.0, 9.9.2, 9.10.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da) [exec]; the independent reproduction's main() variant fails on 5.0.0, 5.5.5, 6.6.6, 7.7.3 and 8.11.4 [exec]; implementation exercised on JDK 25: ByteBufferIndexInput$DefaultImpl 4.9.0-5.2.1, ByteBufferIndexInput$MultiBufferImpl 5.3.0-9.9.2, MemorySegmentIndexInput$MultiSegmentImpl 9.10.0-10.5.2 and main; the MemorySegmentIndexInput copies in 9.4.0-9.9.2 have the same lines by source [read]; unaffected: 4.0.0-4.8.1 [exec] and 3.6.2 by source (seek() always indexes the buffer array) [read]; branch_10x and branch_10_6 carry the same lines [read], so 10.6.0 (released 2026-10-29) is affected [not executed]; not fixed upstream [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "",
   "repro": "repro/LFV-130/",
   "triage_status": "wont_fix",
   "triage_by": "Uwe Schindler (Lucene PMC)",
   "triage_date": "2026-10-29",
   "triage_link": "https://github.com/apache/lucene/issues/16937#issuecomment-6508981328",
   "triage_note": "Uwe Schindler explained that once a read or seek throws an IOException (EOFException included), an IndexInput's state is undetermined and it should no longer be used, so the later seek and read are not a bug; Uwe opened #16951 (documentation, milestone 11.0.0) to document this in IndexInput (and may still make it always throw EOFException if that is cheap), and on 2026-10-30 told a contributor who offered to write the javadoc change to go ahead and open a PR (none as of 2026-11-02). Uwe's comment names LFV-140 but links and describes this bug.",
   "triage_hide": true,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-129",
   "priority": "low",
   "priority_rank": 1035,
   "novelty": "known",
   "withheld": false,
   "area": "store / MMapDirectory read advice (PosixNativeAccess madvise, MemorySegmentIndexInput slices of closed inputs)",
   "title": "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)",
   "summary": "You clone an MMapDirectory input, close the original, and then slice the clone with an IOContext whose read advice is RANDOM or SEQUENTIAL (for example with setReadAdvice(ADVISE_BY_CONTEXT) and IOContext.DEFAULT.withHints(DataAccessHint.RANDOM)); like reading from the clone, which throws AlreadyClosedException, this should report that the input is closed. Instead the slice call throws java.lang.AssertionError: java.lang.IllegalStateException: Already closed, because PosixNativeAccess.madvise wraps every Throwable of the native posix_madvise call in an AssertionError before MemorySegmentIndexInput.advise() can turn the closed-arena IllegalStateException into AlreadyClosedException. It is an explicit throw, not an assert, so it happens with assertions disabled too; no data is read or written wrongly.",
   "impact_class": "wrong error",
   "introduced_commit": "cfbf8d93df81 (apache/lucene#13467 'Honor read advice on compound files.', author jpountz, merged on main 2024-06-21 before the 10.0 branch was cut) added IndexInput#slice(String, long, long, ReadAdvice) and made MemorySegmentIndexInput madvise every such slice through advise(), the first madvise call on an input that is already open, so a slice of a clone whose original was closed reaches the downcall on a closed arena [read]; the root-cause line, catch (Throwable th) { throw new AssertionError(th); } around the posix_madvise downcall, came earlier with a4055dae629d (apache/lucene#13196, author uschindler, 2024-03-25; 9.x backport 91b47531495e, #13213, first released in 9.11.0), when madvise ran only while a new file was mapped on a fresh arena; later narrowing: #13907 and #13917 (10.1.0: NORMAL advice and sub-page slices are no longer madvised), #14482/#14510 (10.3.0: slice(..., IOContext), advice from the directory's read-advice function) and #15040 (10.3.0: default read advice NORMAL); an unreleased prefetch window 3003731aa942 (#13337) to aac856a831af (#13381) in May 2024 is from code reading only",
   "introduced_date": "2024-06-21 (#13467 merged); the wrapper itself 2024-03-25 (#13196); reach narrowed 2024-10-15 (#13907, #13917) and 2025-08-08 (#15040, default read advice NORMAL)",
   "first_affected_version": "10.0.0 [exec]",
   "affected_versions": "every 10.x release, 10.0.0 through 10.6.0 (10.6.0 by reading), and main ea57360912ed; the 12 releases 10.0.0 through 10.5.2 and main all executed and failing [exec]: on 10.0.0 for any advice (NORMAL too) and any slice length; on 10.1.0-10.2.2 for a non-NORMAL ReadAdvice argument and a slice of at least one page, with a stock directory configuration; on 10.3.0-10.5.2 and main for a non-NORMAL read advice resolved from the IOContext (opt-in through setReadAdvice, for example ADVISE_BY_CONTEXT, or -Dorg.apache.lucene.store.defaultReadAdvice=random, both executed) and a slice of at least one page; main fails with -ea and -da [exec]; unaffected: 9.11.0 and 9.12.3 (the wrapper exists but no API madvises an already-open input; a probe passes and the repro does not compile) [exec], 9.10.0 and older have no PosixNativeAccess [read]; upstream main, branch_10x and branch_10_6 still contain the wrapper [read], so 10.6.0 (released 2026-10-29) is affected [not executed]; not fixed upstream [read]; every run was on aarch64 Linux with JDK 25 (macOS and x86 not run; Windows has no PosixNativeAccess and is not affected)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/13277",
    "https://github.com/apache/lucene/issues/13467",
    "https://github.com/apache/lucene/issues/15843",
    "https://github.com/apache/lucene/issues/15844",
    "https://github.com/apache/lucene/issues/16883",
    "https://github.com/apache/lucene/issues/13196"
   ],
   "doc": "",
   "repro": "repro/LFV-129/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-135",
   "priority": "low",
   "priority_rank": 1036,
   "novelty": "known",
   "withheld": false,
   "area": "store / MMapDirectory (MemorySegmentIndexInput absolute reads, error reporting)",
   "title": "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",
   "summary": "You take a random-access view of an MMapDirectory file that spans more than one mmap chunk, for example randomAccessSlice(33, 143) of a 191-byte file with 128-byte chunks, and call readBytes(pos, b, 0, 1) with a position past its end; you expect an EOFException naming that position, as readByte(pos) on the same view, a single-chunk view and NIOFSDirectory give. Instead readBytes(228, ...) throws an unchecked IllegalArgumentException 'read negative position (pos=-28)' and readBytes(314, ...) throws an EOFException naming position 58, because the method overwrites its position argument with the offset inside the chunk before its error handler reports it.",
   "impact_class": "wrong error",
   "introduced_commit": "c4694c31fde0 (apache/lucene#12600 'Add readBytes method to RandomAccessInput', issue #12599, author iverase, approved by uschindler, merged on main 2023-10-04; the masked position first reaches handlePositionalIOOBE in PR revision b47705f69efb 'remove readByteBoundaries method'; never backported to 9.x) added MemorySegmentIndexInput.readBytes(long, ...) with 'pos = pos & chunkSizeMask' ahead of the IndexOutOfBoundsException handler that reports pos; the other ingredient, MultiSegmentImpl.handlePositionalIOOBE subtracting the slice offset, is older (#11918, merged 2022-11-11, released in 9.4.2/9.5.0) and correct for every caller that existed before #12600; on main the method differs from 10.x only by #15033 (c485e4889d4, unused catch-parameter removal, no behaviour change) [read]",
   "introduced_date": "2023-10-04 (#12600 merged on main)",
   "first_affected_version": "10.0.0 [exec] (tagged 2024-10-09; the first release containing #12600)",
   "affected_versions": "every release from 10.0.0 through 10.5.2 (12 releases: 10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2), each executed and failing 2 of 2 with seed DEADBEEF and identical messages (10.5.2 also with -da), and main ea57360912ed (2 of 2 with -ea and -da) [exec], and 10.6.0 (by reading); the method body is byte-identical from c4694c31fde through 10.5.2 [read]; unaffected: every 9.x release, because RandomAccessInput#readBytes(long, byte[], int, int) does not exist there (the repro does not compile on 9.8.0, 9.9.0 and 9.12.3 [exec]; javap and source agree [read]), and a 9.x-compatible control (scalar absolute reads on the same view name the caller's position) passes on 9.8.0, 9.9.0, 9.12.3, 10.0.0, 10.5.2 and main [exec]; branch_10x and branch_10_6 carry the same lines [read], so 10.6.0 (released 2026-10-29) is affected [not executed]; not fixed upstream [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16804",
    "https://github.com/apache/lucene/issues/16145",
    "https://github.com/apache/lucene/issues/15892",
    "https://github.com/apache/lucene/issues/15556",
    "https://github.com/apache/lucene/issues/14156",
    "https://github.com/apache/lucene/issues/13981"
   ],
   "doc": "",
   "repro": "repro/LFV-135/",
   "triage_status": "confirmed",
   "triage_by": "Uwe Schindler (Lucene PMC)",
   "triage_date": "2026-10-29",
   "triage_link": "https://lists.apache.org/thread/cry1gb5bxr73vs4fk6td2rntvnpqlorr",
   "triage_note": "Uwe Schindler now plans to fix it: the wrong offset is reported through a private method that the subclass can override, and Uwe will post a PR. (Earlier on 2026-10-28 Uwe had suggested ignoring it.)",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-480",
   "priority": "low",
   "priority_rank": 1037,
   "novelty": "new",
   "withheld": false,
   "area": "store / BufferedIndexInput.SlicedIndexInput (BufferedIndexInput.wrap and the default slice())",
   "title": "Inputs from BufferedIndexInput.wrap and the default BufferedIndexInput.slice accept seek and skipBytes past the end instead of throwing EOFException",
   "summary": "You take 20 bytes of a file with BufferedIndexInput.wrap(\"w\", in, 10, 20), or a slice of a BufferedIndexInput subclass that keeps the default slice(), call seek(21) or skipBytes(21), and expect the EOFException that IndexInput#seek promises for a position beyond the end and that the stock Directories' inputs and slices throw in normal use. Instead the call succeeds and getFilePointer() returns 21; only the next read throws EOFException. The cause is the empty SlicedIndexInput.seekInternal: BufferedIndexInput.seek hands every target outside its buffer to seekInternal, and only readInternal checks the slice's length.",
   "impact_class": "minor",
   "introduced_commit": "7aeac4f07b35d663009f946e07fb7bd3c90757a3 (trunk, svn r1595480) and its branch_4x backport 3c8d05ca062944b1a95b25a517a37d29f5ee21e9 (svn r1599274), which 4.9.0 shipped: LUCENE-4371 'Replace IndexInputSlicer with IndexInput.slice' (rmuir; JIRA and svn era, no PR; the issue is now apache/lucene#5437). It added the public static BufferedIndexInput.wrap and the default BufferedIndexInput.slice(), both returning the private SlicedIndexInput, whose empty 'protected void seekInternal(long pos) {}' it moved from Directory.SlicedIndexInput [read]. The behaviour became a contract violation with ddc65d977f920013c5fca16c8ac75ae2c6895f9d (svn r1726039; branch_5x aa1a0cf3be8a), LUCENE-6932 (apache/lucene#7990), which wrote the IndexInput#seek EOFException sentence and fixed the RAM, NIOFS, SimpleFS and RAF inputs but not SlicedIndexInput [exec]. The deferred check itself is older: Directory.SlicedIndexInput (LUCENE-3218, 28f59a2e056, 4.0.0-4.8.1, executed on 4.8.1) and CompoundFileReader.CSIndexInput (1.4-3.0.0 tags) [read]",
   "introduced_date": "2014-05-17 (LUCENE-4371 on trunk; branch_4x backport 2014-06-02); 2016-01-21 (LUCENE-6932 wrote the contract it violates)",
   "first_affected_version": "5.5.0 [exec] (tagged 2016-02-20), the first release whose IndexInput#seek promises EOFException; 4.9.0 to 5.4.1 show the same lenient seek [exec] but had no such contract (a stock RAMDirectory input accepted a seek past the end there too); 4.8.1 and older lack wrap() and IndexInput.slice [exec]",
   "affected_versions": "every release from 5.5.0 to 10.6.0 and main ea57360912ed; never fixed. [exec] portable main() ports and the JUnit repro accept the illegal seek of wrap() inputs and default slices on 5.5.0 (-ea and -da), 5.5.5, 6.0.0, 6.6.6, 7.7.3, 8.0.0, 8.5.2, 8.6.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.5.2 (-ea and -da) and main (-ea and -da); the skipBytes variant exists only from 9.0.0, because LUCENE-9480 made IndexInput.skipBytes call seek (8.11.4 and older read the bytes and throw EOFException). In-tree reach through opt-in DirectIODirectory slices, which returned BufferedIndexInput.wrap: 9.0.0 to 10.1.x [exec], gone from 10.2.0 (#14103) [read]. [read] the releases between the executed ones carry the same empty seekInternal (the class changed only in LUCENE-5681, LUCENE-9271, LUCENE-9570 and #14126, none touching seekInternal); upstream main f4cc6ac2097c and branch_10x 657014b3c579 still have it (read 2026-10-26); 10.6.0 (released 2026-10-29) fails the one-test minimal repro on its release jars (SHA-1 checked against Maven Central, -ea and -da, 2026-11-01) [exec]. All runs: JDK 25, SHA-1-verified release jars from Maven Central",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-480.html",
   "repro": "repro/LFV-480/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-060",
   "priority": "low",
   "priority_rank": 1038,
   "novelty": "new",
   "withheld": false,
   "area": "search / scoring",
   "title": "MaxScoreBulkScorer can skip a document whose score equals the minimum competitive score (1-ulp rank inversion)",
   "summary": "You run a top-k disjunction of 4 or more SHOULD clauses whose clause scores span more than 2^29. You expect every document that is competitive by its own score to be collected. Instead the required-clause test skips MathUtil.sumUpperBound, so a document whose score equals minCompetitiveScore can be dropped and the top hits change by one rank.",
   "impact_class": "silent wrong results",
   "introduced_commit": "#12589 (611bbbd9512)",
   "introduced_date": "2023-10-24",
   "first_affected_version": "9.9.0 [read]",
   "affected_versions": "9.9.0+ [read]; main [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-060.html",
   "repro": "repro/LFV-060/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-079",
   "priority": "low",
   "priority_rank": 1039,
   "novelty": "known",
   "withheld": false,
   "area": "codecs / vectors",
   "title": "Quantized MIP score of a document equal to its segment centroid is 3.0 instead of 3.5",
   "summary": "With the OSQ format and MAXIMUM_INNER_PRODUCT, you score a document whose vector equals its segment's centroid. You expect the exact inner-product score (3.5 in the repro). Instead float32 absorption in the corrective tail gives 3.0.",
   "impact_class": "silent wrong results",
   "introduced_commit": "unknown (not yet bisected)",
   "introduced_date": "unknown (not yet bisected)",
   "first_affected_version": "unknown (not yet bisected)",
   "affected_versions": "10.5.2 and main [exec]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15408",
    "https://github.com/apache/lucene/issues/15411"
   ],
   "doc": "",
   "repro": "repro/LFV-079/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-095",
   "priority": "low",
   "priority_rank": 1040,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter doc-values updates",
   "title": "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",
   "summary": "You use index sorting with a parent field (IndexWriterConfig#setParentField) and document blocks, and call IndexWriter#updateNumericDocValue or #updateDocValues on that parent field, for example to give a child document a parent mark or to set a parent's mark to null. You expect the call to be rejected with IllegalArgumentException, as IndexWriter rejects doc-values updates of index-sort fields and any document that contains the parent field ('is a reserved field'), or else the index to stay valid. Instead the update is accepted: a child given a mark can put the segment out of index-sort order, so CheckIndex fails ('segment has indexSort=<long: \"sort\"> but docID=1 sorts after docID=2') as soon as the update is committed, and a removed mark makes the next merge throw EOFException in MultiSorter and close the writer when the unmarked block was the last of its segment and every document there has a sort value, and otherwise silently moves the orphaned documents into the next block.",
   "impact_class": "data corruption",
   "introduced_commit": "df6bd25ce44 (#12829 'Add support for index sorting with document blocks', main, first released in 10.0.0); its branch_9x backport 0aa88910ca9 shipped first, in 9.10.0 [read]; not a regression: #12829 created the parent field and a document-path 'reserved field' check but no check in the doc-values update methods, whose only guard is the index-sort-field check from LUCENE-7581 (4efbde4e762, 2016); no later commit opened or closed the gap",
   "introduced_date": "2024-01-11 (#12829 merged into main as df6bd25ce44; the branch_9x backport 0aa88910ca9 was committed 2024-01-17, author date 2024-01-11)",
   "first_affected_version": "9.10.0",
   "affected_versions": "all 19 releases from 9.10.0 through 10.5.2 (9.10.0, 9.11.0, 9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2) and main ea57360912ed (unreleased 11.0.0) [exec]; 10.6.0 (released 2026-10-29): the one-test minimal repro fails on its release jars (SHA-1 checked against Maven Central, -ea and -da, 2026-11-01) [exec]; 9.9.2 and earlier not affected (no IndexWriterConfig#setParentField; the repro does not compile on 9.9.2) [exec]; only a writer configured with a parent field can reach it; IndexWriter accepts one on an existing index only if the index has that field or no fields at all (#13016, #13341) [read]; not fixed upstream as of main ea57360912ed [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-095.html",
   "repro": "repro/LFV-095/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-108",
   "priority": "low",
   "priority_rank": 1041,
   "novelty": "known",
   "withheld": false,
   "area": "index / merge setup (MergeState merge instances, KnnVectorsReader finishMerge lifecycle)",
   "title": "If merge setup throws, the vectors merge instances obtained so far never get finishMerge (MergeState constructor and PerFieldKnnVectorsFormat merge copy constructor)",
   "summary": "You merge segments that have vectors (forceMerge, a background merge or addIndexes(CodecReader...)) and the merge fails while it is being set up, after it already took a vectors merge instance from one source segment or one vector field, for example because re-opening a data file for sequential reads throws an IOException. You expect every merge instance obtained with KnnVectorsReader#getMergeInstance to get its finishMerge call on this failure too, as #14977 ('always called regardless of merge outcome'), the 10.6.0 CHANGES entry for GITHUB#14930 ('including exceptional exits') and the test framework's AssertingKnnVectorsReader close check (mergeInstanceCount == finishMergeCount) say. Instead the failure happens inside new SegmentMerger(...) (the MergeState constructor) or inside the PerFieldKnnVectorsFormat merge copy constructor, before IndexWriter enters the try/finally that calls cleanupMerge, so the instances already obtained never get finishMerge (obtained=1, finished=0); stock formats on main see no effect because their finishMerge does nothing.",
   "impact_class": "minor",
   "introduced_commit": "46204f6b53c5 on main (branch_10x backport 7c5a9deaf9e, same day), PR #13985 'Introduces IndexInput#updateReadAdvice to change the ReadAdvice while merging vectors' (shatejas): it added KnnVectorsReader#finishMerge, the PerFieldKnnVectorsFormat.FieldsReader merge copy constructor (getMergeInstance per field, no cleanup) and the only caller, at the end of KnnVectorsWriter#merge, so from the start a setup failure skipped finishMerge [read]. It became a separate defect, no longer part of a wider known bug, with 085a0ae054b1 on main (#14977, 'Move finishMerge to a finally block so it always runs', resolves #14930) and its branch_10x backport 8383eb54f80d (#16481): both put the try/finally that calls SegmentMerger#cleanupMerge after 'new SegmentMerger(...)' [read]",
   "introduced_date": "2024-11-22 (46204f6b53c, the gap comes with the API); 2025-09-17 on main (085a0ae054b) and 2026-08-07 on branch_10x (8383eb54f80): the setup path becomes the only uncovered exit",
   "first_affected_version": "10.6.0 (released 2026-10-29) as a distinct defect; it also ships in 11.0.0 (main) unless fixed first [exec]. The path itself is in every release since 10.1.0 [exec], where it is part of known #14930 (10.1.0-10.4.0) or known #16419 (10.5.0-10.5.2)",
   "affected_versions": "As a distinct defect: main from 085a0ae054b through ea57360912ed [exec], branch_10_6 [exec] and branch_10x from 8383eb54f80 through 657014b3c579 [exec]; there the version-independent history repro fails exactly the 3 setup-failure tests and the strict AssertingCodec close check (4 of 7; -da 3 of 6), while both controls and the merge-body-failure test pass. Inside known bugs: 10.1.0, 10.2.2, 10.3.0, 10.4.0 and main 71ea58a3241 [exec]; 10.5.0 and 10.5.2 (-ea and -da) [exec]; 10.2.0, 10.2.1, 10.3.1, 10.3.2 and 10.5.1 [read]. Not affected because the API does not exist: 10.0.0 and 9.12.3 [exec] and the other 9.x releases [read]. Not fixed at main 645d4fe14a2 or branch_10x 657014b3c579 [exec]; branch_10_6 4ae946e5a9b unchanged [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/14930",
    "https://github.com/apache/lucene/issues/14977",
    "https://github.com/apache/lucene/issues/16481",
    "https://github.com/apache/lucene/issues/16419",
    "https://github.com/apache/lucene/issues/16883",
    "https://github.com/apache/lucene/issues/14631"
   ],
   "doc": "",
   "repro": "repro/LFV-108/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-575",
   "priority": "low",
   "priority_rank": 1042,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexWriter point-in-time merges (merge-on-commit, merge-on-getReader: the preparePointInTimeMerge OneMerge wrapper and the OneMerge lifecycle hooks)",
   "title": "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)",
   "summary": "You install a merge policy whose OneMerge subclass overrides the public mergeInit hook (for example to start a timer or set up per-merge state that mergeFinished later releases) and let IndexWriter merge on commit or on getReader, which it does by default since 9.3.0. You expect that OneMerge to get mergeInit when the merge starts and mergeFinished when it ends, as the same OneMerge does when it comes from findMerges or forceMerge. Instead IndexWriter wraps the policy's merge in its own OneMerge that forwards mergeFinished and the other hooks but not mergeInit, so the policy's OneMerge sees mergeFinished(success=true) for a merge that ran and committed and never sees mergeInit (in the repro: mergeInit=0, mergeFinished=1 for the merge on commit and on getReader; 1 and 1 for forceMerge).",
   "impact_class": "minor",
   "introduced_commit": "7f352a96659b4d304ae3ef0c7a1b62784ce2a406 (main) and its branch_8x backport 9b1c92809e7 (shipped in 8.6.0): apache/lucene-solr#1617, LUCENE-8962 'Merge small segments on commit' (GitHub issue #10005; author s1monw, co-authors msfroh, msokolov and mikemccand; merged 2020-06-27), which created the wrapper new MergePolicy.OneMerge(toWrap.segments) with mergeFinished and wrapForMerge forwarding ('// must delegate') and no mergeInit override [read]. The defect was there when the wrapper was created, not a later regression: OneMerge#mergeInit had been public since LUCENE-7700 (9540bc37583, 2017, first released 6.5.0 / 7.0.0). Two earlier merge-on-commit attempts were reverted before any release (043c5dff6f4 #1155, whose wrapper forwarded no hook; 972c84022ec #1552, same shape as #1617). Later changes kept the gap: 8294e1ae206 (#1623, 8.7.0) reused the wrapper for getReader as preparePointInTimeMerge and added onMergeComplete forwarding; b5795db0cf5 (LUCENE-10078, 9.3.0) made the full-flush wait 500 ms by default; f7cab164501 (#12622, 9.9.0) switched to the wrapping constructor and added reorder ('// must delegate') and setMergeInfo forwarding; no commit on main or branch_8x has ever contained toWrap.mergeInit (git log -G)",
   "introduced_date": "2020-06-27",
   "first_affected_version": "8.6.0 [exec] (merge on commit; the getReader path from 8.7.0 [exec]); 8.5.2 and older not affected [exec]",
   "affected_versions": "every release from 8.6.0 to 10.6.0 and main (645d4fe14a20, a9779ef3c193 and the previous main ea57360912ed). [exec] the minimal test (ported for 8.6.0-9.0.0 and 9.1-9.2) fails on all 50 releases from 8.6.0 to 10.6.0 (the history step, 2026-11-01), and on main 645d4fe14a20 with -ea and -da. [exec] the finder's JUnit or its 8.x/9.0 variant fails on 8.6.0 and 8.6.3 (commit path only; no GET_READER there), 8.7.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2, main ea57360912ed and main a9779ef3c193, with the forceMerge control passing everywhere; [exec] main a9779ef3c193; the independent reproduction's own JUnit also fails on 10.5.2, 9.12.3, 8.11.4 and 8.7.0; the default-settings test (stock LogDocMergePolicy, only findMerges customised, default wait) passes on 9.2.0 (default wait 0, no merge on commit) and fails on 9.3.0 and main. [read] the wrapper has no mergeInit override at every release tag in the history clone. Reach: opt-in (an explicit full-flush wait > 0) in 8.6.0-9.2.x, on by default from 9.3.0. Not fixed upstream [read]. Executed on aarch64 with JDK 25 only",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-575.html",
   "repro": "repro/LFV-575/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-090",
   "priority": "low",
   "priority_rank": 1043,
   "novelty": "new",
   "withheld": false,
   "area": "memory / MemoryIndex vectors",
   "title": "MemoryIndex.addField throws AssertionError under -ea for a KnnFloat16VectorField, because a stale assertion in storeVectorValues predates the FLOAT16 branch",
   "summary": "You add a KnnFloat16VectorField to a MemoryIndex, through MemoryIndex.addField or MemoryIndex.fromDocument, with Java assertions enabled. You expect it to be stored and readable through getFloat16VectorValues, like a float32 or byte vector field, because MemoryIndex has a FLOAT16 storage branch and a FLOAT16 reader. Instead the first statement of storeVectorValues asserts that the field is a KnnFloatVectorField or a KnnByteVectorField, so the call throws AssertionError before the FLOAT16 branch runs; with assertions disabled the vector is stored and read back exactly.",
   "impact_class": "minor",
   "introduced_commit": "#16383 (bfe5c847d3c) [read]; the assertion line itself was written by #13633 (9e831ee8097, 2024-08-07) and was correct then, when only the float32 and byte vector field classes existed",
   "introduced_date": "2026-07-27",
   "first_affected_version": "unreleased (main and the 11.0 release branch branch_11x, 11.0.0-SNAPSHOT; no release tag contains bfe5c847d3c)",
   "affected_versions": "main from bfe5c847d3c (2026-07-27) through 645d4fe14a20 [exec]; branch_11x (cut 2026-10-29 for 11.0.0) has the same MemoryIndex.java [read]; 10.6.0, 10.5.2 and 9.12.3 not affected (no float16 vector API, the repro does not compile) [exec]; 9.12.0, 9.12.3, 10.0.0 and 10.5.2 carry the same two-class assertion, which is correct there (a float32/byte control passes under -ea) [exec]; branch_10x and branch_10_6 have no KnnFloat16VectorField [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-090.html",
   "repro": "repro/LFV-090/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-092",
   "priority": "low",
   "priority_rank": 1044,
   "novelty": "new",
   "withheld": false,
   "area": "queries / function vector sources",
   "title": "ConstKnnFloat16ValueSource accepts Inf/NaN float16 query vectors that its float32 twin ConstKnnFloatValueSource rejects (missing VectorUtil.checkFiniteFloat16)",
   "summary": "You build a ConstKnnFloat16ValueSource from a float16 query vector that contains an infinity or NaN half and score it against a KnnFloat16VectorField with a FunctionQuery over Float16VectorSimilarityFunction. You expect the constructor to throw IllegalArgumentException, as its float32 twin ConstKnnFloatValueSource does (VectorUtil.checkFinite) and as KnnFloat16VectorQuery and KnnFloat16VectorField do for the same halves (VectorUtil.checkFiniteFloat16). Instead the constructor only null-checks the array, so with -ea scoring later fails with an AssertionError inside VectorUtil (no message for EUCLIDEAN; 'not finite: ... from <raw shorts>' for DOT_PRODUCT and MAXIMUM_INNER_PRODUCT; COSINE silently scores 0), and with -da documents score 0 through FunctionQuery's intended NaN/negative clamp or, for DOT_PRODUCT and MAXIMUM_INNER_PRODUCT with an infinite component, +Infinity.",
   "impact_class": "wrong error",
   "introduced_commit": "bfe5c847d3c (#16383 'Add fp16 (float16) vector encoding') [read]; not a regression: the class has never validated, while its float32 twin has validated since 14c18d86245 (#12253, 2023-06-14)",
   "introduced_date": "2026-07-27",
   "first_affected_version": "unreleased (main and the 11.0 release branch branch_11x, 11.0.0-SNAPSHOT; no release tag contains bfe5c847d3c)",
   "affected_versions": "main from bfe5c847d3c (2026-07-27) through 645d4fe14a2 [exec]; branch_11x 603af870375 has the identical file [read]; 10.5.2, 10.5.0, 9.12.3 and the parent 606a26dafd55 not affected (no FLOAT16 API, the repro does not compile) [exec]; the float32 twin rejects non-finite vectors on 9.12.3, 10.5.0, 10.5.2, 606a26dafd55, bfe5c847d3c and main [exec]; branch_10x 657014b3c57 and branch_10_6 4ae946e5a9b do not have the class [read]; not fixed upstream as of main 645d4fe14a2 [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-092.html",
   "repro": "repro/LFV-092/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-084",
   "priority": "low",
   "priority_rank": 1045,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / vectors",
   "title": "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",
   "summary": "You index finite FLOAT16 vectors with large components (for example 60000) in the Lucene104 scalar-quantized format, then drop the raw vectors the way the format's own tests do (simulateEmptyRawVectors), so reads go through the dequantized fp16 view. You expect getFloat16VectorValues().vectorValue() to return an approximation of each stored vector, and full-precision rescoring with a document's own vector to rank that document first. Instead OptimizedScalarQuantizer.deQuantize(byte[], short[], ...) narrows a slightly out-of-range float reconstruction to fp16 without saturating, so 60000 comes back as Infinity, and rescoring gives the exact match the score 0.0 and ranks it last (with -ea, an AssertionError in VectorUtil.squareDistance).",
   "impact_class": "silent wrong results",
   "introduced_commit": "#16473 (50c1e6acb7f) [read]",
   "introduced_date": "2026-08-26",
   "first_affected_version": "unreleased (main and branch_11x, 11.0.0-SNAPSHOT; no release tag contains 50c1e6acb7f)",
   "affected_versions": "main from 50c1e6acb7f (2026-08-26) through 645d4fe14a2 [exec]; 10.5.2 and 9.12.3 not affected (no fp16 vector API, the repro does not compile) [exec]; branch_10x 657014b3c57 and branch_10_6 4ae946e5a9b have no FLOAT16 encoding and no fp16 deQuantize [read]; branch_11x 603af870375 contains 50c1e6acb7f and has both files unchanged [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-084.html",
   "repro": "repro/LFV-084/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-085",
   "priority": "low",
   "priority_rank": 1046,
   "novelty": "known",
   "withheld": false,
   "area": "codecs / vectors",
   "title": "With raw vectors dropped from a Lucene104 scalar-quantized field, rescorer().bulk() reads quantized bytes as float32 vectors and returns wrong scores",
   "summary": "You drop the raw float vectors from a Lucene104 scalar-quantized field (the read-only fallback added by #15415), open the index with MMapDirectory and the Panama vector provider, and score documents with FloatVectorValues#rescorer(q).bulk(...). You expect the same scores as rescorer(q).score(), which compares the query with each document's dequantized vector. Instead bulk() reads the quantized .veq bytes as if they were float32 vectors at the wrong stride and returns, for example, 8.9e-16 instead of 0.84, or NaN, 0.0 or huge values such as 5.3e37; with the 1-bit and 2-bit encodings it throws instead (IndexOutOfBoundsException from bulk(), or IllegalArgumentException when the rescorer is created).",
   "impact_class": "silent wrong results",
   "introduced_commit": "683f59f66b9f (#15474 'Use bulk scoring new osq', 10.x backport 01093318981): added the view's bulk() overrides; parent 94312d0f3739 passes, 683f59f66b9f fails [exec]. Root cause one step earlier: ba455f2bae13 (#15415, 10.x backport eb0173245c8) made the dequantizing view advertise HasIndexSlice over the quantized records with getVectorByteLength() = dimension [exec]",
   "introduced_date": "2025-12-08 (#15474); root cause 2025-11-13 (#15415)",
   "first_affected_version": "10.4.0 [exec]",
   "affected_versions": "10.4.0, 10.5.0, 10.5.1, 10.5.2 and main ea57360912ed [exec]; branch_10x and branch_10_6 heads (2026-10-24) [read]; not applicable to 10.3.2 and earlier, including 9.12.3 (API absent, the repro does not compile) [exec]; #16415 (10.5.1) narrowed it: scorer() fixed, rescorer() still affected",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16030",
    "https://github.com/apache/lucene/issues/16415"
   ],
   "doc": "",
   "repro": "repro/LFV-085/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-065",
   "priority": "low",
   "priority_rank": 1047,
   "novelty": "known",
   "withheld": false,
   "area": "codecs / vectors",
   "title": "PACKED_NIBBLE quantized vectors with an odd dimension fail once raw vectors are dropped",
   "summary": "You use PACKED_NIBBLE scalar quantization with an odd vector dimension and drop the raw vectors. You expect vectorValue() and full-precision rescoring to work from the quantized data. Instead every vectorValue() call and every rescore throws (IllegalArgumentException on 10.6.0 and main; on 10.4.0 to 10.5.2 ArrayIndexOutOfBoundsException with assertions off).",
   "impact_class": "crash",
   "introduced_commit": "#15415 (ba455f2bae1)",
   "introduced_date": "2025-11-13",
   "first_affected_version": "10.4.0 [exec]",
   "affected_versions": "10.4.0, 10.5.0, 10.5.1, 10.5.2 and 10.6.0 [exec]; main 645d4fe14a20 [exec]; 10.3.2 and older not affected (no lucene104 codec) [exec]; branch_10x 657014b3c57 and branch_10_6 4ae946e5a9b: OffHeapScalarQuantizedFloatVectorValues.java identical to 10.5.2 [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16030"
   ],
   "doc": "bugs/LFV-065.html",
   "repro": "repro/LFV-065/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-112",
   "priority": "low",
   "priority_rank": 1048,
   "novelty": "new",
   "withheld": false,
   "area": "index / SortingCodecReader re-sort (index sorting with document blocks)",
   "title": "With assertions enabled, re-sorting an index with document blocks through SortingCodecReader and addIndexes fails SortingCodecReader's cache assertion for the parent field",
   "summary": "You re-sort an index that uses document blocks and a parent field (IndexWriterConfig#setParentField) the way the SortingCodecReader javadoc describes: wrap each segment with SortingCodecReader.wrap(reader, newSort) and pass the wrapped readers to IndexWriter#addIndexes(CodecReader...) of a fresh writer with the new index sort and the same parent field. You expect the re-sort to succeed, as it does with assertions disabled (the result is then correctly sorted with every block intact) and as it does for an index without blocks. Instead, with Java assertions enabled (-ea), addIndexes throws AssertionError 'only sort fields should be cached twice but [_parent] is not a sort field' and the destination writer closes, because MultiSorter reads the parent field's doc values once to find the blocks and the doc-values merge reads them again, while SortingCodecReader's internal check allows a second read only for sort fields.",
   "impact_class": "minor",
   "introduced_commit": "df6bd25ce44 (#12829 'Add support for index sorting with document blocks', main, first released in 10.0.0); its branch_9x commit 0aa88910ca9 shipped first, in 9.10.0 [read]; #12829 added the parent field and MultiSorter's read of it but did not touch SortingCodecReader, whose single-entry doc-values cache and sort-field-only assertCreatedOnlyOnce allow-list are older (LUCENE-9539, 17c285d6174 on main and 427e11c7f64 on branch_8x, 2020-09-23, first released in 8.7.0) and were never extended to the parent field [read]; so the bug is the interaction and exists from the first commit at which it can be expressed",
   "introduced_date": "2024-01-11 (#12829 merged into main as df6bd25ce44; the branch_9x commit 0aa88910ca9 was committed 2024-01-17, same author date); 9.10.0 tagged 2024-02-20",
   "first_affected_version": "9.10.0 [exec]",
   "affected_versions": "all 19 releases from 9.10.0 through 10.5.2 (9.10.0, 9.11.0, 9.11.1, 9.12.0-9.12.3, 10.0.0, 10.1.0, 10.2.0-10.2.2, 10.3.0-10.3.2, 10.4.0, 10.5.0-10.5.2) and main ea57360912ed (unreleased 11.0.0), with -ea only [exec]; with -da the re-sorted index is correct on 9.10.0, 9.12.3, 10.5.2 and main [exec]; 9.9.2 and earlier not applicable (no IndexWriterConfig#setParentField; the repro does not compile on 9.9.2, and the re-sort without blocks passes there) [exec]; the failing call site moved but the assertion did not change: with two or more sort fields, 9.10.0-10.4.0 already fail inside MultiSorter.sort, and from 10.5.0 (#16202, e6f12f31d08, backport 5a3ec9ad9d8) the second read is always the doc-values merge [exec]; 10.6.0 (released 2026-10-29) fails with -ea (9 of 9 runs) and passes with -da [exec], and the unreleased branch_10x has the same allow-list and the same parent read [read]; main 645d4fe14a20 fails with -ea (9 of 9 runs) and passes with -da [exec]; not fixed upstream as of main 2f424fd428da (2026-10-30) [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-112.html",
   "repro": "repro/LFV-112/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-821",
   "priority": "low",
   "priority_rank": 1049,
   "novelty": "known",
   "withheld": false,
   "area": "suggest / document (NRT) suggester (ContextQuery: ContextCompletionWeight.setInnerWeight when the inner automaton accepts the empty string)",
   "title": "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)",
   "summary": "You index suggestions in a ContextSuggestField and query them with a RegexCompletionQuery such as '.*' or 'z*' (or a FuzzyCompletionQuery with nonFuzzyPrefix 0 whose edit budget covers the whole prefix); you expect what a plain SuggestField returns for the same query, here every suggestion. Instead, with Java assertions enabled, the suggest call throws 'AssertionError: input should not end with the context separator': the inner automaton accepts the empty string, so the matched path ends right at the context separator, which ContextQuery's setInnerWeight asserts cannot happen. Upstream fixed this assertion in 2018 (LUCENE-8287) only for an empty regex text; with assertions disabled the results are correct.",
   "impact_class": "minor",
   "introduced_commit": "be4d58c7740bea4e797eb1acff6355eb260e7c93 (LUCENE-6459 'add common suggest API for document based NRT suggester', Areek Zillur via Mike McCandless, trunk, svn era with no pull request; issue now apache/lucene#7518; branch_5x backport 380bb29f39595de1c3947075296d1d0a36f02fd8 the same day, identical ContextQuery.java) [read]. That commit added the composed automaton (contexts + CONTEXT_SEPARATOR + optional SEP_LABEL + inner), the assertion in the all-contexts branch and the automatic rewrite into ContextQuery; the stop-at-first-accept prefix intersection FSTUtil.intersectPrefixPaths is older (LUCENE-6339, 5.1). The named-context (addContext) trigger came with LUCENE-6702 (f8ae631751ae98ca770d8f387793d9846db62c48 trunk / 4a44bd9a50969cedfd0227749827aacc0a9578fc branch_5x, 2015-07-30, apache/lucene#7760), which moved both branches into the shared setInnerWeight [exec]. Not a regression: the defect is as old as the API. LUCENE-8287 (master 0159e4b974b / branch_7x b6b30500036, 2018, in 7.4.0) removed only the empty-regex-text trigger, and beb163c9160 (lucene-solr#383, merged 2021-01-02, 9.0.0) added an Operations.isEmpty short-cut that only catches inner automata that accept nothing",
   "introduced_date": "2015-05-28 (be4d58c7740 and 380bb29f395); named-context trigger 2015-07-30 (LUCENE-6702); first release 5.3.0 (tag commit 2015-08-20)",
   "first_affected_version": "5.3.0 [exec] (the first release with ContextQuery: with -ea all 4 bug cases of the history probe throw the AssertionError, both controls pass; with -da the results are correct). 5.2.0 and 5.2.1 have no ContextQuery, CompletionQuery, RegexCompletionQuery or FuzzyCompletionQuery, so the probe does not compile there [exec]: not affected",
   "affected_versions": "every release from 5.3.0 through 10.5.2 (103 releases, each executed with -ea: 5.3.0-5.5.5, 6.0.0-6.6.6, 7.0.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2) and main a9779ef3c193 [exec]. Only with assertions enabled: with -da the probe passes on 13 sampled versions from 5.3.0 to main [exec]. 10.6.0 (branch_10_6 at 4ae946e5a9b) and the unreleased branch_10x differ from main in ContextQuery, RegexCompletionQuery and FuzzyCompletionQuery only by a javadoc tag [read], so 10.6.0 is affected too. Not fixed upstream as of origin/main 20ced71c1e6e (2026-10-27) [read]. LUCENE-8287 changed only the empty-regex-text trigger: up to 7.3.1 it trips the same assertion, from 7.4.0 it returns no suggestions on either field [exec]. Caveats: every release ran on JDK 25, not the JVM it targeted (the controls pass in each run); 8.8.2-8.11.4 ran from verified release jars because the history clone has no tags for them",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-8287",
    "https://issues.apache.org/jira/browse/LUCENE-8288"
   ],
   "doc": "",
   "repro": "repro/LFV-821/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-697",
   "priority": "low",
   "priority_rank": 1050,
   "novelty": "new",
   "withheld": false,
   "area": "misc / document: LazyDocument (lazy loading of stored fields, multi-valued fields)",
   "title": "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",
   "summary": "For a document whose stored field f has the values v0 and v1, you call LazyDocument.getField(f), read the returned field, then call getField(f) again and read the second one; getField's own comment says the document is re-fetched when more lazy fields are requested after others were loaded, so you expect v0 and then v1. With assertions enabled the first read instead throws AssertionError 'More lazy values then real values for field: f', because fetchRealValues asserts realValues.length <= lazyValues.size() (LazyDocument.java:113-114), the reverse of what its message and the loop right after it (:116-121, which reads realValues[i] once per lazy value) need. With -da the same calls return v0 and v1, and the case the message describes (more getField calls than stored values) passes the assertion and fails with ArrayIndexOutOfBoundsException in both modes.",
   "impact_class": "minor",
   "introduced_commit": "ad81236c7d52fac6f681b670055a22d3e13ab3ee (SOLR-4589, svn r1458887 on trunk, by hossman, 'Fixed CPU spikes and poor performance in lazy field loading of multivalued fields'; Subversion era, no pull request): it replaced the per-value ordinal lookup with fetchRealValues and added the assertion with the reversed condition; backports 29756e22101 (lucene_solr_4_2, r1458959, first release 4.2.1) and dfd2d1f49cd (branch_4x, r1458938, 4.3.0). The condition and message never changed afterwards (later commits only renamed types, reformatted, and moved the package in 9.0.0) [read]",
   "introduced_date": "2013-03-20",
   "first_affected_version": "4.2.1 [exec] (4.2.0 and 4.0.0 not affected [exec]; LazyDocument first shipped in 4.0.0-alpha with an ordinal-based implementation that had neither fetchRealValues nor the assertion)",
   "affected_versions": "Every release from 4.2.1 to 10.6.0 and main (a9779ef3c193, 645d4fe14a20), only with assertions enabled [exec]. With -da every executed version returns the right values. Not fixed: upstream main a95c754ee003 (2026-10-26), branch_10x and branch_10_6 still have the reversed condition, and no open PR touches LazyDocument.java [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-697.html",
   "repro": "repro/LFV-697/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-761",
   "priority": "low",
   "priority_rank": 1051,
   "novelty": "known",
   "withheld": false,
   "area": "util / BKD points (BKDReader.BKDPointTree navigation: visitDocIDs/visitDocValues on a leaf reset the inner-node input; default points format)",
   "title": "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)",
   "summary": "You index points with the default codec, take a PointTree from PointValues.getPointTree(), go down to a leaf, visit its documents (visitDocIDs or visitDocValues), call moveToParent() and then visit the parent or call moveToChild() again, which the API has allowed since LUCENE-10262 (Lucene 9.1, 'This change allows random navigation of a PointValues#PointTree'), and expect the parent's documents or its first child. Instead, with assertions enabled, that next call throws AssertionError in BKDReader.BKDPointTree.resetNodeDataPosition (BKDReader.java:401): the leaf visit had reset the reader's inner-node input to a saved position that readNodeData writes only for inner nodes, so for a leaf it is stale (0 on a fresh tree), and the parent then finds the input behind its own saved position. With assertions disabled every later read seeks to an absolute position first, so all results are correct and only -ea test runs fail.",
   "impact_class": "minor",
   "introduced_commit": "a590c6d2a08d85103bc207e28aa530a195a1838f (main, 2021-11-26, author and merger iverase, approved by jpountz): 'LUCENE-10262: Lift up restrictions for navigating PointValues#PointTree (#476)'; branch_9x backport cb0c2b87edd638271862ff530a1224ea3d0c4999 (same day, identical BKDReader.java blob ff2584fd8dd). It added readNodeDataPositions (written only in readNodeData's inner-node branch, BKDReader.java:746 today), resetNodeDataPosition() with 'assert readNodeDataPositions[level] <= innerNodes.getFilePointer()' (:399-403) and the unconditional calls to it from visitDocIDs (:588) and visitDocValues (:620) [read]. The leaf call was there from the PR's first revision (6832a77aaba, a conditional 'if (pos != fp) { assert pos <= fp; seek(pos); }'); review changed it to the unconditional seek; both forms fail the same way on this sequence [read].",
   "introduced_date": "2021-11-26 (main a590c6d2a08 and branch_9x cb0c2b87edd)",
   "first_affected_version": "9.1.0 [exec]: the first release that contains cb0c2b87edd; on the 10.x line the main commit first ships in 10.0.0 [exec]. 9.0.0 and earlier have no PointTree API (the repros do not compile there) [exec]; the API (LUCENE-9820, #7) and this defect first shipped together in 9.1.0, so no release ever had the API without the defect.",
   "affected_versions": "every release from 9.1.0 to 10.5.2 (32 tags), 10.6.0 (by reading) and main a9779ef3c193 (unreleased 11.0), only with -ea; never fixed upstream. [exec] the follow-up history test (three oracles: leaf visit, moveToParent, then visitDocIDs, visitDocValues or moveToChild) fails 3 of 5 with -ea and passes 5 of 5 with -da on 9.1.0, 9.12.3, 10.0.0, 10.5.2, main and the commit build cb0c2b87edd; the finder's JUnit fails 1 of 1 with -ea on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main and passes with -da on 9.1.0, 10.5.2 and main; the independent reproduction's JUnit fails 4 of 6 with -ea on 9.1.0, 9.12.3, 10.5.2 and main and passes 6 of 6 with -da on 9.12.3, 10.5.2 and main; the intended-behaviour check's right-to-left probe fails 2 of 3 with -ea on 9.1.0, 9.12.3, 10.5.2 and main. [read] the other releases: the bodies of resetNodeDataPosition, visitDocIDs and visitDocValues are byte-identical (hash 2931cba0ad0e) at every tag from 9.1.0 to 10.5.2, on branch_10_6 2763db11b0a, branch_10x 1309534296e and upstream main a95c754ee00 (2026-10-26), and the fix-site lines are unchanged on upstream main f7bcc0abd816 (2026-10-27). Not affected: 9.0.0 and earlier (no PointTree API) and the unreleased week between LUCENE-9820 and #476 (branch_9x 30c4b8d5b80 executed: the oracles pass).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/486",
    "https://github.com/apache/lucene/issues/15376",
    "https://github.com/apache/lucene/issues/476",
    "https://issues.apache.org/jira/browse/LUCENE-10262",
    "https://github.com/apache/lucene/issues/11298",
    "https://github.com/apache/lucene/issues/11305"
   ],
   "doc": "",
   "repro": "repro/LFV-761/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-713",
   "priority": "low",
   "priority_rank": 1052,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / hunspell (Hunspell.spell and suggest compound checking, CHECKCOMPOUNDPATTERN replacements)",
   "title": "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",
   "summary": "You load a Hunspell dictionary with a compound rule such as 'CHECKCOMPOUNDPATTERN o /X z' (a simplified compound form whose second part may begin with anything: hunspell(5) allows empty beginchars with a flag and an optional replacement) and call Hunspell.spell(\"foz\"), and expect true or false; C Hunspell 1.3.2 and 1.7.2 both say false. Instead, with assertions enabled, spell() and suggest() throw java.lang.AssertionError from WordStorage.lookupWord ('assert length > 0'). The cause: checkCompoundPatternReplacements expands the final 'z' to 'o' plus empty beginchars and puts the break right after 'foo', but never checks that a second part remains, so checkCompoundsAfter looks up a second part of length 0; with -da that lookup finds nothing and spell() returns false for the repro.",
   "impact_class": "minor",
   "introduced_commit": "d0ae2bd2b9c9, LUCENE-9717 'Hunspell: support CHECKCOMPOUNDPATTERN' (apache/lucene-solr#2280, by donnerpeter; issue apache/lucene#10756), the root cause: it added checkCompoundPatternReplacements ('int breakPos = pos + pattern.endLength()') and 'remainingLength = word.length - breakPos' in checkCompoundsAfter with no check that a second part remains [read] [exec]. Silent at that commit, because the FST lookup returns no entry for an empty word. Made visible as an AssertionError by LUCENE-9825 (4842e0c9cab, 2021-03-05, by donnerpeter, apache/lucene-solr#2459, issue apache/lucene#10864), which added WordStorage.lookupWord with 'assert length > 0' and reached main through the merge f5012a4cdaf (apache/lucene#2, 2021-03-10) [exec]. Reached 8.x through the branch_8x backport c6b964a1157 (apache/lucene-solr#2499, LUCENE-9687). Both steps predate every release, so it is not a regression of a released version",
   "introduced_date": "2021-02-03 (root cause, silent); 2021-03-10 (AssertionError visible on main); 2021-05-28 (8.x backport with both)",
   "first_affected_version": "8.9.0 [exec] (the first release with the spell-checking API, through the 8.x backport; 8.8.2 has no Hunspell class [exec]); on the main line 9.0.0 [exec]",
   "affected_versions": "every release that has the spell-checking API: 8.9.0, 8.10.0, 8.10.1, 8.11.0 - 8.11.4, 9.0.0 - 9.12.3 and 10.0.0 - 10.6.0 (42 releases), all executed with -ea and all failing [exec], and main a9779ef3c193 and 645d4fe14a20 [exec]; with -da every executed run (8.9.0, 9.0.0, 10.5.2, 10.6.0, main) returns the correct false for the repro [exec]. Not affected: 8.8.2 and older (no spell-checking API) [exec]. Not fixed upstream: checkCompoundPatternReplacements is unchanged and lookupWord still asserts length > 0 on upstream main a95c754ee003, branch_10x and branch_10_6 (2026-10-27) [read]. All runs on Linux aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-713.html",
   "repro": "repro/LFV-713/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-421",
   "priority": "low",
   "priority_rank": 1053,
   "novelty": "new",
   "withheld": false,
   "area": "misc / BP merge-time reordering (BpVectorReorderer centroid arithmetic)",
   "title": "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",
   "summary": "You index DOT_PRODUCT or COSINE float vectors and reorder them with BpVectorReorderer, by calling computeDocMap or by merging through BPReorderingMergePolicy, for example 64 legal unit vectors where docs 0..31 alternate (1,0) and (-1,0) and docs 32..63 are (0,1); you expect a valid reordering, as for any other legal vectors. Instead the half whose vectors cancel out sums to the zero vector, computeCentroid normalizes it by 1/sqrt(0) = Infinity and the centroid becomes NaN. With assertions on, VectorUtil.dotProduct then fails with 'AssertionError: not finite: NaN from <[1.0, 0.0],[NaN, NaN]>' and the merge path closes the IndexWriter; with assertions off nothing throws, but the NaN biases leave that split in doc-ID order.",
   "impact_class": "minor",
   "introduced_commit": "02a09f6ab124 (#14097 'HNSW BP reordering' by msokolov, main) [exec]; the finite-result assertion in VectorUtil.dotProduct predates the class (071461ece541, #12281, 2023-06-13; #15213 only added the 'not finite' message); not a regression: the class has had this behaviour since it was added",
   "introduced_date": "2025-01-07",
   "first_affected_version": "unreleased (main and branch_11x, 11.0.0-SNAPSHOT; CHANGES.txt lists GITHUB#14097 under 11.0.0 and no release tag contains BpVectorReorderer)",
   "affected_versions": "main from 02a09f6ab124 (2025-01-07) through 645d4fe14a20 [exec]; branch_11x 603af870375 has the same file and contains 02a09f6ab124 [read]; upstream main cf398bfb142c (2026-10-26) still has the unguarded line [read]; open PR #15430 (moves the class to core) copies it [read]. Not affected: 9.12.3, 10.1.0, 10.2.0 and 10.5.2, where the repro does not compile because BpVectorReorderer does not exist [exec]; every release tag through 10.6.0 and branch_10x, branch_10_6 and branch_10_5 lack the file [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-421.html",
   "repro": "repro/LFV-421/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-267",
   "priority": "low",
   "priority_rank": 1054,
   "novelty": "known",
   "withheld": false,
   "area": "search / TopDocs.merge tie breaking (score and Sort merges with a custom tie breaker)",
   "title": "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",
   "summary": "You merge per-shard results with TopDocs.merge(start, topN, shardHits, tieBreaker), or the Sort overload, and pass a valid Comparator<ScoreDoc> tie breaker that ignores the shard, for example one that compares doc ids only; two shards each have a hit with the same score (or sort value) at the same rank and the same local doc id. You expect both hits back, since the method accepts any custom tie breaker and its helper documents that a 0 from the tie breaker falls back to hit indices. Instead, with assertions enabled, the merge throws AssertionError at TopDocs.java:88 ('assert first.hitIndex != second.hitIndex'), because that check assumes a tie can only come from the same shard while the merge queue only ever compares hits of different shards; with -da both hits are returned.",
   "impact_class": "minor",
   "introduced_commit": "f686167e710e2dd1d8b37f938ee0fcda9cebbe1a, 'LUCENE-8857: Introduce Custom Tiebreakers in TopDocs#merge (#757)' (apache/lucene-solr#757; issue LUCENE-8857, now apache/lucene#9900; author atris, reviewed and committed via jpountz) [exec]; it replaced the shard-index comparison that ran before the hit-index branch with the caller's comparator and kept the assertion, its 'Tie break in same shard' comment and the 'intra shard ties' javadoc; the first attempt e70b43c39a2 (#734, 2019-07-01) was reverted the same day by 3f0ecfa9c46; the assertion statement itself dates from a1e74fd6c94 (LUCENE-3191, 2011) and was moved into tieBreakLessThan by 5eeb8136f34 (LUCENE-7707, 2017) [read]",
   "introduced_date": "2019-07-02 (PR #757 merged 2019-07-02T18:35:19Z; author date 2019-07-03 +0530)",
   "first_affected_version": "9.0.0 [exec], the first release with the tie-breaker overloads (8.x has no TopDocs.merge overload that takes a Comparator<ScoreDoc>: the repro does not compile on 8.1.1 or 8.11.4 [exec])",
   "affected_versions": "every 9.x and 10.x release from 9.0.0 through 10.5.2 (33 releases), and main ea57360912ed: AssertionError with -ea [exec], every hit returned with -da [exec]; the assertion is at TopDocs.java:84 up to 10.1.0 and at :88 from 10.2.0; not affected: 8.x and older (API absent) [exec]; not fixed upstream (the assertion is unchanged on main and no open PR changes tieBreakLessThan); the 10.6 branch and 10.6.0 (released 2026-10-29) were not checked; executed on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/9900",
    "https://github.com/apache/lucene-solr/pull/734",
    "https://github.com/apache/lucene/issues/757",
    "https://github.com/apache/lucene/issues/8758",
    "https://github.com/apache/lucene/issues/9873",
    "https://issues.apache.org/jira/browse/LUCENE-7707"
   ],
   "doc": "",
   "repro": "repro/LFV-267/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-057",
   "priority": "low",
   "priority_rank": 1055,
   "novelty": "new",
   "withheld": false,
   "area": "util / automaton",
   "title": "UTF32ToUTF8 still accepts overlong UTF-8 for ranges that span into 3- and 4-byte code points",
   "summary": "You convert a code-point range that starts below U+0800 and ends at or above U+1000 into a UTF-8 automaton, as makeAnyChar and regex '.' do, and match it against binary terms that are not valid UTF-8. You expect only valid UTF-8 to match. Instead the overlong sequences E0 80..9F xx are accepted.",
   "impact_class": "silent wrong results",
   "introduced_commit": "LUCENE-2265 (5b74a4ec611), which created UTF32ToUTF8; narrowed, not fixed, by #12472 (ec1367862d0, 9.8.0) [exec]",
   "introduced_date": "2010-05-03",
   "first_affected_version": "4.0.0-ALPHA [exec]",
   "affected_versions": "every release from 4.0.0-ALPHA to 10.5.2 and main (all run) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-057.html",
   "repro": "repro/LFV-057/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-058",
   "priority": "low",
   "priority_rank": 1056,
   "novelty": "new",
   "withheld": false,
   "area": "util / bitsets",
   "title": "SparseFixedBitSet.nextClearBit returns NO_MORE_DOCS in the last 4096-bit block",
   "summary": "You call nextClearBit on a SparseFixedBitSet longer than 2^31-4096 bits at a position in its last 4096-bit block. You expect the next clear bit. Instead blockBase + 4096 wraps, it returns NO_MORE_DOCS, and BitSetIterator.docIDRunEnd then claims absent documents.",
   "impact_class": "silent wrong results",
   "introduced_commit": "#16072 (9f33b54a13a)",
   "introduced_date": "2026-05-18",
   "first_affected_version": "10.5.0",
   "affected_versions": "10.5.0, 10.5.1 and 10.5.2 (assertions off; with them on, the constructor's own blockCount assertion fires first) and 10.6.0 (assertions on and off) [exec]; main 645d4fe14a20 [exec]; 10.4.0 not affected (no nextClearBit; a docIDRunEnd probe returns the right answer) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-058.html",
   "repro": "repro/LFV-058/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-066",
   "priority": "low",
   "priority_rank": 1057,
   "novelty": "new",
   "withheld": false,
   "area": "util / bitsets",
   "title": "RoaringDocIdSet.Builder.add(min, max) throws on the last 2^16-doc block",
   "summary": "You add a doc-ID range that falls in the last 65,536-doc block below 2^31 to a RoaringDocIdSet.Builder. You expect the range to be added. Instead (block+1)<<16 wraps and the call throws; it never returns wrong data.",
   "impact_class": "crash",
   "introduced_commit": "#16081 (33d6115c384)",
   "introduced_date": "2026-05-18",
   "first_affected_version": "10.5.0",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2 and 10.6.0 [exec]; main 645d4fe14a2 [exec]; 10.3.2 and 10.4.0 not affected (no add(int, int)) [exec]; branch_10x 657014b3c57 and branch_10_6 4ae946e5a9b (10.6.0 RC1) have the same defect line RoaringDocIdSet.java:164 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-066.html",
   "repro": "repro/LFV-066/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-069",
   "priority": "low",
   "priority_rank": 1058,
   "novelty": "new",
   "withheld": false,
   "area": "util / heaps",
   "title": "LongHeap and TernaryLongHeap stop growing at 715,827,883 elements despite 'grows unbounded'",
   "summary": "You push more than 715,827,882 elements into a growable LongHeap or TernaryLongHeap. You expect the heap to keep growing, as documented. Instead (size*3+1)/2 wraps, push throws and leaves the heap corrupt; TernaryLongHeap.downHeap has a related index overflow at the same size.",
   "impact_class": "crash",
   "introduced_commit": "LongHeap af3e12265fe (LUCENE-9626); TernaryLongHeap ac90517c17e (#15140)",
   "introduced_date": "2020-12-09 (af3e12265fe); 2025-09-02 (ac90517c17e)",
   "first_affected_version": "9.0.0 [exec] for LongHeap (no 8.x release has the class); 10.4.0 [exec] for TernaryLongHeap and the IndexSearcher.search path",
   "affected_versions": "LongHeap: every release from 9.0.0 to 10.6.0 and main [exec]; TernaryLongHeap and the IndexSearcher.search(query, n) path: 10.4.0 to 10.6.0 and main [exec]; not affected: 8.11.0 (no LongHeap) and 10.3.2 (no TernaryLongHeap) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-069.html",
   "repro": "repro/LFV-069/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-294",
   "priority": "low",
   "priority_rank": 1059,
   "novelty": "new",
   "withheld": false,
   "area": "util / PriorityQueue (sift-down; base class of HitQueue and FieldValueHitQueue)",
   "title": "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",
   "summary": "You fill a Lucene PriorityQueue with 2^30 + 1 elements, a size its constructor accepts (any maxSize below ArrayUtil.MAX_ARRAY_LENGTH), and call updateTop, pop or insertWithOverflow; you expect the usual log(size) sift-down and the new least element back. Instead, when the sift-down reaches node 2^30, the child index i << 1 wraps to Integer.MIN_VALUE, the negative index -2147483647 passes the 'k <= size' check, and the call throws ArrayIndexOutOfBoundsException after children were already moved up, so the queue has lost the element being sifted and holds a second copy of another. A queue of 2^30 - 1 elements works; exactly 2^30 already fails for updateTop.",
   "impact_class": "crash",
   "introduced_commit": "bd3948c539ec1065db8b05b433ea55dbf844ff27 'Initial revision' (2001-09-18, svn r149570, the oldest commit that contains this code (its parent is 749b4aaf7e9; the repository roots are a0e7ee9d0d1 and 3cdb369a611): the import of the existing code base, with no issue or pull request) [exec]; reachable within the documented capacity since 2e082f2f008 (2003-09-11, svn r150020, 'Added insert(Object) method to PriorityQueue class', which changed the heap size from 2 * maxSize + 1 to maxSize + 1 and documented maxSize as the capacity; CHANGES 1.3 RC2 item 5) [read]. Not a regression: later changes to downHeap (generics LUCENE-1935 698b73e2ae1, start index LUCENE-6066 ef3a99b385f, LessThan interface #14873 39549329509, visibility #15493 dea98efd5e2, whitespace) left the index arithmetic alone, and each new sift-down entry point (insertWithOverflow 2.3.0, updateTop 2.9.0, addAll's heapify 9.2.0 #770) inherited it",
   "introduced_date": "2001-09-18 (bd3948c539e; the code may be older, its pre-import history is not in the repository); reachable within the documented capacity since 2003-09-11 (2e082f2f008)",
   "first_affected_version": "1.3 [exec], the first release where it is reachable within the documented capacity (maxSize >= 2^30, size <= maxSize); the identical downHeap is already in 1.2, the first Apache release (2001-10-02, the same file as tag 1.0.1 and the initial revision), but there 2^30 elements can only be reached by calling put() more than maxSize times on a queue with maxSize >= 2^29 + 1 (allowed there: 2 * maxSize + 1 slots, no check) [exec]",
   "affected_versions": "every release from 1.2 through 10.6.0 and main (ea57360912ed, a9779ef3c193, 645d4fe14a20); no version has a fix [exec] [read]. Caveat: every run used JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-294.html",
   "repro": "repro/LFV-294/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-043",
   "priority": "low",
   "priority_rank": 1060,
   "novelty": "new",
   "withheld": false,
   "area": "util / sorters",
   "title": "TimSorter overflows its 49-entry run stack on legal inputs of about 1.1 billion elements",
   "summary": "You sort about 1.09 billion or more elements with ArrayUtil.timSort or CollectionUtil.timSort, arranged in a specific pattern of 1,061 runs. You expect a sorted result. Instead TimSorter's fixed 49-entry run stack overflows and the sort throws ArrayIndexOutOfBoundsException.",
   "impact_class": "crash",
   "introduced_commit": "3ec9440e94 (LUCENE-6293) raised STACKSIZE from 40 to 49 without the fourth-run check",
   "introduced_date": "2015-02-26",
   "first_affected_version": "5.1.0 [exec] (the 49-entry stack of LUCENE-6293, 3ec9440e94, 2015); the root defect, the three-run check of LUCENE-4839 (2013), since 4.3.0 [exec]",
   "affected_versions": "5.1.0 through 10.6.0 and main [exec]; the same root defect with the older 40-entry stack in 4.3.0 through 5.0.0 [exec]; 4.2.1 and earlier have no TimSort [exec]; TimSorter.java is the same blob in 9.12.3, 10.0.0, 10.6.0, main and upstream main f815e679bf6c [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-043.html",
   "repro": "repro/LFV-043/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-133",
   "priority": "low",
   "priority_rank": 1061,
   "novelty": "new",
   "withheld": false,
   "area": "util / FixedBitSet (approximateCardinality)",
   "title": "(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",
   "summary": "You create a FixedBitSet of 2^31-63 to 2^31-1 bits (for example new FixedBitSet(Integer.MAX_VALUE), a legal length: the class javadoc points to LongBitSet only for more than 2.1B bits), set some bits and call approximateCardinality(); you expect a non-negative estimate of the number of set bits, as BitSet documents ('an approximation of the cardinality of this set'). Instead it returns a negative number (-2147418112 with all 2^31-1 bits set, -64 with a single set bit), because the scale factor (interval / rangeLength) * numWords / maxWord is computed in int and its product 64 * numWords wraps to Integer.MIN_VALUE once the set has 2^25 words; new BitDocIdSet(bits) then throws IllegalArgumentException 'cost must be >= 0'. No Lucene code path builds a bit set that long (doc-ID sets stop at IndexWriter.MAX_DOCS = 2^31-129 bits), so only external code that uses FixedBitSet directly over another int domain is affected.",
   "impact_class": "minor",
   "introduced_commit": "ca73ed1c2842 (LUCENE-10311, apache/lucene#710 'Make FixedBitSet#approximateCardinality faster (and actually approximate).', author jpountz, merged on main 2022-03-03; branch_9x backport bb10e62dff88, same date) replaced the inherited exact BitSet default with the sampled estimate and wrote the overflowing line [read]; later commits in the same series did not touch the overflow: ae16917c1de (#724, rewrote the sampling loop with Long.bitCount) and e999056c19d (dweiss, 2022-03-09, 'avoid division by zero on small sets', changed numWords < interval to <= in the same method)",
   "introduced_date": "2022-03-03 (#710 merged on main and backported to branch_9x)",
   "first_affected_version": "9.1.0 [exec]; 9.0.0 passes [exec]",
   "affected_versions": "every release from 9.1.0 to 10.5.2 (32 releases: all 20 from 9.1.0 to 9.12.3 and all 12 from 10.0.0 to 10.5.2), 10.6.0 and main (ea57360912ed, a9779ef3c193 and 645d4fe14a20): executed and failing on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main with -ea and -da (the same value, -2147418112, everywhere) [exec]; the other 28 releases (9.2.0-9.12.2, 10.1.0-10.5.1) have a byte-identical approximateCardinality() body [read]; 9.0.0 passes [exec] because FixedBitSet then inherited BitSet's default, which returned the exact cardinality(); no 8.x or older release has the override [read]; upstream main, branch_10x, branch_10_6 and branch_9_12 still contain the expression (2026-10-26) [read], and 10.6.0 (released 2026-10-29) fails with -ea and -da (the minimal test, -64 for one set bit) [exec]; branch_9x not checked; not fixed upstream [read]; executed on aarch64 Linux with JDK 25 only (pure int arithmetic, platform-independent)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-133.html",
   "repro": "repro/LFV-133/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-323",
   "priority": "low",
   "priority_rank": 1062,
   "novelty": "new",
   "withheld": false,
   "area": "util / RamUsageEstimator",
   "title": "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",
   "summary": "You ask RamUsageEstimator.sizeOfCollection (or sizeOfObject) for the size of a very large list, for example Arrays.asList(new Object[536870908]). You expect a size in bytes that is at least the 2,147,483,648 bytes of its backing array, which shallowSizeOf(Object[]) reports correctly. Instead the method adds the array header and the per-element references in int arithmetic, which wraps, so it returns -2,147,483,616; in general the estimate is too low by a multiple of 2^32 bytes from 536,870,908 elements on (268,435,453 with 8-byte references), and it is negative only when the elements' own sizes add little.",
   "impact_class": "minor",
   "introduced_commit": "7989a863faad (master, now main; branch_8x cherry-pick 84db2b274286), the LUCENE-8855 follow-up 'Fix some size estimates and relax test assertions to work under different JVMs.' by sigram (GitHub), no PR (2019 JIRA patch workflow; issue LUCENE-8855, migrated as apache/lucene#9898) [read]; it replaced 'size += NUM_BYTES_ARRAY_HEADER * 2', the form with which a76c962ee61f (LUCENE-8855, 2019-06-26) had added the method one day earlier and which was never released",
   "introduced_date": "2019-06-27 (authored; committed and pushed 2019-06-28)",
   "first_affected_version": "8.2.0 [exec]; 8.1.1 and earlier have no sizeOfCollection (compile error) [exec]",
   "affected_versions": "8.2.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.6.0 and main (ea57360912ed, a9779ef3c193 and 645d4fe14a20) [exec]; the identical line is in all 48 release tags from 8.2.0 to 10.5.2 that the history clone has (8.8.2-8.11.3 are not in the clone and are bracketed by the 8.8.1 source and the 8.11.4 run) [read]; upstream main e1c4184cb983 (line 307), branch_10x and branch_10_6 (line 309; 10.6.0 was released from branch_10_6 on 2026-10-29) still have it (2026-10-26) [read]; 8.1.1 and earlier: API absent [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-323.html",
   "repro": "repro/LFV-323/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-148",
   "priority": "low",
   "priority_rank": 1063,
   "novelty": "new",
   "withheld": false,
   "area": "util / packed ints (MonotonicBlockPackedWriter, MonotonicBlockPackedReader)",
   "title": "(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()",
   "summary": "You write a block of non-negative, increasing longs with MonotonicBlockPackedWriter, for example {1, Long.MAX_VALUE}, and read it back with MonotonicBlockPackedReader. You expect the same values back: the writer is documented as 'A writer for large monotonically increasing sequences of positive longs' with no upper bound, and flush() says 'adjust min so that all deltas will be positive'. Instead the predicted value min + (long) (avg * i) wraps past Long.MAX_VALUE, so the adjustment of min is skipped and the resulting negative delta is ignored when the bit width is chosen; get(1) returns Long.MIN_VALUE with no error (a larger block trips an AssertionError in BulkOperationPacked.encode under -ea and reads back wrong values under -da).",
   "impact_class": "minor",
   "introduced_commit": "b31ae698e5d (b31ae698e5d1574105d43901356ae752eedb6e4e) 'LUCENE-5721: Monotonic compression doesn't use zig-zag encoding anymore.' by jpountz (JIRA LUCENE-5721, migrated as apache/lucene#6783; svn r1600694, no GitHub PR); branch_4x backport 1b450e1be80 (svn r1600747), the commit that the 4.9.0-5.5.5 release tags contain. It replaced the wrap-consistent zig-zag deltas with the min-adjustment loop whose signed test 'expected > actual' runs on a possibly wrapped expected value [read]",
   "introduced_date": "2014-06-05 (trunk b31ae698e5d and branch_4x 1b450e1be80, the same day)",
   "first_affected_version": "4.9.0 [exec] (4.2.0, the first release with these classes, and 4.8.1, the last before LUCENE-5721, pass [exec])",
   "affected_versions": "every release 4.9.0 through 10.5.2 (105 release tags in the history clone, plus 8.9.0-8.11.x, which the clone does not tag), 10.6.0 (RC1 4ae946e5a9b [exec]) and main ea57360912ed through 645d4fe14a2; never fixed. Executed failing: 4.9.0 and 4.10.4 (-ea and -da), 5.5.5, 6.6.6, 7.7.3 and 8.11.4 (-da), 9.12.3, 10.5.2 and main (-ea and -da) [exec]; the other releases by identical flush()/expected() code [read]. 4.9.x also fails to read a block whose origin is 2^62 or more (writeVLong(zigZagEncode(min)); 'Invalid vLong detected' with -da), which LUCENE-5739 removed in 4.10.0 [exec]. Not affected: 4.2.0-4.8.1 (pre-LUCENE-5721 zig-zag arithmetic) [exec]; the classes do not exist before 4.2.0. Not executed: 9.0.0 (identical code). Upstream main 645d4fe14a2 and branch_10_6 RC1 4ae946e5a9b fail [exec]; branch_10x 657014b3c57 has the identical file [read] (MonotonicBlockPackedWriter.java last changed 2021 by @Override annotations)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-148.html",
   "repro": "repro/LFV-148/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-449",
   "priority": "low",
   "priority_rank": 1064,
   "novelty": "new",
   "withheld": false,
   "area": "index / sorted-set doc values terms enum (SortedSetDocValuesTermsEnum, the default SortedSetDocValues#termsEnum())",
   "title": "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",
   "summary": "You take the terms enum of a sorted-set doc-values view with more than 2^31 distinct values (for example MultiDocValues.getSortedSetValues over a very large multi-segment index), position it on a term with seekCeil, keep ord() or termState(), and later return with seekExact(ord) or seekExact(term, state); you expect to land on that term again, because sorted-set ordinals are longs and termsEnum() is documented to support ord() and seekExact(long). Instead seekExact(long) stores '(int) ord' (SortedSetDocValuesTermsEnum.java:69), so for ordinals from 2^31 to 2^32-1 it asks the values for a negative ordinal and throws, and for 2^32+5 it silently positions on ordinal 5 and returns that term, with -ea and -da. seekCeil, seekExact(BytesRef), next() and ord() use long arithmetic and are correct; the fix is to drop the cast.",
   "impact_class": "silent wrong results",
   "introduced_commit": "2dcf80718c21548c85aa3e1c2283721242b11d04 (svn r1444647, branch lucene4765, 'commit current state', 2013-02-11), part of LUCENE-4765 'Multi-valued docvalues field' (now GitHub issue #5830; no pull request, the change predates GitHub). It created SortedSetDocValuesTermsEnum as a copy of SortedDocValuesTermsEnum and widened currentOrd from int to long, but kept 'currentOrd = (int) ord;' in seekExact(long). Reached trunk through the merge b44aa618348 (r1447999) and branch_4x through bb1f4d0c61b (r1448085), both 2013-02-20; the line never changed afterwards [read]",
   "introduced_date": "2013-02-11 (branch commit); 2013-02-20 (merged to trunk and branch_4x)",
   "first_affected_version": "4.2.0 [exec] (the first release with SortedSetDocValues; in 4.2.0 the enum is reached through its then-public constructor, and from 4.2.1 on, LUCENE-4819, it is what SortedSetDocValues#termsEnum() returns); 4.1.0 is not affected [exec]. Not a regression.",
   "affected_versions": "every release from 4.2.0 through 10.6.0, and main (ea57360912ed, a9779ef3c193 and 645d4fe14a20) [exec] [read]; unchanged on upstream main and branch_10x (2026-10-26) and on upstream main f815e679bf6c, branch_11x and branch_10_6 (2026-11-01) [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-449.html",
   "repro": "repro/LFV-449/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-298",
   "priority": "low",
   "priority_rank": 1065,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / BufferingKnnVectorsWriter flush-time vector values (KnnVectorValues.ordToDoc and getAcceptOrds)",
   "title": "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)",
   "summary": "You build a vector codec on BufferingKnnVectorsWriter and, in writeField, ask the flush-time vector values which document a vector ordinal belongs to (ordToDoc, or getAcceptOrds, which is built on it), expecting what the javadoc promises, 'the docid of the document indexed with the given vector ordinal'. Instead the buffered values answer ordToDoc(ord) = ord, which is right only when every document has a vector and there is no index sort: for a field that documents 0, 2 and 3 have, ordinals 1 and 2 map to documents 1 and 2 instead of 2 and 3, so a getAcceptOrds filter that accepts only document 2 accepts document 3's vector and one that accepts only document 3 accepts none; under a reversing index sort even a dense field's ordinals map to themselves instead of to their documents' sorted positions. Iteration (nextDoc, index, vectorValue) stays correct, nothing throws, and FLOAT32, BYTE and FLOAT16 behave the same.",
   "impact_class": "minor",
   "introduced_commit": "6053e1e31378378f6d310a05ea6d7dcdfc45f48b (#13779 'First-class random access API for KnnVectorValues', author msokolov, merged into main 2024-09-28, milestone 10.0.0) [read]. Inside the PR (commits read through the read-only GitHub API, not built): 2bbf8f1fed (2024-09-02, 'adding some ordToDoc') gave BufferedFloatVectorValues ordToDoc(ord) { return ord; } while the base ordToDoc still threw UnsupportedOperationException; dce766c975 (2024-09-05) made the base default return ord, documented as right for dense values; ff7a317a81 (2024-09-12, 'fix case where index is reordered') made the sorting views hand out ordinals in the delegate's ordinal space without an ordToDoc override. Later extension: bfe5c847d3c4 (#16383, fp16 vector encoding, 2026-07-27; on main and branch_11x, in no release) copied the identity override to BufferedFloat16VectorValues and added SortingFloat16VectorValues without one. The defect came with the API; it is not a regression, because before 10.0.0 these values had no ordinal-to-document method",
   "introduced_date": "2024-09-28 (merge of #13779; the identity override was written in its commit 2bbf8f1fed on 2024-09-02); FLOAT16 copy 2026-07-27 (#16383; on main and branch_11x, in no release)",
   "first_affected_version": "10.0.0 [exec] (the first release with #13779); 9.x is not applicable: no KnnVectorValues class and no ordToDoc on these values [exec]",
   "affected_versions": "every 10.x release (10.0.0, 10.1.0, 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2, 10.6.0) and main (ea57360912ed and 645d4fe14a20) [exec]; the FLOAT16 classes exist on main and branch_11x only, in no release (#16383) [exec]; not affected: 9.x and earlier, where the API does not exist [exec]; not fixed: upstream main cb19aecba8f3 (2026-10-26) has not changed BufferingKnnVectorsWriter.java since #16383 [read]; unreleased maintenance branches not checked",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-298.html",
   "repro": "repro/LFV-298/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-159",
   "priority": "low",
   "priority_rank": 1066,
   "novelty": "new",
   "withheld": false,
   "area": "util / HNSW graph node iterators (HnswGraph.NodesIterator, DenseNodesIterator)",
   "title": "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)",
   "summary": "You take the level-0 node iterator of an HNSW graph (getNodesOnLevel(0), a DenseNodesIterator over the node ids [0, size)) and read it in chunks with consume(buf), expecting each call to hand out the next block of ids, as the javadoc ('Consume integers from the iterator') and the two sibling iterator classes do. Instead DenseNodesIterator.consume copies the block but never moves its cursor, so every call returns the same first block, hasNext() stays true and the loop never ends; a nextInt() after consume() also starts again at 0. Lucene's own code never calls consume() on level 0, so indexes and search results are not affected.",
   "impact_class": "minor",
   "introduced_commit": "d0be9ab57c9c (main) / d9a331c85bc (branch_9x backport, the same day), #11860 'GITHUB-11830 Better optimize storage for vector connections' (benwtrent; closes #11830): added NodesIterator.consume(int[]) whose dense branch (nodes == null, the level-0 mode) returns before 'cur += numToCopy' while the array branch of the same method advances [read]; carried unchanged by #12050 (776149f0f69, 9.6.0: dense mode moved into ArrayNodesIterator(int size)) and #15425 (08538bbaf0e, 10.4.0: dense mode split out as DenseNodesIterator) [read]",
   "introduced_date": "2022-12-07 (#11860 merged on main and backported to branch_9x)",
   "first_affected_version": "9.5.0 [exec] (9.4.2 has no NodesIterator.consume [exec]; 9.4.0 and 9.4.1 [read])",
   "affected_versions": "every release from 9.5.0 to 10.6.0 and main (ea57360912ed, a9779ef3c193 and 645d4fe14a20). [exec] the minimal repro fails on 10.6.0 and main 645d4fe14a20 (-ea and -da); the follow-up's version-portable public-API history test (stored graph of a 2000-document index, chunked consume over level 0, level 1 as control) fails on 9.5.0, 9.6.0, 9.9.0, 9.12.3, 10.0.0, 10.3.2, 10.4.0, 10.5.2 (-ea and -da) and main (-ea and -da); the independent reproduction's tests fail on main (-ea and -da), 10.5.2, 9.12.3 and 9.5.0 (a 9.5-shape test); the intended-behaviour check's public-API test on main (-ea and -da), 10.5.2 and 9.12.3; the finder's JUnit on main (-ea and -da), 10.5.2 and 10.4.0; all on JDK 25, also for releases that predate it. [read] the same dense consume block without the advance in every release tag from 9.5.0 to 10.5.2 (9.5.0 in NodesIterator, 9.6.0-10.3.x in ArrayNodesIterator(int size), 10.4.0 on in DenseNodesIterator). Not affected: 9.4.2 and older (no consume()). Not fixed upstream: main, branch_10x, branch_10_6 and branch_10_5 still lack the advance (read-only GitHub API, 2026-10-26).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-159.html",
   "repro": "repro/LFV-159/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-165",
   "priority": "low",
   "priority_rank": 1067,
   "novelty": "new",
   "withheld": false,
   "area": "index / doc values and norms flush with index sorting (NumericDocValuesWriter.SortingNumericDocValues)",
   "title": "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)",
   "summary": "You sort an index at flush and every document in the segment has a given numeric doc-values field (or norms, or a single-valued SortedNumericDocValuesField); a custom DocValuesFormat or NormsFormat consumer bulk-loads the iterator it gets at flush with intoBitSet(maxDoc) or intoBitSet(NO_MORE_DOCS) and expects it to end on NO_MORE_DOCS, as the reference loop in the intoBitSet javadoc does. Instead NumericDocValuesWriter.SortingNumericDocValues sets the right bits but leaves docID() at maxDoc, a position the docID() contract never allows, so a consumer that loops until NO_MORE_DOCS never ends; fed to IndexedDISI.writeBitSet it fails the flush with an AssertionError (-ea) or keeps writing empty-block headers until the output fails (-da). Lucene's own consumers never bulk-load a field that every document has, so stock indexes and search results are not affected.",
   "impact_class": "minor",
   "introduced_commit": "88f3d24ce7e1b3e7b6716d078b69b0098d467a8c (main) and its branch_10x backport ef8dd5fb8bc466ce8a22eb41d167f036554fc64a, PR #16126 'Implement #intoBitSet and #docIDRunEnd in DocValuesWriter implementations' (author and merger iverase, approved by martijnvg; CHANGES 10.5.0 Optimizations; no tests for these iterators), which added the SortingNumericDocValues.intoBitSet override whose dense branch ends with 'docID = upTo;' [read]; the dense state the branch keys on (docsWithField == null) comes from #12381 (01200b58046e, 9.8.0) and was harmless until the override, because the inherited default loop ends on NO_MORE_DOCS [read]",
   "introduced_date": "2026-05-26 (merged on main; branch_10x backport committed the same day)",
   "first_affected_version": "10.5.0 [exec] (10.4.0 is the last unaffected release [exec]; 10.2.0 to 10.4.0 have DocIdSetIterator#intoBitSet but no override in this class, so the default loop is used [exec]; before 10.2.0 the method does not exist [exec])",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2, 10.6.0 and main (ea57360912ed, a9779ef3c193 and 645d4fe14a20). [exec] the minimal test fails on 10.6.0 and main 645d4fe14a20 (-ea and -da) and passes on 10.4.0; the finder's JUnit fails 4 of 5 on 10.5.0, 10.5.1, 10.5.2 and main, and on 10.5.2 and main also with -da; the independent reproduction's JUnit fails 6 of 12 on 10.5.0, 10.5.1, 10.5.2 (-ea and -da) and main (-ea and -da); both pass on 10.4.0 (the independent reproduction's OBS lines show the probe ran on SortingNumericDocValues and ended on NO_MORE_DOCS, so the pass is not vacuous), the finder's also on 10.2.0 and 10.3.2; 9.12.3 is not applicable (DocIdSetIterator#intoBitSet(int, FixedBitSet, int) does not exist; it first shipped in 10.2.0 via #14069 and #14134). [read] the method text is identical (sha1) at 10.5.0, 10.5.1, 10.5.2 and main; 10.0.0 and 10.1.0 lack the API. Not fixed upstream: main, branch_10x, branch_10_6 and branch_10_5 still have 'docID = upTo;' in the dense branch (read-only GitHub API, 2026-10-26).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-165.html",
   "repro": "repro/LFV-165/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-418",
   "priority": "low",
   "priority_rank": 1068,
   "novelty": "new",
   "withheld": false,
   "area": "index / doc values flush (DocValuesWriter Buffered*DocValues iterators handed to DocValuesConsumer)",
   "title": "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)",
   "summary": "A custom doc-values codec receives, at flush, the iterator over a field's buffered values; it calls nextDoc(), bulk-loads the next documents into a bit set with intoBitSet(), and then reads the value of the current document, expecting what the documented nextDoc() loop gives. Instead the five flush-time iterators (one per doc-values type) move only their doc-ID cursor in intoBitSet(), so the value read belongs to an earlier document, and every later value of the field in that segment stays shifted by the same number of documents (doc 2 reports doc 0's value, doc 3 reports doc 1's). Lucene's own doc-values consumer never reads values after intoBitSet() on the same iterator, so indexes written by stock Lucene are correct.",
   "impact_class": "minor",
   "introduced_commit": "88f3d24ce7e1b3e7b6716d078b69b0098d467a8c (main merge commit of PR #16126 'Implement #intoBitSet and #docIDRunEnd in DocValuesWriter implementations', author iverase, one approving review by martijnvg ('LGTM'), no comments, no tests for these iterators; CHANGES 10.5.0 Optimizations) and its branch_10x backport ef8dd5fb8bc466ce8a22eb41d167f036554fc64a (same git patch-id, the copy that shipped in 10.5.0), which added 'intoBitSet(...) { docsWithField.intoBitSet(upTo, bitSet, offset); }' to BufferedNumericDocValues, BufferedBinaryDocValues, BufferedSortedDocValues, BufferedSortedNumericDocValues and BufferedSortedSetDocValues [read]. A regression from an optimisation: from 10.2.0 to 10.4.0 these iterators inherited the default intoBitSet loop, which calls nextDoc() and keeps the value cursor in step",
   "introduced_date": "2026-05-26 (main merge 88f3d24ce7e and branch_10x backport ef8dd5fb8bc, same day)",
   "first_affected_version": "10.5.0 [exec] (release commit f6eaee8148b, tagged 2026-06-25); 10.4.0 is the last unaffected release [exec]: it has DocIdSetIterator#intoBitSet but these iterators use the default nextDoc() loop; the method first shipped in 10.2.0 (#14069), and 10.1.0 and earlier, including all of 9.x, lack it [exec]",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2, 10.6.0 and main (ea57360912ed, a9779ef3c193 and 645d4fe14a20) [exec]. Not affected: 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2 and 10.4.0 [exec]. Not applicable (API absent): 10.1.0 and earlier, including all of 9.x [exec]. Not fixed: the five delegating overrides are still on upstream main (cf398bfb142c at search time, 2026-10-26), branch_10_6 (10.6.0, released 2026-10-29), branch_10x and branch_10_5 [read]. All runs on one aarch64 Linux host with JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-418.html",
   "repro": "repro/LFV-418/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-753",
   "priority": "low",
   "priority_rank": 1069,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / SimpleText points format (SimpleTextBKDReader.SimpleTextPointTree#clone)",
   "title": "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",
   "summary": "You index points with the SimpleText codec, take a PointTree from PointValues.getPointTree(), clone it and keep moving both the clone and the original, and expect each tree to report the bounds of its own current node, as PointTree#clone promises ('the current node becomes the root of the new tree') and as the default points format does. Instead SimpleTextPointTree.clone() copies the reference to the original's saved split-value array for the current level, so a move of one tree overwrites the bound that the other tree restores when it moves back up: after tree.moveToChild(), tree.moveToParent(), clone = tree.clone(), clone.moveToChild(), tree.moveToChild(), tree.moveToSibling(), clone.moveToParent(), the clone at its root reports max 0 instead of 2047 for the values 0..2047. Any traversal that prunes on those bounds can then miss or wrongly include cells; no in-tree query moves trees this way.",
   "impact_class": "minor",
   "introduced_commit": "ad911df2605591a63ca58d237182f84aa8384325 (main, 2021-11-19, by iverase): 'LUCENE-9820: Separate logic for reading the BKD index from logic to intersecting it' (apache/lucene#7), which created the PointValues.PointTree cursor API and SimpleTextPointTree, including clone() with the reference copy 'index.splitDimValueStack[level] = splitDimValueStack[level];' (the default BKDReader.clone in the same commit already cloned its per-level split values); branch_9x backport 9adf7e27f97b (#457) [read]. The contract was widened a week later by a590c6d2a08 (LUCENE-10262, #476, 2021-11-26, 'Lift up restrictions for navigating PointValues#PointTree'), which updated BKDReader.clone but not the SimpleText fork; from then on every trigger is inside the contract.",
   "introduced_date": "2021-11-19 (LUCENE-9820, the defect); 2021-11-26 (LUCENE-10262, contract widened to random navigation)",
   "first_affected_version": "9.1.0 [exec]: LUCENE-9820 and LUCENE-10262 both first shipped there; 9.0.0 and all earlier releases have no PointTree API (the repro does not compile on 9.0.0) [exec], so the defect was born with the API and is not a regression",
   "affected_versions": "every release with the PointTree API, 9.1.0 through 9.12.3 and 10.0.0 through 10.5.2 (the last release before 10.6.0), 10.6.0, and main (a9779ef3c193 and 645d4fe14a20, unreleased 11.0); never fixed upstream. [exec] the minimal test fails on 10.6.0 and main 645d4fe14a20 (-ea and -da) and on 9.1.0 (-ea); the finder's JUnit fails 1 of 1 on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea; main also -da); the independent reproduction's no-moveToParent visit trigger fails on 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea); the independent reproduction's JUnit fails 4 of 6 with -da (4 of the 5 that run with -ea; its default-codec controls pass) on 10.5.2 and 9.12.3 (-ea and -da), 9.1.0 (-da) and main (-ea and -da); a separate JUnit fails 3 of 6 on 10.5.2, 9.12.3 and main (-ea and -da). [read] the other 28 releases: the clone() line is present at all 32 tags from 9.1.0 to 10.5.2 and absent from 9.0.0; the only later edits to clone/push/pop are mechanical (LUCENE-10264 in.clone() before 9.1.0; BKDConfig record accessors in 10.0.0).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-753.html",
   "repro": "repro/LFV-753/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-071",
   "priority": "low",
   "priority_rank": 1070,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / vectors",
   "title": "Panama minMaxScalarQuantize rounds differently from the default implementation at one boundary value",
   "summary": "You scalar-quantize vectors with the Panama vector provider. You expect the same bytes as the default implementation. Instead Panama rounds with (int)fma(x, scale, 0.5f), not Math.round, so the two can differ only when fl(scale*x) == 0.49999997f.",
   "impact_class": "minor",
   "introduced_commit": "#14304 (1e8a1468768) [read]",
   "introduced_date": "2025-03-25",
   "first_affected_version": "10.2.0",
   "affected_versions": "10.2.0-10.6.0 and main [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-071.html",
   "repro": "repro/LFV-071/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-063",
   "priority": "low",
   "priority_rank": 1071,
   "novelty": "new",
   "withheld": false,
   "area": "search / similarities",
   "title": "AxiomaticF2LOG and AxiomaticF2EXP scores drop by 1 ulp as term frequency crosses a power of two",
   "summary": "You score with AxiomaticF2LOG or AxiomaticF2EXP at default parameters and no boost. You expect the score never to decrease as term frequency rises, which impacts-based pruning relies on. Instead it drops by 1 ulp when the frequency crosses a power of two, so a pruned search can return a different top hit than exhaustive search.",
   "impact_class": "silent wrong results",
   "introduced_commit": "LUCENE-7997 (42717d5f4bb) [exec]",
   "introduced_date": "2017-10-24",
   "first_affected_version": "8.0.0 [exec]",
   "affected_versions": "8.0.0 to 10.6.0 (61 releases) and main [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-063.html",
   "repro": "repro/LFV-063/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-072",
   "priority": "low",
   "priority_rank": 1072,
   "novelty": "new",
   "withheld": false,
   "area": "search / similarities",
   "title": "IBSimilarity with DistributionLL returns -0.0f scores",
   "summary": "You score with IBSimilarity and DistributionLL in a degenerate case. You expect a non-negative score. Instead it returns -0.0f, which AssertingScorer rejects, and tie order then depends on slicing.",
   "impact_class": "minor",
   "introduced_commit": "LUCENE-7996 (a8a63464e7d), which made negative scores illegal; the formula itself dates from LUCENE-2959 (cfaf91c7398, 2011) [exec]",
   "introduced_date": "2017-12-06",
   "first_affected_version": "8.0.0 [exec]",
   "affected_versions": "8.0.0 to 10.6.0 (61 releases) and main [exec]; the zero-score tie order only from 10.2.0",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-072.html",
   "repro": "repro/LFV-072/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-162",
   "priority": "low",
   "priority_rank": 1073,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / block-tree terms dictionary (Lucene103 Stats, CheckIndex verbose statistics)",
   "title": "Lucene103 block tree never sets Stats.indexNumBytes, so Terms.getStats() and CheckIndex -verbose print 'index trie: 0 bytes' for every field",
   "summary": "You run CheckIndex -verbose at level 2 or more (or call Terms.getStats()) on an index written with the default codec and expect each field's block-tree statistics to say how many bytes its terms index takes, as the field's javadoc 'Byte size of the index' and the printed label 'index trie: N bytes' promise. Since 10.3.0 the Lucene103 block tree never assigns Stats.indexNumBytes, so every field prints 'index trie: 0 bytes', even a 20,000-term field with 607 blocks in a segment whose .tip file is 2,473 bytes. Nothing else reads the number, so search and indexing are unaffected, and the older Lucene90 block tree had already stopped reporting the real size (a constant such as 56 bytes since 8.6.0), so this is a small diagnostic defect, not a regression of a working metric.",
   "impact_class": "minor",
   "introduced_commit": "878e23f77390058b6787e0a0537de9087d1019b3 on main (PR #14333 'A specialized Trie for Block Tree Index', author gf2121), which created codecs.lucene103.blocktree by copying the Lucene90 block tree; its copy of SegmentTermsEnum.computeBlockStats() drops the 'if (fr.index != null) { stats.indexNumBytes = fr.index.ramBytesUsed(); }' block and nothing else assigns the field, while the same commit relabels Stats.toString from 'index FST:' to 'index trie:'. The released code came from the branch_10x backport 65fd8648eb633b90ca7f7b69bbae39b373ddaa16 (#14563), with identical computeBlockStats and Stats [read]",
   "introduced_date": "2025-04-14 on main (878e23f77390); 2025-05-09 on branch_10x (65fd8648eb63), the commit that reached a release",
   "first_affected_version": "10.3.0 [exec]; 10.2.2 is the last release without the Lucene103 block tree [exec]",
   "affected_versions": "10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2 and main ea57360912ed [exec]; 10.6.0 (released 2026-10-29) [exec]. Not affected in the always-0 form: 10.2.2 and older, which use the Lucene90 block tree (the test cannot compile there; a version-spanning probe reads non-zero values) [exec]. Caveat [exec]: the older value was not the index size either. The Lucene90 code stores FST.ramBytesUsed(), and an off-heap FST reports only its shallow size, so the probe (MMapDirectory, reader opened from the directory) reads a size-independent constant per field: 88 bytes on 8.1.0-8.3.0, 72 on 8.4.0-8.11.4, 80 on 9.0.0 and 56 on 9.12.3, 10.0.0 and 10.2.2; it tracked the size on 7.7.3 and 8.0.0, and on 8.5.2 only with a heap-backed directory (the intended-behaviour check: 65 vs 28,716 bytes on ByteBuffersDirectory), because the FST is always off-heap only from 8.6.0 (LUCENE-9257)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-162.html",
   "repro": "repro/LFV-162/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-062",
   "priority": "low",
   "priority_rank": 1074,
   "novelty": "new",
   "withheld": false,
   "area": "util / automaton",
   "title": "Operations.topoSortStates misses self-loop cycles and returns an order instead of throwing",
   "summary": "You call Operations.topoSortStates on an automaton whose only cycles are self-loops on states that push no child, such as determinized ab* or a+. You expect IllegalArgumentException for a cyclic automaton. Instead it returns an order.",
   "impact_class": "minor",
   "introduced_commit": "#12286 (5d203f8337c)",
   "introduced_date": "2023-05-15",
   "first_affected_version": "9.7.0 [exec]",
   "affected_versions": "9.7.0-10.6.0 (all 25 releases) and main [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-062.html",
   "repro": "repro/LFV-062/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-868",
   "priority": "low",
   "priority_rank": 1075,
   "novelty": "known",
   "withheld": false,
   "area": "core / analysis: AutomatonToTokenStream (automaton to token-graph conversion)",
   "title": "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)",
   "summary": "You build a finite acyclic automaton with one extra state that nothing leads to, for example 0 -a-> 2 and 1 -b-> 2 with state 2 accepting, or you take TokenStreamToAutomaton's output for the text 'the' after a stop filter removed it, and convert it with AutomatonToTokenStream.toTokenStream, whose javadoc asks only for a finite DAG. You expect the token graph of the part reachable from the start (here the single token 'a'), or at least an error that says what is wrong. Instead it throws IllegalArgumentException 'Cycle found in automaton' ('Start node has incoming edges, creating cycle' when the unreachable state points at state 0), because it counts incoming edges over all states but walks only from state 0; the designers knew such input is unsupported (PR #157), but the javadoc never says so and the message is false.",
   "impact_class": "wrong error",
   "introduced_commit": "647255b4d29bb56ddcfdf44bdb6e7d5d0ca76a14 (apache/lucene#157, LUCENE-9963, FlattenGraphFilter robustness with holes, author @glawson0), which created AutomatonToTokenStream as a test helper for FlattenGraphFilter with the all-states in-degree count, the start-edge check and the Kahn pass seeded only with state 0; 8.x backport 75eba3892979 (apache/lucene-solr#2551, branch_8x). The reachability requirement was stated in that PR's design discussion (#157 issue comment 862439629) but never reached the javadoc. [read]. Not a regression.",
   "introduced_date": "2021-08-10 (647255b4d29, author date 2021-08-10T05:06:53+09:00 = 2021-08-09T20:06:53Z); 8.x backport 2021-08-16 (75eba389297)",
   "first_affected_version": "8.10.0 [exec] (the first release with AutomatonToTokenStream; 8.9.0 has no such class [exec]); 9.0.0 on the 9.x line",
   "affected_versions": "Every release that has the class. [exec] the follow-up's core-only main() probe is affected on 8.10.0, 8.10.1, 8.11.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0 and 10.5.2, the branch_10_6 head 4ae946e5a9b9 (10.6.0, released 2026-10-29) and main a9779ef3c193 (-ea and -da); the finder's JUnit fails 3 of 3 on 9.1.0, 9.12.3, 10.0.0, 10.5.2, the branch_10_6 head and main (-ea and -da); the independent reproduction's JUnit fails 3 of 5 on main, 10.5.2 and 9.12.3. [read] 8.11.1-8.11.3, 9.2.0-9.12.2 and 10.1.0-10.5.1 (the tags contain 647255b4d29 or its backport, no logic change in between). Same exceptions and messages in every executed version. One difference for real cycles only: in 8.10.0-9.12.3 an Operations.isFinite pre-check rejected a reachable cycle as 'Automaton must be finite' (removed by #11813, 15f3743f02c, first released in 10.0.0), so in those versions the two 'cycle' messages could fire only for automata with an unreachable state that has a transition [read]. Not affected: 8.9.0 and earlier (class absent) [exec]. Not fixed upstream: the newest commit to the file on main is 7335eb0ad96 (#15704, author date 2026-02-26, container refactor), checked against upstream main head c5ab3e57b9ba on 2026-10-28 [read]. All runs with JDK 25 on aarch64.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/157",
    "https://issues.apache.org/jira/browse/LUCENE-9963",
    "https://github.com/apache/lucene/issues/11813",
    "https://github.com/apache/lucene/issues/15704",
    "https://github.com/apache/lucene/issues/11002",
    "https://github.com/apache/lucene/issues/9391"
   ],
   "doc": "",
   "repro": "repro/LFV-868/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-025",
   "priority": "low",
   "priority_rank": 1076,
   "novelty": "new",
   "withheld": false,
   "area": "util / bitsets",
   "title": "FixedBitSet and LongBitSet equals depend on the backing array capacity, not only on the bits",
   "summary": "You compare two FixedBitSet (or LongBitSet) objects with the same length and bits that were built with different backing-array capacities. You expect equals to return true. Instead it returns false.",
   "impact_class": "minor",
   "introduced_commit": "LUCENE-4069 (b889626bc4c on branch_4x, ad2cefee00a on trunk), which added the oversized-array constructor FixedBitSet(long[], int); the whole-array equals line dates from LUCENE-3280 (a17df303e9d, 2011) [read]",
   "introduced_date": "2012-08-02",
   "first_affected_version": "4.0.0 [exec]",
   "affected_versions": "4.0.0 to 10.6.0 and main (LongBitSet since 4.7.0) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-025.html",
   "repro": "repro/LFV-025/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-039",
   "priority": "low",
   "priority_rank": 1077,
   "novelty": "known",
   "withheld": false,
   "area": "analysis, util and document / equals methods",
   "title": "equals(null) throws in KeywordAttributeImpl and MutableValue, and DecodedTriangle.equals throws ClassCastException",
   "summary": "You call equals(null) on a KeywordAttributeImpl or MutableValue, or compare a ShapeField.DecodedTriangle with an object of another type. You expect false, per the equals contract. Instead an exception is thrown (ClassCastException for DecodedTriangle).",
   "impact_class": "crash",
   "introduced_commit": "e9a979f1eb8 (LUCENE-2198) for KeywordAttributeImpl; 0269c89b07f (SOLR-1682) for MutableValue; 62001b9b965 (LUCENE-8620) for DecodedTriangle [read]",
   "introduced_date": "2010-01-27 (e9a979f1eb8); 2010-08-21 (0269c89b07f); 2019-09-09 (62001b9b965)",
   "first_affected_version": "unknown (not yet bisected)",
   "affected_versions": "since 2010 [read]; main [exec]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/6572",
    "https://issues.apache.org/jira/browse/LUCENE-5509"
   ],
   "doc": "",
   "repro": "repro/LFV-039/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-042",
   "priority": "low",
   "priority_rank": 1078,
   "novelty": "known",
   "withheld": false,
   "area": "util / UnicodeUtil",
   "title": "UnicodeUtil.UTF8toUTF32 throws ArrayIndexOutOfBoundsException instead of IllegalArgumentException for lead bytes 0xF8-0xFF",
   "summary": "You pass invalid UTF-8 whose lead byte is 0xF8-0xFF to UnicodeUtil.UTF8toUTF32. You expect the IllegalArgumentException its javadoc promises. Instead an ArrayIndexOutOfBoundsException is thrown.",
   "impact_class": "wrong error",
   "introduced_commit": "unknown (not yet bisected)",
   "introduced_date": "unknown (not yet bisected)",
   "first_affected_version": "unknown (not yet bisected; since at least 4.9.1 [exec])",
   "affected_versions": "since at least 4.9.1: 4.9.1, 4.10.4, 5.0.0, 7.4.0, 8.11.4 and main [exec]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/12320"
   ],
   "doc": "",
   "repro": "repro/LFV-042/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-389",
   "priority": "low",
   "priority_rank": 1079,
   "novelty": "new",
   "withheld": false,
   "area": "test infrastructure / JUnit 4 test discovery (core, core.tests, monitor, distribution.tests, analysis-common hunspell)",
   "title": "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')",
   "summary": "You run Lucene's test suite on main and expect TestRuntimeDependenciesSane, TestCandidateMatcherVisibility, TestClassloadingDeadlock, TestModularLayer and TestScripts to run their 17 test methods, and TestHunspellRepositoryTestCases to check Hunspell's test data when -Phunspell.repo.path is set. Instead the build passes without running any of those methods: #16028 removed their @Test annotations, which is harmless in LuceneTestCase subclasses (LuceneTestCase finds test* methods by name), but these six classes do not extend LuceneTestCase, so JUnit 4 finds only @Test methods and there are none. Two classes report zero tests, three report one green placeholder named after the class, and the Hunspell runner fails with 'No runnable methods'.",
   "impact_class": "minor",
   "introduced_commit": "bfa16d51c21b323e7ba5d9ca06f9150774ce4c7d, apache/lucene#16028 'Misc junit4 test cleanups' (by dweiss, merged to main 2026-05-02, milestone 11.0.0, 0 reviews, 0 comments; parent 41ebd23821a) [exec] [read]. The zero-test (rather than 'No runnable methods') symptom of the two plain JUnit 4 classes comes from main's earlier switch to the JUnit Platform vintage engine (5d7f8bd46fb, #15949, 2026-04-10, main only), which is not itself a defect.",
   "introduced_date": "2026-05-02",
   "first_affected_version": "unreleased (main / 11.0.0-SNAPSHOT from bfa16d51c21 on; no release tag contains the commit, and releases 10.5.0-10.5.2, tagged later, come from branch_10_5, which never received it) [read]",
   "affected_versions": "main from bfa16d51c21 (2026-05-02) through 645d4fe14a20 [exec]; branch_11x (603af870375), cut from main on 2026-10-28, has the six files unchanged [read]; upstream main as of 2026-10-26 (head cf398bfb142c) still has no @Test in any of the six files [read]. Not affected: 9.12.3, 10.4.0, 10.5.0 and 10.5.2, each release's own test sources on its own jars [exec]; every release tag 9.0.0-10.5.2 and branch_10x, branch_10_6 and branch_10_5 have the annotations [read]. The defect travels with the test sources, not the jars (main's test sources on 10.5.2 jars fail 2 of 2) [exec].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-389.html",
   "repro": "repro/LFV-389/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1013",
   "priority": "low",
   "priority_rank": 1080,
   "novelty": "new",
   "withheld": false,
   "area": "tests / test-method discovery (core geo TestXYRectangle, core automaton TestOperations, analysis-common TestCommonGramsFilter)",
   "title": "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",
   "summary": "You run Lucene's test suite and expect every method written as a test to run. Four are named 'tes...' or 'Test...' instead of 'test...', so Lucene's runner, which picks only public no-arg methods whose names start with lowercase 'test' (or that carry @Test), silently skips TestXYRectangle.tesInvalidMinMaxX/Y, TestOperations.TestOptionalOptionalAcceptsState0 and TestCommonGramsFilter.TestFirstAndLastStopWord. Run under 'test...' names, the two TestXYRectangle methods fail, because they look for '5 > 4' while XYRectangle correctly reports 'minX must be lower than maxX, got 5.0 > 4.0'; the library itself behaves correctly.",
   "impact_class": "minor",
   "introduced_commit": "4a54ffb553ad (apache/lucene-solr#1252, LUCENE-9218, by iverase; branch_8x backport ca3319cdbce1) for TestXYRectangle.tesInvalidMinMaxX/Y, created misnamed and with the '5 > 4' checks in the same commit that added XYRectangle's float bounds and its min > max IllegalArgumentException [read]; de1ed71261d5 (apache/lucene#14218, by rmuir; branch_10x backport b74580c51f0c) for TestOperations.TestOptionalOptionalAcceptsState0, split out of the running testOptional [read]; b105beef661a (SOLR-1674, in the Solr test), moved into the Lucene tree by 1d1331fa033f (LUCENE-2413) for TestCommonGramsFilter.TestFirstAndLastStopWord [read]. Each method was created with its final name; none was renamed into this state later [read]",
   "introduced_date": "2020-02-14 (TestXYRectangle pair); 2025-02-13 (TestOperations method); 2009-12-21 in the Solr test, 2010-05-04 in the Lucene tree (TestCommonGramsFilter method)",
   "first_affected_version": "8.5.0 for the TestXYRectangle pair, the only real coverage loss [exec]; 10.2.0 for the TestOperations method [exec]; 4.0.0-alpha for TestFirstAndLastStopWord, the oldest [read]",
   "affected_versions": "main 645d4fe14a20 [exec]; 10.6.0 (4ae946e5a9b) [exec]; branch_10x 657014b3c579 [read]; 10.5.2 [exec]; 9.12.3 [exec]; 8.11.4 and 8.5.0 [exec]; 10.2.0 [exec]; 4.0.0 [exec]; every release tag from 8.5.0 to 10.5.2 has the TestXYRectangle pair and every one from 4.0.0-alpha has TestFirstAndLastStopWord [read]. Not affected: 8.4.1 for the TestXYRectangle pair (no such test and no IllegalArgumentException; XYRectangle only asserted) [exec]; 10.1.0 for the TestOperations method (absent; testOptional held an earlier related check and ran) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1013.html",
   "repro": "repro/LFV-1013/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-576",
   "priority": "low",
   "priority_rank": 1081,
   "novelty": "known",
   "withheld": false,
   "area": "test-framework / merge policies (ForceMergePolicy; FilterMergePolicy forwarding of MergePolicy.findFullFlushMerges for merge-on-commit and merge-on-getReader)",
   "title": "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)",
   "summary": "You wrap a merge policy in the test framework's ForceMergePolicy, documented as 'A MergePolicy that only returns forced merges' for when you 'wish to disallow background merges', keep the rest of IndexWriterConfig at its defaults, and commit or open an NRT reader after each of several small flushes. You expect every flushed segment to stay until you call forceMerge, as with NoMergePolicy. Instead ForceMergePolicy only nulls findMerges and inherits FilterMergePolicy's forward of findFullFlushMerges, whose MergePolicy default runs the wrapped policy's own natural merges of small segments, so with the default 500 ms merge-on-commit wait 25 one-document commits leave 1 segment instead of 25 (and an NRT reader after 25 flushes has 1 leaf).",
   "impact_class": "minor",
   "introduced_commit": "b5795db0cf517f8942eed868752249df9b105603 on main, 'LUCENE-10078: Enable merge-on-refresh by default. (#921)' (apache/lucene#921, written and merged by jpountz; issue #11116), and its branch_9x backport 7d9de759f244896d47da77c842051845199d316e (same day, same diff) [read]. It changed MergePolicy#findFullFlushMerges from 'return null' to 'the natural findMerges merges whose segments are all below maxFullFlushMergeSize()' and IndexWriterConfig.DEFAULT_MAX_FULL_FLUSH_MERGE_WAIT_MILLIS from 0 to 500, without touching ForceMergePolicy; the PR and issue discussions never mention ForceMergePolicy. Latent root: 7f352a96659b4d304ae3ef0c7a1b62784ce2a406 on main ('LUCENE-8962: Merge small segments on commit (#1617)', apache/lucene-solr#1617; branch_8x 9b1c92809e7) added the hook, made FilterMergePolicy forward it and NoMergePolicy return null, but gave ForceMergePolicy (created by LUCENE-6925, 8575e3fb3a3, 2015) no override; from then on a wrapped policy that implements the hook itself (a custom policy, or the test framework's MockRandomMergePolicy) plus a non-zero wait gets its full-flush merges through ForceMergePolicy [exec]",
   "introduced_date": "2022-06-07 (default-config exposure, LUCENE-10078); 2020-06-27 (latent forwarding gap, LUCENE-8962)",
   "first_affected_version": "9.3.0 with stock merge policies and an otherwise default IndexWriterConfig [exec]; with a wrapped policy that implements findFullFlushMerges (a custom policy or MockRandomMergePolicy) plus a non-zero wait: 8.6.0 for commit and 8.7.0 also for NRT reopen [exec]; before 8.6.0 the hook API does not exist [exec]",
   "affected_versions": "default config with stock policies: every release from 9.3.0 to 9.12.3 and every 10.x release to 10.6.0 (10.6.0 by reading), branch_10_6, the unreleased branch_10x, and main ea57360912ed and a9779ef3c193 [exec]; not affected with default config: 8.x, 9.0.0, 9.1.0 and 9.2.0 [exec]; with a wrapped policy that implements the hook plus a non-zero wait: every release from 8.6.0 on [exec]; not fixed upstream [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15817",
    "https://issues.apache.org/jira/browse/LUCENE-10649",
    "https://github.com/apache/lucene/issues/11685",
    "https://github.com/apache/lucene/issues/1025",
    "https://github.com/apache/lucene/issues/7983",
    "https://issues.apache.org/jira/browse/LUCENE-6925"
   ],
   "doc": "",
   "repro": "repro/LFV-576/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-664",
   "priority": "low",
   "priority_rank": 1082,
   "novelty": "new",
   "withheld": false,
   "area": "test-framework / search: AssertingLeafCollector DocIdStream wrapper (AssertingIndexSearcher, bulk collection)",
   "title": "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",
   "summary": "In a Lucene test you search with LuceneTestCase.newSearcher (an AssertingIndexSearcher) and a collector whose collect(DocIdStream) first calls stream.forEach(5, consumer) and then stream.count() for the rest, which the DocIdStream javadoc allows ('up to the given upTo exclusive ... It is not possible to iterate these doc IDs again later on'). You expect the split a plain IndexSearcher gives: docs 0-4 in the first step and docs 5-9 counted afterwards. Instead the test framework's wrapper calls the wrapped stream's unbounded forEach, so the first step also receives docs 5-9 and the second step gets nothing (with -da), and with -ea the nested wrapper then rejects the legal count() with AssertionError 'exhausted'.",
   "impact_class": "minor",
   "introduced_commit": "82200c0f4f7396b0312fe7b85eccc3f09453af4f on main, apache/lucene#14273 'Speed up histogram collection in a similar way as disjunction counts.' (GitHub jpountz; reviewers epotyom and gsmiller, approved by gsmiller), backported to branch_10x as 0018e62cf21fe589633b01812fe9ec49fd42b426 (same AssertingLeafCollector.java blob ca05ef76f878) [read]. The PR added the bounded DocIdStream.forEach(int upTo, ...) and the wrapper override together; the unbounded call is already in the PR's first revision 0ca1b737de65 and never changed, so this is an original defect, not a regression",
   "introduced_date": "2025-03-28",
   "first_affected_version": "10.2.0 [exec], the first release with DocIdStream.forEach(int upTo, ...); 10.1.0, 10.0.0 and 9.12.3 do not have that method [exec]",
   "affected_versions": "every release from 10.2.0 through 10.6.0 (executed: 10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2; on 10.6.0 and main 645d4fe14a20 the minimal repro fails with -ea and -da, 2026-11-01) and main a9779ef3c193; never fixed. [exec] the finder's JUnit (seed 5EED0205) fails 2/2 with -ea and with -da on each of those releases and on main (follow-up); the independent reproduction executed 10.2.0 and 10.5.2 (-ea and -da) and the intended-behaviour check 10.5.2 (-ea and -da) with the same result; the one-line fix shadowed onto 10.2.0 and 10.5.2 passes 2/2 with -ea and -da. [read] upstream main a95c754ee003, branch_10x 657014b3c579 and branch_10_6 (10.6.0, released 2026-10-29) 4ae946e5a9b9 still make the unbounded call (2026-10-26/27); the last commit to the file on upstream main is 14a3b87e75e0 (#16144, 2026-05-31), which does not touch this method (rechecked read-only 2026-10-27)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-664.html",
   "repro": "repro/LFV-664/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-073",
   "priority": "low",
   "priority_rank": 1083,
   "novelty": "new",
   "withheld": false,
   "area": "test-framework / similarities",
   "title": "BaseSimilarityTestCase's 'scores don't decrease as terms get rarer' check is dead code",
   "summary": "You validate a custom Similarity with lucene-test-framework's BaseSimilarityTestCase. You expect it to check that scores do not decrease as terms get rarer, as documented. Instead the check rescores term instead of prevTerm and can never fail; fixing it fails TestBasicModelG 8/8, Indri 4/8 and SPL 1/8 seeds.",
   "impact_class": "minor",
   "introduced_commit": "LUCENE-7997 (42717d5f4bb); the check was wrong when it was written",
   "introduced_date": "2017-10-24",
   "first_affected_version": "8.0.0 [exec]",
   "affected_versions": "8.0.0 to 10.6.0 (61 releases) and main [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-073.html",
   "repro": "repro/LFV-073/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-102",
   "priority": "low",
   "priority_rank": 1084,
   "novelty": "new",
   "withheld": false,
   "area": "test-framework / search checkers (CheckHits)",
   "title": "CheckHits.checkTopScores (test framework) fails on correct minimum-should-match disjunctions because it walks the COMPLETE and TOP_SCORES two-phase approximations in lockstep",
   "summary": "In a test you call the test framework's CheckHits.checkTopScores on a BooleanQuery of three term clauses with setMinimumNumberShouldMatch(2), for example (f:a f:b f:c)~2. You expect it to pass, because the query returns the same matching docs with the same scores in COMPLETE and TOP_SCORES mode (checked in the same test). Instead it throws AssertionError 'expected:<1> but was:<0>' in CheckHits.doCheckMaxScores (CheckHits.java:751): the checker requires the two scorers' two-phase approximations, which only have to be supersets of the matches, to stop on the same docs, and the TOP_SCORES WANDScorer legitimately stops on doc 0 (it holds only 'c'), which matches() then rejects.",
   "impact_class": "minor",
   "introduced_commit": "c2493283a58 (LUCENE-9346 'Support minimumNumberShouldMatch in WANDScorer', apache/lucene-solr#2141, main) and its branch_8x backport 74c0a978148, which shipped first, in 8.8.0 [exec]: from it on, TOP_SCORES with minimumNumberShouldMatch > 1 uses WANDScorer, whose approximation can stop on docs that the COMPLETE approximation skips. The failing lockstep assertion itself is older and was latent until then: 4fb7e3d02c6 (LUCENE-8135 'Implement block-max WAND', 2018-02-15, first released in 8.0.0) [read]. LUCENE-9346 is a legitimate scorer change that exposed the checker's assumption, not a scorer bug. Later: LUCENE-9668 (7f4d4dfdbf6, backport d266a09ff4c, 8.9.0) kept the failure, and #13996 (a67120e1754, 10.1.0) re-exposed the plain unboosted input after it had passed on 9.12.0-10.0.0 [exec]",
   "introduced_date": "2021-01-11 (LUCENE-9346 merge and branch_8x backport); the latent assertion dates from 2018-02-15 (LUCENE-8135)",
   "first_affected_version": "8.8.0 [exec]; 8.7.0 passes [exec]",
   "affected_versions": "every release from 8.8.0 to 10.5.2 (44 releases: 8.8.0-8.8.2, 8.9.0, 8.10.0, 8.10.1, 8.11.0-8.11.4, all 21 9.x and the 12 10.x releases before 10.6.0) and main ea57360912ed fail [exec]; both probe inputs fail on 8.8.0-9.11.1 and 10.1.0-main, while on 9.12.0-10.0.0 only the boosted (a b c^10)~2 input fails and the plain (a b c)~2 input passes (that pass is not bisected) [exec]; 8.0.0-8.7.0 pass (all 16 releases) [exec]; before 8.0.0 the API did not exist (7.x has no checkTopScores and no ScoreMode) [read]; upstream main, branch_10x and branch_10_6 have a doCheckMaxScores body byte-identical to ea57360912ed (2026-10-26), and 10.6.0 (released 2026-10-29) fails too [exec]; not fixed upstream [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-102.html",
   "repro": "repro/LFV-102/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-033",
   "priority": "low",
   "priority_rank": 1085,
   "novelty": "new",
   "withheld": false,
   "area": "test-framework / postings formats",
   "title": "Test-framework RAMOnlyPostingsFormat cannot index DOCS-only fields",
   "summary": "In a test, you index a field with IndexOptions.DOCS using the test framework's RAMOnlyPostingsFormat. You expect indexing to work as with other postings formats. Instead it throws NegativeArraySizeException and the writer closes tragically.",
   "impact_class": "minor",
   "introduced_commit": "42bd0e24f87 on branch_4x and its trunk twin e0d137f8e2ad (same patch), LUCENE-4248 'Producers to the Codec API don't always follow the spec' (Robert Muir, 2012-07-23; the commit message says LUCENE-4828, very likely a typo): the indexing chain and PostingsConsumer.merge pass freq -1 instead of 0 for DOCS_ONLY fields, while RAMOnlyPostingsFormat's RAMDoc kept new int[freq] [exec]",
   "introduced_date": "2012-07-23 (first released in 4.0.0-BETA)",
   "first_affected_version": "4.0.0-BETA [exec] (first final release 4.0.0); 4.0.0-ALPHA passes [exec]",
   "affected_versions": "every release from 4.0.0-BETA to 10.6.0 (132 releases) and main [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-033.html",
   "repro": "repro/LFV-033/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-823",
   "priority": "low",
   "priority_rank": 1086,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter delete-by-query (deleteDocuments(Query...) and updateDocuments(Query, ...) javadoc and class NOTE vs deferred application in FrozenBufferedUpdates and the applyUpdatesPacket tragic close)",
   "title": "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)",
   "summary": "You index 10 documents with a StringField id, commit 6 of them, and call deleteDocuments(new PhraseQuery(\"id\", \"d1\", \"d2\")), which returns a sequence number; nothing in its javadoc says the query runs later or what happens if it fails then. The query actually runs only when the buffered delete is applied, and because a StringField has no positions the PhraseQuery throws IllegalStateException at that point: the exception comes out of the next commit (or flush, NRT open, merge, close, or an unrelated addDocument), the IndexWriter closes itself and the 4 uncommitted documents are gone. The close is a deliberate fail-safe (the same documents are lost without it); what is missing is a warning on deleteDocuments(Query...) and both updateDocuments(Query, ...) overloads, and in the class NOTE on when the writer closes itself.",
   "impact_class": "minor",
   "introduced_commit": "58105a203a19d18a56e09cf69dc0083c1b890315 (LUCENE-7868 'use multiple threads to concurrently resolve deletes and DV udpates', JIRA issue now GitHub #8919, committed as a patch, no GitHub PR; author mikemccand, CHANGES credits s1monw and mikemccand) [read]. It made an exception thrown while applying a buffered-updates packet a tragic event and updated neither the class NOTE nor the deleteDocuments(Query...) javadoc. Later refactors kept it (LUCENE-8269 6f0a884582a, LUCENE-8271 d32ce909241 moved it into the IndexWriter.publishFrozenUpdates lambda, LUCENE-8571 5f8855ee0bf, #14668 0a4a76f0a86). The deferred evaluation it sits on is older: 5b113c8af63 (LUCENE-1194, deleteDocuments(Query) added, 2008-03-06, first release 2.4.0) [read]",
   "introduced_date": "2017-06-21 (author date = commit date of 58105a203a1); the deferred evaluation dates from 2008-03-06 (LUCENE-1194); updateDocuments(Query, Iterable) 2023-06-03 (#12346), updateDocuments(Query, ColumnBatch) 2026-06-19 (#16168)",
   "first_affected_version": "7.0.0 [exec] (first release with the tragic close: finder, tie-break and follow-up history runs; release-tag scan [read]: the string applyUpdatesPacket is at all 65 local tags 7.0.0-10.5.2 and at none of the 33 tags 5.0.0-6.6.6). The undocumented deferred failure itself is older: 4.0.0 to 6.6.6 show the pre-7.0 stuck form (writer stays open, every commit and close() throw the query's exception, the uncommitted documents never reach the index unless the application calls rollback()) [exec]; API since 2.4.0 [read]",
   "affected_versions": "every release from 7.0.0 through 10.5.2, 10.6.0 (by reading) and main a9779ef3c193 in the tragic form [exec]; updateDocuments(Query, Iterable) from its first release 9.7.0 and updateDocuments(Query, ColumnBatch) from its first release 10.5.0 [exec]; branch_10_6 head 4ae946e5a9b has the same code [read]; 4.0.0-6.6.6 in the pre-7.0 stuck form [exec]. The deleteDocuments(Query...) javadoc is substantively the same at the 6.6.6, 7.0.0, 9.12.3 and 10.5.2 tags and on main [read]. Not fixed upstream: upstream main 20ced71c1e6e has the same code and text; IndexWriter.java and FrozenBufferedUpdates.java were last changed by 169cbffd12f (author date 2026-09-21), not on this path [read]. All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/8531",
    "https://github.com/apache/lucene/issues/8398",
    "https://github.com/apache/lucene/issues/9738",
    "https://issues.apache.org/jira/browse/LUCENE-8692",
    "https://github.com/apache/lucene/issues/16905",
    "https://github.com/apache/lucene/issues/16923"
   ],
   "doc": "",
   "repro": "repro/LFV-823/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-847",
   "priority": "low",
   "priority_rank": 1087,
   "novelty": "known",
   "withheld": false,
   "area": "queryparser / classic and flexible standard grammars (_WHITESPACE, _TERM_START_CHAR) and the query syntax documentation",
   "title": "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'",
   "summary": "You parse 'title:foo AND -bar' with the classic or the flexible query parser, but the spaces are EM SPACEs (U+2003), as in text pasted from a formatted document; nothing in the query syntax docs says which characters separate clauses, so you expect the same query as with ordinary spaces, '+title:foo -body:bar'. Instead both grammars separate clauses only on space, TAB, LF, CR and U+3000, so 'foo<EM>AND<EM>-bar' is one term that the analyzer splits under the first field: the result is 'title:foo title:and title:bar', AND became the search word 'and', the '-' exclusion is gone and a document whose body contains bar now matches (2 hits instead of 1). The closed separator set is very likely intended, so the defect is the missing documentation; when the next clause has its own field prefix ('-body:bar') both parsers throw ParseException instead.",
   "impact_class": "minor",
   "introduced_commit": "bd3948c539ec1065db8b05b433ea55dbf844ff27 (svn r149570, 'Initial revision', 2001-09-18: the import of the parser's pre-Apache sources; the cvs2svn tag releases/lucene/1.0.1 points at this tree): the parser arrived with a closed separator list, _WHITESPACE = ' ' | TAB, and no Unicode space outside the list has separated clauses in any version since [exec]. The silent absorption of the four breakable spaces above U+00FF (U+2002, U+2003, U+2009, U+205F) into a term began with 584d2b394b0 (2001-11-01, 'Fix query parser so it accepts queries with unicode characters', CHANGES 1.2 RC3 item 3); before it they made parse() throw a lexical error, while U+00A0 and U+0085 were already silently part of the term [exec]. Documentation side: the query syntax page added by c092af6cfa3 (2002-05-15, 1.2) says 'A query is broken up into terms and operators' and never defines the separators; the same sentence is in classic/package-info.java today [read]. Commits that shaped the list later: 1fa4fa82d12 (2002-01-17, every unlisted character becomes a term character), 9ada9671259 (2004-03-03, LUCENE-93 / #1171: LF and CR added), 1ebfc379fd8 (2004-03-24, Bugzilla 27491: '-' and '+' allowed inside terms, so the '-' of '-bar' is absorbed too), 13d5245314e (2009-01-28, LUCENE-1528 / #2602: U+3000 added, deliberately and alone), 343992fcbb4 (2009-08-03, LUCENE-1567 / #2641: the flexible parser created with the same five characters), 7d092fac4ea / 17d113dac1e (2016-07-05, LUCENE-2605: setSplitOnWhitespace, whose javadoc uses 'whitespace' without defining it) [read]. No issue or PR for the introducing commits (svn era, pre-JIRA)",
   "introduced_date": "2001-09-18 (initial revision: closed separator list); 2001-11-01 (584d2b394b0: silent absorption of the breakable spaces above U+00FF); 2002-05-15 (c092af6cfa3: syntax documentation added without a separator definition)",
   "first_affected_version": "1.0.1 [exec] (the cvs2svn tag of the imported pre-Apache sources; the first release cut in the Apache repository is 1.2-rc1). In 1.0.1 to 1.2-rc2 U+00A0, U+0085, VT, FF and U+001C-U+001F are silently part of a term while the four breakable spaces above U+00FF throw a lexical error; the silent misparse of those four starts in 1.2-rc3 [exec]; first affected release on Maven Central: 1.2 [exec]; the flexible StandardQueryParser is affected from 2.9.0, the release that added it [exec]",
   "affected_versions": "Every release from 1.0.1 to 10.5.2 (latest 9.x: 9.12.3; latest 10.x before 10.6.0: 10.5.2), the branch_10_6 head 4ae946e5a9b9 (10.6.0, released 2026-10-29) and main a9779ef3c193; no last good version and no fix: the two grammar lines are unchanged on upstream main 20ced71c1e6e, branch_10x and branch_10_6, and the classic and flexible syntax docs still say nothing about separators (2026-10-28 [read]). Classic QueryParser in every release, flexible StandardQueryParser from 2.9.0. [exec] history probe (one class, public parse API through reflection, 24 characters, analyzer-dependent and analyzer-independent checks against the U+0020 form): 162 release jars (1.2, 1.3-rc1, 1.3, 1.4.1, 1.4.2, 1.4.3 as plain JDK runs on SHA-1-checked Maven Central jars, and all 156 releases from 1.9.1 to 10.5.2 through repro.sh), the regenerated grammars of 1.0.1, 1.2-rc1, 584d2b394b0, 1fa4fa82d12, 1.2-rc3 and 1.2, the branch_10_6 head and main (-ea and -da): every one affected, with controls holding (TAB always a separator, U+3000 one exactly from 2.9.0). Only the shape of the wrong query changes (U+2003, classic): 1.2-1.3 'title:foo -body:bar', 1.4.1-2.9.4 'title:\"foo bar\"', 3.0.x 'title:\"foo ? bar\"', 3.1.0-7.7.3 'title:foo title:bar', 8.0.0-main 'title:foo title:and title:bar'. The finder's JUnit fails 3/3 on main (-ea and -da), the branch_10_6 head, 10.5.2 (-ea and -da) and 9.12.3 (it does not compile before 9.1, older test-framework package); the independent reproduction's JUnit fails 3 of 5 (controls pass) on main (-ea and -da), 10.5.2, 9.12.3 and the branch_10_6 head. [read] releases not on Maven Central (1.2-rc4/rc5, 1.3-rc2/rc3, 1.4-rc1 to 1.4, 1.9-rc1, 1.9) have the same whitespace and term-character rules as their executed neighbours. Affected characters (classic and flexible): U+000B, U+000C, U+0085, U+00A0, U+1680, U+2000-U+200A, U+2028, U+2029, U+202F, U+205F (Unicode White_Space) and U+001C-U+001F (Character.isWhitespace only). All runs JDK 25.0.3 on aarch64; the behaviour is in the generated lexer tables, so no platform dependence is expected (not executed on x86)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16688",
    "https://github.com/apache/lucene/issues/2199",
    "https://issues.apache.org/jira/browse/LUCENE-1122",
    "https://github.com/apache/lucene/issues/2076",
    "https://issues.apache.org/jira/browse/LUCENE-1000",
    "https://github.com/apache/lucene/issues/2602"
   ],
   "doc": "",
   "repro": "repro/LFV-847/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-514",
   "priority": "low",
   "priority_rank": 1088,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / phonetic (PhoneticFilter and DaitchMokotoffSoundexFilter output from the bundled commons-codec); release notes (lucene/CHANGES.txt, lucene/MIGRATE.md)",
   "title": "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)",
   "summary": "You index a field with a phonetic filter, for example PhoneticFilter with ColognePhonetic, upgrade Lucene and keep searching the same index; you expect the same tokens or a CHANGES/MIGRATE note telling you to re-index, as Lucene gave in 2014 for the Beider-Morse change of the commons-codec 1.10 upgrade (LUCENE-6058) and gives on main for the Snowball upgrade (GITHUB#15505). Instead the bundled commons-codec moved from 1.13 (up to 10.1.0) to 1.17.2 (10.2.0 to 10.6.0) and to 1.23.0 (main) with no note anywhere, and its encoder fixes change the tokens: 'Köln' gets the RefinedSoundex code K378 from 10.2.0 (10.1.0 kept only the word), and on main 'chantaient' becomes XNTN instead of KNTN (Metaphone), 'quick' 4 instead of 44 (ColognePhonetic) and \"it's\" 040000 instead of 034000 (Daitch-Mokotoff). An index written by the older version and searched by the newer one silently misses or changes matches in that field until it is re-indexed (executed: ColognePhonetic with inject=false, the query 'quick' finds no document in a 10.5.2 index searched by main, against 2 in a fresh index).",
   "impact_class": "minor",
   "introduced_commit": "118afb7054fc (main, GITHUB#14129 'Upgrade commons-codec from 1.13.0 to 1.17.2', a hand-written PR) and its branch_10x backport 279502600af3 (GITHUB#14177 'Upgrade opennlp and codec 10x'), which shipped the RefinedSoundex change in 10.2.0; main only: the dependabot bumps d8cf8f7fb301 (GITHUB#14982, 1.18.0 -> 1.19.0: Daitch-Mokotoff) and 43f310fca2c5 (GITHUB#16035, 1.21.0 -> 1.22.0: Metaphone, ColognePhonetic). No Lucene source line introduced the defect: these are dependency pins whose commits touch only build files (version catalog, lock file, license checksums; #14129 also one test module-info line) and add no CHANGES or MIGRATE text [read] [exec]",
   "introduced_date": "2025-01-27 (#14129 on main); 2025-01-29 UTC (#14177 on branch_10x); main-only parts 2025-07-24 (#14982) and 2026-05-06 (#16035)",
   "first_affected_version": "10.2.0 [exec] (RefinedSoundex part only; the first release after #14177). The Metaphone, ColognePhonetic and Daitch-Mokotoff parts are unreleased: main only, the first release would be 11.0.0",
   "affected_versions": "10.2.0, 10.2.1, 10.2.2, 10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1 and 10.5.2 [exec] (RefinedSoundex part only: the finder's JUnit fails 1 of 4 on each, stock release jars with their commons-codec 1.17.2); main ea57360912ed (11.0.0-SNAPSHOT, commons-codec 1.23.0) [exec] all four parts, -ea and -da. Not affected [exec]: 9.12.3, 10.0.0 and 10.1.0 (commons-codec 1.13; every release from 9.0.0 to 10.1.0 pins 1.13 [read]). branch_10x and branch_10_6 [read] still pin 1.17.2, and 10.6.0 (released 2026-10-29) carries only the RefinedSoundex part [exec], and a later 10.6.x would too unless a newer commons-codec is backported. Measured only for the four encoders above; DoubleMetaphone, Soundex, Caverphone2 and Nysiis were unchanged on a 53-word probe and BeiderMorseFilter (GENERIC/APPROX) on 6,901 words, and the Beider-Morse changes listed in the 1.19.0 and 1.23.0 release notes were not otherwise measured. Executed only on aarch64 Linux with JDK 25 (plain Java string logic); main 645d4fe14a2 [exec]; branch_10x 657014b3c57 and branch_10_6 4ae946e5a9b (10.6.0 RC1) still pin commons-codec 1.17.2 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-514.html",
   "repro": "repro/LFV-514/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-870",
   "priority": "low",
   "priority_rank": 1089,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / synonym.word2vec (Word2VecSynonymFilter minAcceptedSimilarity javadoc vs Word2VecSynonymProvider threshold test)",
   "title": "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",
   "summary": "You build Word2VecSynonymFilter with minAcceptedSimilarity 0.8 (the factory default), whose only documentation says it is the 'minimal value of cosine similarity between the searched vector and the retrieved ones', so you expect only model terms at cosine 0.8 or more as synonyms. Word2VecSynonymProvider compares the threshold with the DOT_PRODUCT score of the unit-length model vectors, which is (1 + cosine) / 2, so the real cosine cutoff is 2m - 1: at 0.8 a term at cosine 0.65 is emitted, at 0.5 an orthogonal term (cosine 0) is emitted, and at 0.2 a term at cosine -0.5 is emitted. The authors' intent points to the score scale (the factory accepts only (0, 1]), so the fix is a javadoc clarification, not a code change.",
   "impact_class": "minor",
   "introduced_commit": "1f4f2bf50957ad1a13c32d5351c7de77154953f1 on main (apache/lucene#12169 'Introduced the Word2VecSynonymFilter', feature issue #12168; author dantuzi, co-author Alessandro Benedetti; first on the main line in 10.0.0) and its branch_9x re-backport 64b48b89b501 (committed 2023-05-30, author date 2023-04-24; first in 9.7.0; an earlier backport 53709ccaecc was reverted by 7e15a390688 on 2023-04-25) [read] check to 1f4f2bf5095; git blame at the 9.7.0 tag names 64b48b89b50; git log --all -S on each of them lists only these commits and the revert]. Every part of the mismatch is in the first version; no later commit changed it.",
   "introduced_date": "2023-04-24 (main 1f4f2bf5095, author and commit date); 2023-05-30 (branch_9x re-backport 64b48b89b50, author date 2023-04-24)",
   "first_affected_version": "9.7.0 [exec] (the first release with the API; 9.6.0 has no synonym.word2vec package and the repros do not compile there [exec]); first on the main line: 10.0.0 [exec]",
   "affected_versions": "Every release that has the API: 9.7.0 to 9.12.3 and 10.0.0 to 10.5.2, 24 releases [exec], the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) [exec] and main a9779ef3c193 [exec]. Unchanged on upstream main c5ab3e57b9b (2026-10-28), branch_10x 1309534296e and branch_10_6 2763db11b0a: same javadoc, DOT_PRODUCT, comparison, 0.8f default and (0, 1] check [read]. The 9.9.0 clamp of DOT_PRODUCT to max((1 + dot) / 2, 0) (#12727) changes only scores below 0, which no accepted threshold reaches, and 9.7.0 and 9.8.0 fail the same way [exec]. All runs on aarch64 Linux with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-870.html",
   "repro": "repro/LFV-870/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-351",
   "priority": "low",
   "priority_rank": 1090,
   "novelty": "new",
   "withheld": false,
   "area": "facet / facet sets (MatchingFacetSetsCounts child counts vs. FacetSets.adoc and the demo javadoc)",
   "title": "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)",
   "summary": "You index documents that each hold several facet sets (the adoc's own example: one (genre, year) set per movie of an actor) and count them with MatchingFacetSetsCounts, which the user guide FacetSets.adoc says 'counts how many documents are matched by each of a list of FacetSetMatcher'. You expect each matcher's value to be a number of documents, never larger than FacetResult.value. Instead the code adds 1 for every matching facet set, so one document with the sets (Thriller, 2020) and (Thriller, 2021) gives 2 for a 'Thriller 2020-2022' range matcher while FacetResult.value is 1; upstream tests pin this per-set count, so the conservative fix is to correct the documentation, although maintainers could instead choose per-document counts.",
   "impact_class": "minor",
   "introduced_commit": "f6bb9d218c0e (main, 'LUCENE-10274: Add FacetSets faceting capabilities (#841)', apache/lucene#841 by mdmarshmallow with co-authors shaie and gsmiller per the commit trailers; same-day branch_9x backport 0e1502c12ba (#981, by shaie), the one released in 9.3.0; issue LUCENE-10274 / #11310). The one squash commit added the FacetSets.adoc sentence, the demo javadoc 'Counting documents which match a certain degrees value for any date', the per-set counts[j]++ loop and the demo test that asserts 4 for 2 documents, so the documentation and the code have disagreed from the start; not a regression [read]",
   "introduced_date": "2022-06-25",
   "first_affected_version": "9.3.0 [exec] (first release with the org.apache.lucene.facet.facetset package; 9.2.0 has none [exec])",
   "affected_versions": "every release from 9.3.0 to 10.6.0 and main (ea57360912ed, 645d4fe14a20); not fixed upstream. [exec] the minimal test fails on the 10.6.0 release jars and on main 645d4fe14a20 (-ea and -da) (2026-11-01); the finder's 9.x-compatible JUnit fails on 9.3.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da on main) in the history step and on 9.3.0, 9.4.2 and 9.12.3; the finder's JUnit fails on 10.5.2; the independent reproduction's JUnit fails on 9.4.0, 9.12.3, 10.5.2 and main (-ea and -da). [read] every release tag from 9.3.0 to 10.5.2 contains both the adoc sentence and the per-set loop (git show tag by tag in the history clone); no commit to FacetSets.adoc, MatchingFacetSetsCounts.java or CustomFacetSetExample.java changed the wording or the loop (GitHub commits API, 2026-10-26). The finder's 'since 9.4' and the independent reproduction's '9.4.0 (the first release with facet sets)' are corrected to 9.3.0 (9.3.0 CHANGES.txt: 'LUCENE-10274: Added facetsets module').",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-351.html",
   "repro": "repro/LFV-351/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-830",
   "priority": "low",
   "priority_rank": 1091,
   "novelty": "new",
   "withheld": false,
   "area": "queries / intervals (Intervals.within / Intervals.notWithin and their javadoc; queryparser fn:within / fn:notWithin docs)",
   "title": "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)",
   "summary": "You index 'the new york times' and run within(phrase(new, york), 1, times) and notWithin(phrase(new, york), 1, times), and you expect exactly one of them to match, because the javadoc says within returns source intervals that 'appear within a set number of positions' of the reference and notWithin those that 'do not appear within' it, and the fn:within / fn:notWithin docs give both the same 'maximum positions' parameter. Instead neither matches: within keeps an interval only if all of it lies inside the window [r.start-n, r.end+n] (here [2,4]), while notWithin drops it if any part touches that window, so 'new york' at [1,2], which touches the window without lying inside it, is in neither result (within needs n = 2 for a phrase directly next to the reference). In the same way, on 'new york' both within(phrase(new, york), 0, york) and notWithin(phrase(new, york), 0, york) return nothing, and no doc says that a partly-near interval matches neither.",
   "impact_class": "minor",
   "introduced_commit": "3593af2ac55f12a2ce2cfa76fd58407aa3fafa67 (branch_8x, first released in 8.0.0) and its master twin 7d34bfdaad37a25bfda5df2bf2c2bd1a31540bc2 (same Intervals.java, first released in 9.0.0), both 'LUCENE-8629: New interval functions: before, after, within, overlapping' (@romseygeek; a JIRA patch, no GitHub pull request; the issue is now apache/lucene#9675, whose description lists 'a WITHIN b - inverse of the already available NOT_WITHIN'). It added within = containedBy(source, extend(reference, n, n)) next to the existing notWithin = DifferenceIntervalsSource(minuend, extend(subtrahend, n, n), NON_OVERLAPPING) (LUCENE-8612, 2532a5d31c8, 2019-01-01, also first released in 8.0.0), and in the same commit changed notWithin's @param from 'the maximum distance' to 'the minimum distance' [read] [exec]. The gap needs both factories: notWithin's no-overlap rule predates within (7.4.0-7.7.3 already return no hit for notWithin on both repro documents [exec]). The fn:within / fn:notWithin docs with the shared text 'an integer number of maximum positions between source and reference' came later, with LUCENE-10223 (apache/lucene#429, @dweiss, f725b27e12a, first released in 9.1.0) [read]. Not a regression: within's body is identical in all 30 master revisions of Intervals.java since 7d34bfdaad3 and in main, and notWithin only moved to NonOverlappingIntervalsSource (LUCENE-8477), the same relation [read]",
   "introduced_date": "2019-01-07 (author date of 7d34bfdaad3 and of the branch_8x twin 3593af2ac55); the fn:within / fn:notWithin parser docs 2021-11-11 (f725b27e12a)",
   "first_affected_version": "8.0.0 [exec] (the first release with Intervals.within, shipped in the lucene-sandbox artifact as org.apache.lucene.search.intervals; the package moved to lucene-queries in 8.2.0). 7.4.0 to 7.7.3 have notWithin but no within [exec]; 7.3.1 and earlier have no intervals package [exec]. The fn:within / fn:notWithin query-string route exists from 9.1.0 [read]",
   "affected_versions": "every release from 8.0.0 through 10.5.2, 10.6.0 (its intervals sources at branch_10_6 RC1 4ae946e5a9b [exec], below) and main a9779ef3c193 [exec]; branch_10_6 head 4ae946e5a9b [exec], so the released 10.6.0 has it; main a9779ef3c193 [exec]; upstream main 20ced71c1e6 [read]. Not affected: 7.4.0-7.7.3 (no within) and 7.3.1 (no intervals package) [exec]. All runs on JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-830.html",
   "repro": "repro/LFV-830/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-903",
   "priority": "low",
   "priority_rank": 1092,
   "novelty": "known",
   "withheld": false,
   "area": "core / search similarities (MultiSimilarity: undocumented norm ownership, inherited getDiscountOverlaps)",
   "title": "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)",
   "summary": "You combine two sub-similarities in a MultiSimilarity, for example BM25 with discountOverlaps=true and BM25 with discountOverlaps=false, and use it for indexing and searching; the javadoc says only that it 'will sum the scores of the provided sims' (CombSUM), so you expect both sub-similarities' settings to count. In fact computeNorm returns sims[0].computeNorm(state), so only the first sub-similarity writes the field's single norm and every sub-scorer decodes that norm: the second one's discountOverlaps (or its own computeNorm encoding) is silently ignored, swapping the array order changes the stored norms and therefore the scores (0.7534208 for [discount, noDiscount] vs 0.6862843 for [noDiscount, discount] in an independent repro), and the inherited getDiscountOverlaps() returns true even when sims[0] counts overlap tokens. The single norm is the intended one-norm-per-field design and on any one index the score is an exact sum in either order; what is missing is the documentation (and a correct getter), so the fix is a javadoc sentence, optionally plus passing sims[0].getDiscountOverlaps() to the super constructor.",
   "impact_class": "minor",
   "introduced_commit": "5d10609dbf6fb8a1565523813db49e08b0930b80 (branch flexscoring, svn r1166792, 'LUCENE-2959: clean up nocommits', rmuir), which first wrote MultiSimilarity.java with 'computeNorm(...) { return sims[0].computeNorm(state); }' and the CombSUM javadoc; it reached trunk and every release with the branch merge cfaf91c73981bcce5f240aba5ad1cc29d7b517e4 (svn r1169470, 'LUCENE-2959: add state of the art ranking to Lucene'); issue LUCENE-2959 (apache/lucene#4033), pre-GitHub, no PR [read]. Later commits on the line only changed the signature (98e59fceeec LUCENE-3687; 8ef98119381); it has always delegated to sims[0], and no javadoc ever mentioned the norm. Part 2 (getDiscountOverlaps() always true): 7c056ab88c7589a0d103fd4c372ac7677515691d on main and 1b38d5dec85d on branch_9x, apache/lucene#13757 (cpoerschke, co-author rmuir), which added the final getter and Similarity() -> this(true) while MultiSimilarity's 2011 constructor calls the implicit super() [read]. Not a regression: the behaviour arrived together with the API in both cases.",
   "introduced_date": "2011-09-08 (branch commit 5d10609dbf6); 2011-09-11 on trunk (cfaf91c7398); part 2: 2024-09-13 (#13757)",
   "first_affected_version": "4.0.0-ALPHA [exec] (first GA release 4.0.0 [exec]; no 3.x release has the API: 3.6.2 compile_error [exec]); part 2 (getDiscountOverlaps): 9.12.0 [exec] on 9.x and 10.0.0 [exec] on 10.x (9.11.1 has no getter [exec])",
   "affected_versions": "every release from 4.0.0-ALPHA through 10.5.2, 10.6.0 (branch_10_6 4ae946e5a9b, the RC1 revision) and main a9779ef3c193; not fixed upstream [exec]. Part 2 only from 9.12.0 / 10.0.0. Caveats: 8.8.2-8.11.3 are inferred from 8.0.0 and 8.11.4 (not tagged in the history clone); 4.0.0-ALPHA and 4.0.0-BETA ran on a plain classpath; upstream main c5ab3e57b9b has the same MultiSimilarity.java blob (fetched 2026-10-28)",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/12675",
    "https://github.com/apache/lucene/issues/13757",
    "https://github.com/apache/lucene/issues/14433",
    "https://github.com/apache/lucene/issues/4033",
    "https://issues.apache.org/jira/browse/LUCENE-2959",
    "https://github.com/apache/lucene/issues/16909"
   ],
   "doc": "",
   "repro": "repro/LFV-903/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-812",
   "priority": "low",
   "priority_rank": 1093,
   "novelty": "known",
   "withheld": false,
   "area": "index / IndexWriter delete APIs (deleteAll and deleteDocuments(Query...) javadoc)",
   "title": "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)",
   "summary": "You index a NUMERIC doc values field \"f\", commit, call deleteDocuments(MatchAllDocsQuery.INSTANCE) and then add \"f\" as SORTED. You expect the 'cannot change doc values type' IllegalArgumentException, because the deleteAll() javadoc calls deleteAll() 'much faster than' that call and says a delete query 'only marks documents as deleted' while deleteAll() clears doc values types. Instead the SORTED document is accepted and getFieldNames() is empty: since LUCENE-6379 (5.2.0), deleteDocuments(Query...) returns deleteAll() whenever a query's class is exactly MatchAllDocsQuery, while the same delete wrapped in a ConstantScoreQuery keeps the schema; the routing is deliberate, only the javadoc is wrong.",
   "impact_class": "minor",
   "introduced_commit": "041f9077c2a0 (LUCENE-6379 / #7439, trunk svn r1670410, mikemccand; SVN era, no PR); its branch_5x backport c67a4cbe9a32 (r1670412) is the one first released, in 5.2.0 [read]. The javadoc sentences are older and were true when written: 'much faster than using deleteDocuments( new MatchAllDocsQuery() )' from 64a55ede8b5 (LUCENE-1705 / #2779, 2009) and 'different semantics ... a delete query only marks documents as deleted' from c0e7a50ab8e (LUCENE-5002 / #6066, 2013); later edits kept the claim: bc7deedc092 (#15499, MatchAllDocsQuery.INSTANCE) and 7540c29ee84 (#15598, grammar) [read]",
   "introduced_date": "2015-03-31 (author date of 041f9077c2a0 and c67a4cbe9a32); the javadoc text dates from 2009-06-26 and 2013-05-21; later edits 2025-12-11 and 2026-01-22",
   "first_affected_version": "5.2.0 [exec] (5.1.0 is consistent with the javadoc [exec]; the candidate and the cross-model review/the intended-behaviour check said 5.1.0, corrected by the independent reproduction and the adjudication from the release tags and the CHANGES.txt section)",
   "affected_versions": "every release from 5.2.0 through 10.5.2, and main a9779ef3c193 [exec]. Not affected: 5.1.0 and earlier, where the javadoc was true [exec]. Not fixed upstream: main 20ced71c1e6e has the same text (IndexWriter.java last changed by 169cbffd12f4, author date 2026-09-21), and branch_10x has the same claim in older wording [read]. All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-6379",
    "https://github.com/apache/lucene/issues/9829",
    "https://issues.apache.org/jira/browse/LUCENE-8785",
    "https://github.com/apache/lucene/issues/7439",
    "https://github.com/apache/lucene/issues/16578",
    "https://github.com/apache/lucene/issues/2779"
   ],
   "doc": "",
   "repro": "repro/LFV-812/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-529",
   "priority": "low",
   "priority_rank": 1094,
   "novelty": "new",
   "withheld": false,
   "area": "facet / taxonomy (TaxonomyFacetLabels, per-document facet label retrieval)",
   "title": "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)",
   "summary": "You add FacetField(\"Author\", \"Bob\") and FacetField(\"Publish Date\", \"2010\", \"10\", \"15\") to a document and read its labels back with TaxonomyFacetLabels, whose javadoc offers it as a way to skip stored fields for these values, so you expect [Author/Bob, Publish Date/2010/10/15]; that is what you get when both dimensions are single-valued. With Publish Date configured multi-valued and hierarchical you get [Author/Bob, Publish Date/2010, Publish Date/2010/10, Publish Date/2010/10/15], and with Author configured multi-valued with requireDimCount you get [Author, Author/Bob, Publish Date/2010/10/15]. FacetsConfig deliberately indexes those ancestor (and dimension) ordinals so that multi-valued counts are right, and the reader turns every indexed ordinal back into a label; the javadoc never says so.",
   "impact_class": "minor",
   "introduced_commit": "24aadc220ba9578f581637b9fd0e7e973d46426c (master, apache/lucene-solr#1893, LUCENE-9444 / apache/lucene#10484, by goankur; first released in 9.0.0) and its branch_8x backport d71923065dba0b6fe275cb60bd5cffb017509827 (first released in 8.7.0). It added TaxonomyFacetLabels with the stored-field-replacement javadoc and an unfiltered nextFacetLabel(docId) that returns taxoReader.getPath(ord) for every stored ordinal [read]. The other ingredient, FacetsConfig indexing every parent ordinal for multiValued && (hierarchical || requireDimCount) dims, is intended and dates from LUCENE-5339 (59c08c3fa13b, 2013-11-23, first released in 4.7.0). Later commits on the file (7f8b7ffbcad2 LUCENE-9570 reformat, the LUCENE-9856 cleanups, 6ee69e06fbd1 LUCENE-10062 / #264 in 9.0.0, 2a0b7f20567 #12995) keep the behaviour. Not a regression",
   "introduced_date": "2020-09-28 (PR #1893 merged 14:55:38Z on master; the branch_8x backport the same day)",
   "first_affected_version": "8.7.0 [exec] (the first release with TaxonomyFacetLabels; 8.6.3 has no such class [exec])",
   "affected_versions": "Every release that has the class: 8.7.0 to 8.11.4, 9.0.0 to 9.12.3, 10.0.0 to 10.6.0, and main (ea57360912ed, 645d4fe14a20); not fixed upstream. [exec] the minimal test fails on the 10.6.0 release jars (-ea and -da) and on main 645d4fe14a20 (2026-11-01); the finder's JUnit fails 2 of 3 (the single-valued control passes) with identical values on 8.7.0, 8.11.4, 9.0.0, 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea; main also -da) (follow-up); the independent reproduction's JUnit fails 4 of 7 on main (-ea, -da), 10.5.2 and 9.12.3; the intended-behaviour check ran 8.7.0 (fail) and 8.6.3 (compile error). [read] the other releases from git tag --contains 24aadc220ba9 and no later behaviour change; 8.8.2 to 8.11.3 (untagged in the history clone) inferred from 8.7.0 and 8.11.4 behaving identically. TaxonomyFacetLabels.java is unchanged on main, branch_10x and branch_10_5 since #12995 (2024-01-22). All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-529.html",
   "repro": "repro/LFV-529/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-536",
   "priority": "low",
   "priority_rank": 1095,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / ConcatenateGraphFilter and ConcatenateGraphFilterFactory (maxGraphExpansions javadoc); also suggest / CompletionAnalyzer",
   "title": "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)",
   "summary": "You set maxGraphExpansions on ConcatenateGraphFilter (or its factory), or use CompletionAnalyzer's 1- or 3-argument constructor, and expect what the javadoc says: a TooComplexToDeterminizeException when the token graph has more than that many paths, and, for CompletionAnalyzer, no limit at all. Instead the filter silently emits only the first maxGraphExpansions paths (a 4-path synonym graph at limit 3 gives 3 tokens and no error; CompletionAnalyzer keeps 10000 of 16384 paths), and because the same number is also passed to determinize as its work limit, a 2-path graph at limit 3 throws. Silent truncation is the suggester's deliberate design (LUCENE-4971), so the fix is to correct the javadoc, not the code.",
   "impact_class": "minor",
   "introduced_commit": "f9f5e837450e082ae7e1a82a0693760af7485a1b (LUCENE-8332 'New ConcatenateGraphFilter (from CompletionTokenStream)', now apache/lucene#9379; committed directly from a JIRA patch by dsmiley; PR apache/lucene-solr#384 carried the same javadoc and was closed unmerged on 2018-06-11; the branch_7x copy 9b61121ffb65 is the commit in 7.4.0) [read]. It moved CompletionTokenStream's code, which already kept the first N paths (LimitedFiniteStringsIterator) and passed N to determinize, into a new public class and wrote the throw-above-N javadoc for it; not a code regression. Part B (CompletionAnalyzer 'no limit on graph expansions'): be4d58c7740 (LUCENE-6459, now apache/lucene#7518; branch_5x copy 380bb29f3959, in 5.3.0) changed DEFAULT_MAX_GRAPH_EXPANSIONS from -1 to 10000 without touching the javadoc that LUCENE-6339 (b7adb6ac7704, 5.1.0) had written [read]",
   "introduced_date": "2018-06-04 (part A, ConcatenateGraphFilter and factory javadoc); 2015-05-28 (part B, CompletionAnalyzer default)",
   "first_affected_version": "7.4.0 [exec] for part A (7.3.1 [exec] has no ConcatenateGraphFilter or factory: the probe does not compile); 5.3.0 [exec] for part B (5.1.0 and 5.2.1 [exec] keep all 16384 paths as documented; caveat: there the default -1 was also the determinize state limit, so CompletionAnalyzer(Analyzer) threw on a 2-path shared-prefix graph [exec], i.e. 'no limit' was never fully accurate)",
   "affected_versions": "Part A: every release from 7.4.0 through 10.6.0, and main (ea57360912ed, 645d4fe14a20) [exec]; part B: every release from 5.3.0 through 10.6.0, and main [10.6.0 read 2026-11-02: the release commit 4ae946e5a9b keeps the 'no limit on graph expansions' javadoc and its release jar's 1- and 3-argument CompletionAnalyzer constructors pass 10000]; never fixed (upstream main has no newer commit to the three files, checked through the GitHub API 2026-10-26). [exec] the follow-up's version-portable main() probes: part A fails on 7.4.0, 8.9.0, 8.10.0, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main (-ea and -da), compile error on 7.3.1; part B fails on 5.3.0, 7.3.1, 7.4.0, 8.11.4, 9.12.3, 10.5.2 and main (-ea and -da), passes on 5.1.0 and 5.2.1, compile error on 5.0.0; controls pass wherever the probe compiles; the finder's JUnit fails 3 of 3 on main (-ea and -da), 10.5.2 and 9.12.3; the independent reproduction's JUnit fails 5 of 8 (3 controls pass) on main (-ea and -da), 10.5.2 and 9.12.3; a separate probe shows both mismatches on 7.4.0, 8.9.0, 9.0.0 and main. [read] the javadoc text is present at tags 7.4.0, 8.8.1, 9.0.0, 9.12.3 and 10.5.2 and on main. Behaviour note: LUCENE-9981 (c4cf7aa3e19, CHANGES under 8.10.0) turned the determinize limit from a state count into an effort budget (10 x the value), which moves where the below-the-limit throw starts (a 2-path graph at limit 30 throws on 7.4.0 and 8.9.0 and gives 2 tokens from 8.10.0 [exec]); at limit 3 it throws on every version. 8.9.0-8.11.4 were executed from the official jars but their javadoc was not read from source (tags absent from the history clone)",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-536.html",
   "repro": "repro/LFV-536/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-961",
   "priority": "low",
   "priority_rank": 1096,
   "novelty": "new",
   "withheld": false,
   "area": "grouping / package documentation (package-info.java inputs list vs the collector managers it names)",
   "title": "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)",
   "summary": "You read the grouping package overview, which says topNGroups is 'how many top groups to keep' and that groupOffset 3 'means you'll get 7 groups back (assuming topNGroups is 10)', and which names FirstPassGroupingCollectorManager as the first pass and builds BlockGroupingCollectorManager(groupSort, groupOffset, topNGroups, ...), so you expect groupOffset 3 with topNGroups 10 to return 7 groups. Instead both managers, like GroupingSearch, treat topNGroups as the number of groups to return after the offset and return 10 groups (ranks 4 to 13). The '7 groups' sentence is right only for the plain FirstPassGroupingCollector and BlockGroupingCollector, which the page named until #16385 rewrote it for the managers, so paging code written from the sentence gets oversized, overlapping pages.",
   "impact_class": "minor",
   "introduced_commit": "a6e670d6ed1b4342accf75aed0d63ea11fde6645 (#16385 'Remove unused public methods in AllGroupHeadsCollector', by gaobinlong, reviewed and approved by javanna, who asked for the package-info update; milestone 10.6.0; backport d729cbfd11f in branch_10x and branch_10_6) [read]. Older ingredients [read]: the inputs-list sentence and a two-pass example that already passed groupOffset+topNGroups come from LUCENE-1421 (9083cedb922 on trunk, ee2154e4a39 on branch_3x, by mikemccand, 2011-05-14; first released in 3.2); the BlockGroupingCollector example with groupOffset+topNGroups from LUCENE-3129 (375c1abdbf4, 2011-06-02; 3.3); the managers' page-size semantics from #15574 (636e8e9f587, 2026-06-03) and #15936 (d27d080d101, 2026-06-15, where the author chose groupOffset+topNGroups in review to match GroupingSearch), both first released in 10.5.0.",
   "introduced_date": "2026-08-12 (author date of a6e670d6ed1, 21:16:52 +0800 = 13:16:52Z, merged the same minute; backport d729cbfd11f committed 2026-08-12 15:27:39 +0200); older ingredients 2011-05-14 (LUCENE-1421) and 2011-06-02 (LUCENE-3129)",
   "first_affected_version": "10.6.0, released 2026-10-29 (branch_10_6 head 4ae946e5a9b, tag releases/lucene/10.6.0) for the direct contradiction with the classes the page names [exec]. Not in this form in 10.5.0-10.5.2, whose page names the collectors, although the managers already return 10 there [exec]. The weaker form, the inputs list disagreeing with the page's own example code (which passed groupOffset+topNGroups and so returns 10 groups for topNGroups 10), is in every release since 3.2 [exec].",
   "affected_versions": "Direct contradiction (the page names the managers): main a9779ef3c193 [exec], the branch_10_6 head 4ae946e5a9b (10.6.0, released 2026-10-29) [exec], branch_10x (10.7.0-SNAPSHOT, contains d729cbfd11f) [read]; upstream main 645d4fe14a20 (2026-10-28) still has the sentence [read]. Long-standing mismatch between the inputs list and the page's own example code: 3.2 to 10.5.2 and still on 10.6/main [exec]. The managers' behaviour, unchanged since they shipped: 10.5.0, 10.5.1 and 10.5.2 return 10 for (3, 10) [exec]; 9.12.3 and 10.4.0 have no managers (the JUnit does not compile) [exec]. All runs JDK 25.0.3 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-961.html",
   "repro": "repro/LFV-961/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-885",
   "priority": "low",
   "priority_rank": 1097,
   "novelty": "new",
   "withheld": false,
   "area": "core / index merge scheduling (MultiIndexMergeScheduler visibility)",
   "title": "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",
   "summary": "You read the Lucene 10.3.0 release notes ('MultiIndexMergeScheduler: a production multi-tenant merge scheduler') and the class javadoc ('can be used easily by creating a MultiIndexMergeScheduler instance for each index'), and write iwc.setMergeScheduler(new MultiIndexMergeScheduler(dir)) in your application, using the public constructor the javadoc calls 'The main MultiIndexMergeScheduler constructor -- use this one'. You expect it to compile, as the same line with ConcurrentMergeScheduler does. Instead javac rejects it because the class itself is declared 'class MultiIndexMergeScheduler' without 'public' (MultiIndexMergeScheduler.java:36), and it has been package-private in every release that contains it, so only code inside org.apache.lucene.index (in practice Lucene's own test) can use it.",
   "impact_class": "minor",
   "introduced_commit": "cfb407bb0080 (main, 'MultiIndexMergeScheduler: a production multi-tenant merge scheduler (#15015)', PR by corecursion, merged by vigyasharma; branch_10x backport 79a9ddafcb79): the class was born package-private, already in the PR's first commit ad8cf7b6aa (2025-07-30) and in all 17 PR commits, so there is no regression window; PR commit 7a6ee719bb narrowed only the test-only constructor to package-private [read]",
   "introduced_date": "2025-08-08 (author date of cfb407bb0080 and of the backport 79a9ddafcb79; PR merged 2025-08-08T20:53:02Z; first PR commit 2025-07-30)",
   "first_affected_version": "10.3.0 [exec] (the introducing release, tag dated 2025-09-13; 10.2.2 and older, including every 9.x, have no such class [exec])",
   "affected_versions": "10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1 and 10.5.2, the branch_10_6 head 4ae946e5a9b9 (10.6.0, released 2026-10-29) and main a9779ef3c193 and 645d4fe14a2. [exec] the finder's JUnit fails 2 of 2 on all of them (-ea; also -da on 10.3.0, 10.5.2 and main); the independent reproduction's application-side JUnit (package example.app, javac of application source plus reflection, ConcurrentMergeScheduler control) fails 2 of 3 on 10.3.0 and 10.5.2 (-ea) and on main (-ea and -da), with the control passing; the intended-behaviour check's javac probe fails on main and 10.3.0 on the class path and from a named application module; javap on every affected lucene-core jar shows 'class org.apache.lucene.index.MultiIndexMergeScheduler' (no public) with a public (Directory) constructor; all 7 10.x releases carry the identical file (blob 84b88aafbc97). Not affected: 9.x and 10.0.0 to 10.2.2 (class absent). [read] Not fixed upstream: origin/main 645d4fe14a2, branch_10x 657014b3c57 and branch_10_6 4ae946e5a9b still declare 'class MultiIndexMergeScheduler' at line 36 (re-checked 2026-10-29; the finder's JUnit fails 2 of 2 on the RC1 4ae946e5a9b jars with -ea and -da [exec]); the file's only later commit is ba7f659b1d81 (#15105, author date 2025-08-21, unused-variable cleanup).",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-885.html",
   "repro": "repro/LFV-885/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-989",
   "priority": "low",
   "priority_rank": 1098,
   "novelty": "new",
   "withheld": false,
   "area": "core / analysis (org.apache.lucene.analysis package overview, package-info.java: the TokenStream API tutorial)",
   "title": "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)",
   "summary": "You open the org.apache.lucene.analysis package overview, Lucene's tutorial for writing analyzers, token filters and attributes, and copy one of its examples, expecting it to compile as shown (the page even prints the output the code should produce). Seven examples do not compile on main or on any release since 6.0.0: they call StandardAnalyzer(Version), WhitespaceTokenizer(Version) and FilteringTokenFilter(Version, TokenStream), all removed in 5.0, and new LengthFilter(true, source, 3, Integer.MAX_VALUE), a signature gone since 4.4; one subclasses StandardAnalyzer, which is final; and the custom PartOfSpeechAttributeImpl lacks reflectWith(AttributeReflector), which has been abstract since 6.0. The APIs changed on purpose and the page was never updated: written against the current API (no Version argument, LengthFilter(source, 3, Integer.MAX_VALUE), a custom Analyzer or AnalyzerWrapper instead of a StandardAnalyzer subclass, and a reflectWith method) every example compiles.",
   "impact_class": "minor",
   "introduced_commit": "No single commit: the seven examples went stale at five API changes, and only one of them (LUCENE-4963) edited this page, leaving its stale calls in place [read]. Oldest: 1ae5f89cfb3 (LUCENE-1987 = #3062, uschindler, 2009-10-21, first in 3.0.0) removed StandardAnalyzer(), which the position-gap example then subclassed, and d02cbfe3c16 (LUCENE-2372 = #3448, uschindler, 2010-04-10; branch_3x merge 379c5fd00d4, 2010-05-04; 3.1) made StandardAnalyzer final, so the 2012 Version form of that example (e825015535e, sarowe, 3.6.0) never compiled in any release that shipped it. 8a7f2b6cc45 (LUCENE-4963 = #6027, jpountz, 2013-05-04; branch_4x ddf2a47e3ef; 4.4.0) replaced LengthFilter(boolean, TokenStream, int, int) with Version-first constructors and rewrote this page's LengthFilter and FilteringTokenFilter listings, but left both LengthFilter(true, ...) calls. Primary: 9938a39a872 (LUCENE-5859 = #6921, rjernst, 2014-08-08; branch_5x backport 55594bad9b0, LUCENE-5944, rmuir, 2014-09-18; 5.0.0) removed StandardAnalyzer(Version), WhitespaceTokenizer(Version) and FilteringTokenFilter(Version, TokenStream) without touching the page, breaking five of the seven groups. 4accc254774 (LUCENE-6651 = #7709, uschindler, 2015-07-02; 6.0.0) made AttributeImpl.reflectWith abstract, breaking the custom-attribute example (its MIGRATE entry tells custom attributes to implement it).",
   "introduced_date": "2009-10-21 (1ae5f89cfb3, the oldest break: the position-gap example); 2010-04-10 (d02cbfe3c16, StandardAnalyzer final); 2013-05-04 (8a7f2b6cc45, the LengthFilter calls); 2014-08-08 (9938a39a872, primary: the Version constructors, five groups); 2015-07-02 (4accc254774, the custom attribute); author dates",
   "first_affected_version": "3.0.0 [exec] for the position-gap example (its text of the time compiles on 2.9.4 and fails on 3.0.0); 4.4.0 [exec] for the two LengthFilter(true, ...) calls; 5.0.0 [exec] for the Version constructors (five groups); 6.0.0 [exec] for the custom attribute, so every release from 6.0.0 on has all seven examples broken",
   "affected_versions": "every release from 3.0.0 to 10.5.2, 10.6.0 (released 2026-10-29; branch_10_6 4ae946e5a9b) and main a9779ef3c193; not fixed upstream. 3.0.0-4.3.1: the position-gap example only; 4.4.0-4.10.4: the gap example and both LengthFilter calls; 5.0.0-5.5.x: six of the seven (all but the custom attribute); 6.0.0 to 10.5.2, 10.6.0 and main: all seven. Not affected: 2.2.0-2.9.x (the gap example compiles on 2.9.4; the other six did not exist in their current form). [exec] [read]. Caveat: all runs used JDK 25 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-989.html",
   "repro": "repro/LFV-989/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1018",
   "priority": "low",
   "priority_rank": 1099,
   "novelty": "new",
   "withheld": false,
   "area": "core / search (LeafCollector class javadoc example)",
   "title": "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)",
   "summary": "The LeafCollector class javadoc explains that collect() receives segment-relative doc IDs and shows 'a simple example showing how to collect docIDs into a BitSet' with an anonymous Collector and LeafCollector. Copied into code on any current release it does not compile: the anonymous Collector does not implement the abstract scoreMode() (needsScores() from 5.1.0 to 7.x), and the anonymous LeafCollector does not implement setScorer(Scorable), because the example's setScorer(Scorer) has only been an overload since 8.0.0. With scoreMode() returning ScoreMode.COMPLETE_NO_SCORES and a Scorable parameter the example compiles and collects exactly the expected global doc IDs, so only the javadoc is wrong.",
   "impact_class": "minor",
   "introduced_commit": "010e352f603 (trunk, svn r1657554; LUCENE-6218 'don't decode freqs or enumerate all positions when scoring is not needed', migrated as #7280, by Robert Muir (rmuir), author date = commit date 2015-02-05; branch_5x backport 8c0dbb90087, svn r1657571, same day, is the one released in 5.1.0): it added the abstract Collector.needsScores() and did not touch LeafCollector.java, so the example's anonymous Collector stopped compiling. Two later API changes kept it broken, neither touching the example: 4fc5a872ded (LUCENE-4100, #5172, Adrien Grand, author date 2017-12-07, 8.0.0) replaced needsScores() by the abstract scoreMode(), and 910a0231f6f (LUCENE-6228, #7290, Alan Woodward, author date 2018-09-03, 8.0.0) changed LeafCollector.setScorer(Scorer) to setScorer(Scorable), editing the declaration further down the same file and leaving the example's setScorer(Scorer) as a mere overload (the second javac error). The example itself was written by 85642f59ddf (LUCENE-5527, #6590, Adrien Grand, 2014-04-04) and was valid in 5.0.0; its code lines are unchanged since 927827a215a (LUCENE-6179, 2015-01-15) [read]",
   "introduced_date": "2015-02-05 (010e352f603 and its branch_5x backport 8c0dbb90087, author date = commit date, svn import); the second error since 2018-09-03 (910a0231f6f, LUCENE-6228, author date)",
   "first_affected_version": "5.1.0 [exec] (the verbatim example compiles on 5.0.0 [exec] and fails on 5.1.0 with the needsScores() error); the current pair of errors (scoreMode() and setScorer(Scorable)) since 8.0.0 [exec]",
   "affected_versions": "every release from 5.1.0 to 10.6.0 (RC1 4ae946e5a9b), branch_10x 657014b3c579 and main 645d4fe14a20; not fixed upstream (upstream main HEAD still 645d4fe14a20 at 2026-10-29; the last commit touching LeafCollector.java, 14a3b87e75e0 (#16144, 2026-05-31), does not change the example). [exec] [read]. Before 5.0.0 LeafCollector does not exist (n/a; 4.x had a different example in the Collector javadoc). Caveat: all runs used JDK 25 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1018.html",
   "repro": "repro/LFV-1018/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-980",
   "priority": "low",
   "priority_rank": 1100,
   "novelty": "known",
   "withheld": false,
   "area": "core / search (TermInSetQuery class javadoc example)",
   "title": "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)",
   "summary": "You read the TermInSetQuery javadoc, which says that in its example q1 and q2 'would yield the same scores', and copy the example into your code. It does not compile on any release: q1 calls new TermInSetQuery(\"field\", new BytesRef(\"foo\"), new BytesRef(\"bar\")), a varargs constructor removed in 10.0, and q2 is built with new BooleanQuery() and bq.add(...), which have not existed since BooleanQuery became immutable, with a Builder, in 6.0. Written with the current API (a List of terms and BooleanQuery.Builder) the example compiles and the two queries do return the same hits and scores, so only the code in the javadoc is wrong.",
   "impact_class": "minor",
   "introduced_commit": "22940f5c492 (LUCENE-7624 'Move TermsQuery into core as TermInSetQuery', #8675, author date 2017-01-09, by romseygeek; branch_6x 8511f9e6991): it created the class with a word-for-word copy of the TermsQuery javadoc example (text from 9b060c407e0, LUCENE-6415, 2015-04-13), whose BooleanQuery lines had been stale since 4aafacfbef4 (LUCENE-6570 'Make BooleanQuery immutable', #7628, 2015-06-18, by jpountz, first released in 6.0.0; it moved TermsQuery's own code to BooleanQuery.Builder but not its javadoc), so the example never compiled in any TermInSetQuery release. The current q1 line was broken by b22a9b8998a (#12837 '[10.0] Removing TermInSetQuery varargs ctor', authored and merged 2023-12-05, by slow-J; deprecated in 9.10 by #12864, 5852a0fb8ca), which removed TermInSetQuery(String, BytesRef...) and (RewriteMethod, String, BytesRef...) without touching the javadoc. Earlier, q1 had been broken by 43874fc5b5c (LUCENE-7637, #8688, 2017-01-17) and fixed by d1163450b6a (LUCENE-9046, #10088, 2019-11-16, by danmuzi; released in 8.4.0), which left the BooleanQuery lines as they were [read]",
   "introduced_date": "2017-01-09 (22940f5c492, author date: the class with its born-stale BooleanQuery lines); 2023-12-05 (b22a9b8998a, #12837, author and merge date: the current q1 line); 2015-06-18 (4aafacfbef4, LUCENE-6570: made the BooleanQuery lines stale in the predecessor TermsQuery)",
   "first_affected_version": "6.5.0 [exec] (the first release with TermInSetQuery; the example has not compiled in any release); the current q1 failure first in 10.0.0 [exec]",
   "affected_versions": "every TermInSetQuery release from 6.5.0 to 10.5.2, 10.6.0 (the branch_10_6 head 4ae946e5a9b, by reading) and main a9779ef3c193; not fixed upstream. 6.5.0-8.3.1: 4 broken lines (the q1 Term,Term form plus the 3 BooleanQuery lines); 8.4.0-9.12.3: 3 broken lines (BooleanQuery only; the deprecated varargs constructor still exists in 9.x); 10.0.0-10.5.2, 10.6.0 (by reading) and main: 4 broken lines. [exec] [read]. Caveat: all runs used JDK 25 on Linux aarch64.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/10088",
    "https://github.com/apache/lucene/issues/12837",
    "https://github.com/apache/lucene/issues/12864",
    "https://github.com/apache/lucene/issues/12243",
    "https://github.com/apache/lucene/issues/7628",
    "https://github.com/apache/lucene/issues/8675"
   ],
   "doc": "",
   "repro": "repro/LFV-980/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-992",
   "priority": "low",
   "priority_rank": 1101,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-icu / module overview documentation (overview.html 'Example Usages')",
   "title": "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)",
   "summary": "You read the analysis-icu module overview, which offers 'Example Usages' for ICU tokenization, collation and transliteration, and copy one into your code. The tokenizer example and the Farsi range, Danish sort and Turkish case collation examples do not compile on any current release, because they call APIs Lucene removed between 4.0 and 10.0 (new ICUTokenizer(reader), Field.Index.ANALYZED, new IndexSearcher(dir, true), QueryParser.setAnalyzeRangeTerms, the Filter-taking search methods, Sort.setSort, IndexSearcher.doc(int)), and on main the Serbian transliteration example has a bare, uncommented sentence in its code. Rewritten with the current API (and, for the Danish sort, doc values) the examples compile and do what the page says, so only the page is wrong.",
   "impact_class": "minor",
   "introduced_commit": "f9ed2c19cd7 (trunk, LUCENE-3219 'Moved SortField types to Enum', #4292, author date = commit date 2011-06-22): the first API removal that broke a page line that still fails on main (line 158, the int SortField.STRING); then 598920d7bde (trunk, LUCENE-3571 'nuke IndexSearcher(Directory)', #4645, 2011-11-16, rmuir) broke all three collation examples (lines 124, 156, 179, new IndexSearcher(dir, true)). Neither commit touched this page (LUCENE-3571 updated the core overview.html's call, not this module's page), and both reached a release only in 4.0.0-ALPHA. Later removals broke more lines, each without touching the page: ab0e85fafed (LUCENE-5388, 2014-01-09; ICUTokenizer(Reader), gone in 5.0.0), bc3a3dc5d47 (LUCENE-4095, 2012-05-31; Field.Index, gone in 6.0.0), 2cd3fb807da (LUCENE-6286, 2015-02-24; the Filter search overloads, deprecated in 5.1, gone in 6.0.0), e92a38af90d (LUCENE-7355, author date 2016-06-28; setAnalyzeRangeTerms, gone in 7.0.0), 9e9c3bd249e (LUCENE-9325, #338, 2021-10-06, romseygeek; Sort.setSort, gone in 9.0.0), 9eeab8c4a69 (#11998, 2022-12-13, rmuir; IndexSearcher.doc(int), gone in 10.0.0). Main-only Serbian row: 95d019bd881 (#14832 'style: fix indents inconsistent with editorconfig', rmuir, 2025-06-22) turned the block's valid /** ... */ comment into '//' followed by a bare sentence [read]",
   "introduced_date": "2011-06-22 (f9ed2c19cd7, LUCENE-3219, author date = commit date) and 2011-11-16 (598920d7bde, LUCENE-3571, author date = commit date); 2025-06-22 (95d019bd881, #14832, author and merge date: the main-only Serbian row)",
   "first_affected_version": "4.0.0-ALPHA [exec] (tag 2012-06-29, the first release with both 2011 commits; its shipped page fails against its own jars in the Farsi, Danish and Turkish examples); first GA 4.0.0 [exec], the same; the Serbian row is unreleased (main only)",
   "affected_versions": "every release from 4.0.0-ALPHA to 10.5.2, 10.6.0 [exec] and main a9779ef3c193; not fixed upstream (upstream main 645d4fe14a20 and branch_10_6 still carry every stale call, read 2026-10-29). The set of failing calls grew release by release [exec]: 4.0.0-ALPHA, 4.0.0 and 4.10.4: 3 blocks (IndexSearcher(Directory, boolean), the int SortField.STRING); 5.0.0 and 5.5.5: 4 blocks (+ ICUTokenizer(Reader)); 6.0.0 and 6.6.6: + Field.Index and the Filter search overloads; 7.0.0 and 8.11.4: + setAnalyzeRangeTerms; 9.0.0 and 9.12.3: + Sort.setSort (13 error lines); 10.0.0 and 10.5.2: + IndexSearcher.doc(int) (14 error lines, 4 blocks); main: + the Serbian syntax error (16 error lines, 5 blocks). Main's page against the 4.10.4 to 10.5.2 jars agrees row by row. The branch_10x head 657014b3c57 and the branch_10_6 head 4ae946e5a9b have a page byte-identical to 10.5.2's [read]. Before 4.0: 3.1.0, 3.2.0 and 3.6.2 [exec] show none of these rows, but their page failed 2 of 10 blocks for another reason (QueryParser constructors without the Version argument that 3.0 made mandatory), so no release ever shipped all three collation examples in a form that compiles against it [exec]; they compiled only on trunk from 2011-02-28 to 2011-06-22 [read]. The finder's JUnit (main's text) fails 5 of 10 on main (-ea and -da), 10.5.2, 10.0.0 and 9.12.3. Caveat: all runs used JDK 25 on Linux aarch64; the check only compiles, so the JDK cannot change the outcome.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-992.html",
   "repro": "repro/LFV-992/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1041",
   "priority": "low",
   "priority_rank": 1102,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common / compound (package overview examples and output table, package-info.java)",
   "title": "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)",
   "summary": "The compound package overview shows how to split German and Swedish compound words with HyphenationCompoundWordTokenFilter and DictionaryCompoundWordTokenFilter, in three examples and a table of the tokens the filter produces. Copied into code, none of the three examples compiles on any release since 4.0.0, because getHyphenationTree(Reader), WhitespaceTokenizer(Reader) and the String[] dictionary constructors no longer exist (today: getHyphenationTree(String or InputSource), new WhitespaceTokenizer() plus setReader, and a CharArraySet dictionary), and once ported the loop throws IllegalStateException because it never calls reset(). With those fixes the examples run, but every word part carries the offsets of the whole word, for example (Rind,0,29) where the table shows (Rind,0,4), a deliberate 4.4.0 change (LUCENE-5018) the table never picked up; only the page is wrong.",
   "impact_class": "minor",
   "introduced_commit": "No single commit; a page that was never updated across several deliberate API changes [read]. Today's example text was written by 2c02caead74 (branch_3x; trunk twin fe5f1aabcb1), LUCENE-1287 'Allow usage of HyphenationCompoundWordTokenFilter without a dictionary' (migrated as #2364), committed by Robert Muir (rmuir) from Thomas Peuss's patch, 2010-05-19, first release 3.1.0: it rewrote the loop to CharTermAttribute/incrementToken() and added example 2, which calls a (TokenStream, HyphenationTree) constructor that the same commit added only with a leading Version argument, so example 2 failed from the start. The break of examples 1 and 3, behind the headline 'none compiles since 4.0.0', is a58c26978f5 (LUCENE-2781 'drop deprecations from trunk', #3855, rmuir, 2010-11-30, first release 4.0.0): it removed getHyphenationTree(Reader) (deprecated by LUCENE-2732, 843b57c4367, Uwe Schindler, 2010-10-31, for charset problems), the Version-less String[] constructors of both filters and the Version-less WhitespaceTokenizer(Reader) without updating the page. Compounded by a91efbedd1b (LUCENE-3530, #4604, Uwe Schindler, 2011-10-25, 4.0.0: the remaining String[] constructors removed, dictionaries are CharArraySet), ab0e85fafed / 55594bad9b0 (LUCENE-5388, rmuir, 2014-01-09 on trunk, branch_5x 2014-09-18, 5.0.0: Reader removed from Tokenizer constructors; LUCENE-5859, cb9beac7079, had briefly restored a Version-less WhitespaceTokenizer(Reader) in 4.10.x) and cdb6ea3c022 (LUCENE-5235, rmuir, 2013-09-22, 4.6.0: a missing reset() throws IllegalStateException). The output table (written with the page by 7a27cdcbc90, LUCENE-1166, 2008) went stale with 2e92d089832 (branch_4x; trunk 3e893624367), LUCENE-5018 'Don't update offsets in CompoundWordTokenFilterBase' (#6082, Adrien Grand (jpountz), 2013-05-28, first release 4.4.0), which changed only CHANGES.txt, CompoundWordTokenFilterBase and its test. Later commits to the page (647b5091697, 2012, 'code snippet improvements: fix out of date api usage'; 8f3a71443bd, LUCENE-6224, 2015; 378ca8d1bbf, #15573, 2026) changed only markup or format",
   "introduced_date": "2010-05-19 (2c02caead74 / fe5f1aabcb1, LUCENE-1287: today's example text, example 2 broken from the start); 2010-11-30 (a58c26978f5, LUCENE-2781: examples 1 and 3 break); 2013-05-28 (2e92d089832 / 3e893624367, LUCENE-5018: output table stale)",
   "first_affected_version": "3.1.0 [exec] (the first release with today's text; only example 2 fails there); 4.0.0 [exec] is the first release where all three examples fail; the output table is stale from 4.4.0 [exec]",
   "affected_versions": "3.1.0-3.6.2 (example 2 only; examples 1 and 3 compile with deprecation warnings), every release from 4.0.0 to 10.6.0 (all three examples; the output table from 4.4.0; 10.6.0 = the RC1 revision 4ae946e5a9b) and main 645d4fe14a20. [exec] [static: the finder's bytecode presence scan of every called signature over the cached release jar sets 2.4.0-10.5.2 plus main and the RC: at least one called signature is absent in every jar set from 3.1.0 on]. Not affected: no release has today's text before 3.1.0 (the 2008 text compiled on 2.4.0 and 2.9.4 and broke on 3.0.0 when TokenStream.next() was removed, so no release since 3.0.0 has had a compiling example block on this page). Not fixed upstream: the page is unchanged on main (upstream head 2a32d42e5e85, 2026-10-29) and branch_11x (last change 378ca8d1bbf, #15573, markup only) and on branch_10_6 (last change 8ef6a0da5687, LUCENE-9570, reformatting); branch_10x was decommissioned upstream on 2026-10-29 (#16911) (GitHub commits API, 2026-10-29). Caveat: all runs used JDK 25 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1041.html",
   "repro": "repro/LFV-1041/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1027",
   "priority": "low",
   "priority_rank": 1103,
   "novelty": "new",
   "withheld": false,
   "area": "core / util/fst (package overview examples, package-info.java)",
   "title": "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)",
   "summary": "The org.apache.lucene.util.fst package overview shows five usage examples (build an FST, look up by key, look up by value, iterate in sorted order, N-shortest paths) and the values they print. Copied into code on any release since 9.0.0 they do not compile: Util.getByOutput was removed in 9.0.0 (LUCENE-8638, which deleted the page's link to it but kept the code block), the public FSTCompiler(INPUT_TYPE, Outputs) constructor was removed in 9.9.0 (#12715; FSTCompiler.Builder is the API), and Util.Result became a record in 10.0.0 (#13328), so '.input' and '.output' are private and need input() and output(). With those three edits, dropping the lookup-by-value block because it has no replacement, the examples compile on main and print exactly the documented values, so only the javadoc is wrong.",
   "impact_class": "minor",
   "introduced_commit": "666c7a25907 (#249 'LUCENE-8638: remove deprecated FST get by output', by Michael Sokolov (msokolov), approved by dweiss, author date 2021-08-18; umbrella issue LUCENE-8638, migrated as #9684): it removed both Util.getByOutput overloads (deprecated since 8.2.0 by LUCENE-8895) and deleted the page's '{@link Util#getByOutput Lookup-by-output}' bullet, but left the 'Retrieval by value' code block. That was the first break of the example text written by 59a8e83520e (LUCENE-9089 follow-up 'update FST usage example', Tomoko Uchida, 2020-04-29), which compiled against main until then [exec]. Compounded by 63759a463de ('#12715: remove deprecated FSTCompiler constructor since this is an experimental/internal API', Mike McCandless, 2023-11-14; branch_9x 6cd78318eab; the deprecation df07febfe86 / a4399c3021b is #12715 by Juan Manuel Caicedo Carvajal (cavorite), the same day; first release 9.9.0) and by 942065cc3e7 (#13328 'Convert more classes to record classes', Shubham Chaudhary (shubhamvishu), author date 2024-09-11; first release 10.0.0). None of these changes edited the code blocks; #12831 (63d4ba938fe, Dzung Bui, 2024-02) later edited line 52 of the same block and left line 45 [read]",
   "introduced_date": "2021-08-18 (666c7a25907, author date; #249 merged 2021-08-18T12:15Z); compounding changes 2023-11-14 (63759a463de, #12715) and 2024-09-11 (942065cc3e7, #13328, author date)",
   "first_affected_version": "9.0.0 [exec] (the first release after 666c7a25907: 1 error, getByOutput); 9.9.0 [exec] adds the constructor error and 10.0.0 [exec] the four Util.Result errors",
   "affected_versions": "9.0.0-9.8.0 (1 error: getByOutput), 9.9.0-9.12.3 (2 errors: + the FSTCompiler constructor), 10.0.0-10.5.2 (6 errors: + the four Util.Result field reads), 10.6.0 (the RC1 revision 4ae946e5a9b), branch_10x 657014b3c579 and main 645d4fe14a20 (6 errors). [exec] [static: the unit's javac scan of the page as shipped against every release jar 9.0.0-10.5.2 and a javap scan of the three APIs]. Outside this bug: no release before 9.0.0 has this text (FSTCompiler did not exist); 4.x-8.x ship an older Builder-based text that does not compile either, from an earlier and different drift (executed on 4.10.4, 5.1.0, 7.7.3 and 8.11.4: 4 errors each), so no release ever shipped a compiling version of the current text (it compiled only on main between 2020-04-29 and 2021-08-18). Not fixed upstream: the page is unchanged on main 645d4fe14a20 and branch_11x (last change #15573, markup only) and on branch_10x and branch_10_6 (last change #12831) (GitHub commits API, 2026-10-29). Caveat: all runs used JDK 25 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1027.html",
   "repro": "repro/LFV-1027/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1085",
   "priority": "low",
   "priority_rank": 1104,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-common / collation package documentation (package-info.java 'Example Usages')",
   "title": "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)",
   "summary": "You read the analysis-common collation package overview and copy its Danish Sorting example, which indexes five words with CollationKeyAnalyzer and CollationDocValuesField and sorts the hits in Danish order. You expect it to compile, like the page's Farsi and Turkish examples that #16904 just brought up to date on main; instead javac stops at 'sort.setSort(new SortField(\"contents\", SortField.Type.STRING))' with 'cannot find symbol: method setSort(SortField)', because Sort became immutable and lost setSort in 9.0.0 (LUCENE-9325). Written as 'new Sort(new SortField(\"contents\", SortField.Type.STRING))', the example compiles, runs and returns the documented Danish order A,E,B,D,C.",
   "impact_class": "minor",
   "introduced_commit": "9e9c3bd249e (apache/lucene#338, LUCENE-9325 'Make Sort final', by romseygeek, merged 2021-10-06) [read]. The page's call dates from the original example (LUCENE-1435, 6bf0e6e09bd, 2009; moved into package-info.java by LUCENE-6224, 93c897679d4, 2015). Current form: e1faeba08bd (#16904 by Deepcodr, PR commits authored 2026-10-24..2026-10-28, squash-merged by vsop-479 2026-11-02, main only) rewrote the page's examples to current APIs and edited this very line (SortField.STRING -> SortField.Type.STRING) but kept setSort.",
   "introduced_date": "2021-10-06 (9e9c3bd249e, author date = commit date 2021-10-06T16:13:24Z); current main form 2026-11-02 (e1faeba08bd, squash commit authored 2026-11-02)",
   "first_affected_version": "9.0.0 [exec] (the first release without Sort.setSort; against 8.11.4 the line compiles)",
   "affected_versions": "every 9.x and 10.x release, 9.0.0 to 10.6.0 (released 2026-10-29), and unreleased main, branch_11x and branch_10_6. [read] [exec]. Scope caveat: on the release pages setSort is one of 7 stale calls (with setAnalyzeRangeTerms, three Filter-taking search calls, the int SortField.STRING, broken since 4.0.0, and searcher.doc(int)), the other 6 of which #16904 fixed on main only, so 'the only remaining error on the page' holds for main from e1faeba08bd on. Not affected: 8.x and earlier, which still had setSort (their pages fail on SortField.STRING instead).",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16904",
    "https://github.com/apache/lucene/issues/14775",
    "https://github.com/apache/lucene/issues/10365",
    "https://github.com/apache/lucene/issues/338",
    "https://issues.apache.org/jira/browse/LUCENE-9325",
    "https://github.com/apache/lucene/issues/9534"
   ],
   "doc": "",
   "repro": "repro/LFV-1085/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-702",
   "priority": "low",
   "priority_rank": 1105,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-nori / KoreanPartOfSpeechStopFilterFactory (javadoc example of the stop tags)",
   "title": "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)",
   "summary": "You configure KoreanPartOfSpeechStopFilterFactory exactly as its class javadoc shows, tags=\"E,J\" (verbal endings and particles), through the constructor, the SPI name koreanPartOfSpeechStop or CustomAnalyzer, and expect an analyzer that drops endings and particles, as the same setting does on 9.x. Since 10.0.0 the factory constructor instead throws IllegalArgumentException 'No enum constant org.apache.lucene.analysis.ko.POS.Tag.E', because GITHUB#11778 deliberately replaced E and J with fine-grained tags (EP, EF, EC, ETN, ETM and JKS ... JC) and POS.resolveTag became an exact Tag.valueOf lookup. The tag change itself is intended; the defect is that the javadoc example (KoreanPartOfSpeechStopFilterFactory.java:28-36) was not updated and no CHANGES or MIGRATE entry tells 9.x users.",
   "impact_class": "minor",
   "introduced_commit": "451bab300eca451b0f09704f471443c29167e6ce (GITHUB#11778 via PR #11779, by danmuzi, approved by rmuir; main only, never backported to branch_9x): it removed POS.Tag.E/J and the E*/J* prefix mapping in POS.resolveTag and changed TestKoreanPartOfSpeechStopFilterFactory from \"E, J\" to the 14 fine-grained tags, but did not touch the factory javadoc [read]. The example line itself comes from 82cf667b254 (LUCENE-8453, #9499, 2018-08-10, first released in 7.5.0) and was valid when written.",
   "introduced_date": "2022-09-16 (merged; author date 2022-09-17 +0900)",
   "first_affected_version": "10.0.0 [exec] (every 9.x release still has POS.Tag.E/J and the prefix mapping [read]; 9.0.0, 9.3.0, 9.4.0, 9.12.0 and 9.12.3 pass [exec])",
   "affected_versions": "10.0.0 through 10.5.2 and main a9779ef3c193 [exec]; branch_10x and branch_10_6 carry the same example and no E/J tags [read], so 10.6.0 (released 2026-10-29 from branch_10_6) is affected too. Not affected: 7.5.0-9.12.3, where the example is valid [exec]; 7.4.0 has the factory but not yet the example [read]. Not fixed: upstream main a95c754ee003 (2026-10-26) still shows tags=\"E,J\", and no open PR touches the factory or POS.java [read].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/11778",
    "https://github.com/apache/lucene/issues/9499",
    "https://issues.apache.org/jira/browse/LUCENE-8453",
    "https://github.com/apache/lucene/issues/10607",
    "https://issues.apache.org/jira/browse/LUCENE-9567"
   ],
   "doc": "",
   "repro": "repro/LFV-702/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-930",
   "priority": "low",
   "priority_rank": 1106,
   "novelty": "known",
   "withheld": false,
   "area": "analysis-common / SimplePattern(Split)TokenizerFactory javadoc examples; core / util.automaton RegExp error message",
   "title": "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)",
   "summary": "You copy the class javadoc example of SimplePatternSplitTokenizerFactory, pattern=\"[ \\t\\r\\n]+\" (or SimplePatternTokenizerFactory's \"[^ \\t\\r\\n]+\"), which the javadoc offers 'to match tokens delimited by simple whitespace characters', and expect tokens split on spaces, tabs and newlines. In XML the backslashes stay literal, and since 9.0.0 RegExp deliberately rejects a backslash before a letter other than s, S, w, W, d, D (LUCENE-9370, MIGRATE.md), so building the factory throws IllegalArgumentException 'invalid character class \\116'; on 6.5 to 8.x the same pattern was accepted but split on the letters t, r and n instead. The message is a second, cosmetic defect: RegExp.java:1430 concatenates the int code point returned by next(), so \\t is reported as '\\116' and \\q as '\\113'.",
   "impact_class": "minor",
   "introduced_commit": "two stages: (1) 93fa72f77bd024aa09eef043c65c64a6524613dc (LUCENE-7465, apache/lucene#8517, a JIRA patch with no GitHub PR, by mikemccand; branch_6x backport c24e03e6bf4) added both factories with these examples, which never matched whitespace [read]; (2) 819e668ce2fcfcf86b652a191cdbe0fad0a8ffce (LUCENE-9370, apache/lucene#10410, PR apache/lucene-solr#1516 by markharwood, approved by jimczi; master only) made RegExp reject the escapes (intended, documented in MIGRATE.md) and added the 'invalid character class \\\\' + next() line with an int next() [exec]. fe42efc5918 (#14193, rmuir, first in 10.2.0) moved the throw into expandPreDefined and kept the int concatenation (10.1.0 and 10.2.0 outputs identical [exec])",
   "introduced_date": "2017-02-13 (author date of 93fa72f77bd, the examples); 2020-05-15 (author date of 819e668ce2f, the exception and the message; PR merged 2020-05-15)",
   "first_affected_version": "6.5.0 [exec] (the examples silently split on the letters t, r, n); 9.0.0 [exec] for the IllegalArgumentException and the code-point message (no 8.x tag contains 819e668ce2f [read])",
   "affected_versions": "6.5.0 to 8.11.4: the examples are accepted but split on space and the letters t, r, n, never on TAB, CR or LF [exec]; 9.0.0 to 10.6.0 (10.6.0 run as the branch_10_6 head jars at its release revision 4ae946e5a9b) and main a9779ef3c193: both examples throw IllegalArgumentException 'invalid character class \\116' and the message prints a decimal code point [exec]. Not affected: 6.4.2 and earlier have no such factories [exec]. Not fixed: upstream main 645d4fe14a20 (2026-10-28) still has RegExp.java:1430 and both example lines unchanged [read].",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/11678",
    "https://issues.apache.org/jira/browse/LUCENE-10642",
    "https://github.com/apache/lucene/issues/10410",
    "https://issues.apache.org/jira/browse/LUCENE-9370",
    "https://github.com/apache/lucene-solr/pull/1516",
    "https://github.com/apache/lucene/issues/14193"
   ],
   "doc": "",
   "repro": "repro/LFV-930/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-987",
   "priority": "low",
   "priority_rank": 1107,
   "novelty": "new",
   "withheld": false,
   "area": "analysis / stemming filters (PorterStemFilter and StempelFilter class javadoc)",
   "title": "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)",
   "summary": "PorterStemFilter's javadoc says its input must already be lower case, tells you to use LowerCaseFilter or LowerCaseTokenizer, and shows a MyAnalyzer built on new LowerCaseTokenizer(version, reader); StempelFilter's javadoc gives the same advice. LowerCaseTokenizer was removed in Lucene 8.0.0 (the migration notes say to use LetterTokenizer followed by LowerCaseFilter) and its (Version, Reader) constructor was already gone in 5.0.0, so the example does not compile and the advice names a class that no longer exists. Written with LetterTokenizer and LowerCaseFilter, the example compiles and stems 'Running Dogs' to [run, dog], so only the documentation is wrong.",
   "impact_class": "minor",
   "introduced_commit": "c0d2975970d (LUCENE-8498 'Remove LowerCaseTokenizer', migrated as #9544, by Alan Woodward (romseygeek), author date 2018-09-15, committed 2018-09-20, a JIRA patch, not a GitHub PR; first in 8.0.0) for the headline: it deleted LowerCaseTokenizer and LowerCaseTokenizerFactory and updated SimpleAnalyzer, StopAnalyzer, CharTokenizer, MIGRATE and CHANGES, but not these two class javadocs. The example's tokenizer line was stale earlier: ab0e85fafed (LUCENE-5388 'remove Reader from Tokenizer ctor', migrated as #6451, by Robert Muir (rmuir), author date 2014-01-09; it reached 5.0.0 through the branch_5x backport 55594bad9b0, 2014-09-18) changed this snippet's createComponents signature in the same diff that removed the LowerCaseTokenizer(Version, Reader) constructor, and left the tokenizer line. The prose dates from the initial import (bd3948c539e, 2001) and LUCENE-2298 (98c47c57e0a, 2010), the example from 647b5091697 (2012-09-12), all valid when written [read]",
   "introduced_date": "2018-09-15 (c0d2975970d author date; committed 2018-09-20) for the headline; 2014-01-09 (ab0e85fafed, trunk) and 2014-09-18 (backport 55594bad9b0, branch_5x) for the example's constructor call",
   "first_affected_version": "8.0.0 [exec] for the headline (LowerCaseTokenizer absent, while the prose of both files names it); 5.0.0 [exec] for the example alone (no (Version, Reader) constructor; the prose was still accurate then, and the class was deprecated from 7.6.0)",
   "affected_versions": "Headline (stale advice and example): every release from 8.0.0 to 10.6.0 (61 releases; 10.6.0 [exec]: its own example fails to compile and the minimal repro fails with -ea and -da) and main a9779ef3c193; example only (it does not compile, the advice is still accurate): 5.0.0 to 7.7.3 (47 releases). Not affected: 4.0.0 to 4.10.4 (executed on 4.10.4: the example compiles); 3.6.2 and earlier use another layout (read only). Not fixed upstream: main 645d4fe14a20, branch_11x, branch_10x and branch_10_6 still carry the text (read 2026-10-29). [exec] [read]. Caveat: all runs used JDK 25 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-987.html",
   "repro": "repro/LFV-987/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1026",
   "priority": "low",
   "priority_rank": 1108,
   "novelty": "new",
   "withheld": false,
   "area": "core / search (BulkScorer#score javadoc example)",
   "title": "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)",
   "summary": "The javadoc of BulkScorer#score(LeafCollector, Bits, int, int) explains the window contract (ignore documents before min, return a value >= max) and then shows 'a Scorer-based implementation could look like below'. Copied into code on any release since 5.5.0 the example does not compile, because it calls scorer.advance(min) and scorer.nextDoc(): Scorer stopped extending DocIdSetIterator in LUCENE-6919 and now offers those methods only through scorer.iterator(). With scorer.iterator().advance(min) and scorer.iterator().nextDoc() the example compiles and honours the contract, so only the javadoc is wrong.",
   "impact_class": "minor",
   "introduced_commit": "ddb3a97678f (trunk, svn r1719081; LUCENE-6919 'Change the Scorer API to expose an iterator instead of extending DocIdSetIterator', migrated as #7977, by Adrien Grand (jpountz), author date 2015-12-10; the branch_5x backport 728c5876430, svn r1719124, the same day, is the one released in 5.5.0): it changed 'public abstract class Scorer extends DocIdSetIterator' to a Scorer with 'public abstract DocIdSetIterator iterator()', and in BulkScorer.java it changed only the cost() javadoc link ({@link Scorer#cost()} to {@link DocIdSetIterator#cost()}), leaving the score() example's 'doc = scorer.advance(min);' and 'doc = scorer.nextDoc();' as they were. The example was written by cb3ec682d41 (LUCENE-6184, #7246, 2015-01-19, first released in 5.1.0), when Scorer still extended DocIdSetIterator, so it was valid then; its acceptDocs lines come from d671dd8d890 (LUCENE-6553, #7611, 2015-06-25, 5.3.0); the later edits are mechanical (2d6ad2fee6d, LUCENE-9570 reformatting, 2020-12-23; 378ca8d1bbf, #15573, 2026-01-15, markup only) [read]",
   "introduced_date": "2015-12-10 (ddb3a97678f and its branch_5x backport 728c5876430, author date, svn import; the 5.4.0 tag commit is from earlier the same day and does not contain it)",
   "first_affected_version": "5.5.0 [exec] (the verbatim example compiles against 5.4.1 [exec] and fails on 5.5.0 with the same two errors as on main)",
   "affected_versions": "every release from 5.5.0 to 10.6.0 (RC1 4ae946e5a9b), branch_10x 657014b3c579 and main 645d4fe14a20; not affected: 5.1.0-5.4.1 (the example compiled, Scorer extended DocIdSetIterator) and every release before 5.1.0 (no such example: 5.0.0 has only score(LeafCollector, int max)). Not fixed upstream: main, branch_10x and branch_10_6 still carry both stale lines (read 2026-10-29; branch_11x too); the last commit touching BulkScorer.java, 378ca8d1bbf3 (#15573, 2026-01-15), kept them. [exec] [read]. Caveat: all runs used JDK 25 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1026.html",
   "repro": "repro/LFV-1026/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1032",
   "priority": "low",
   "priority_rank": 1109,
   "novelty": "new",
   "withheld": false,
   "area": "memory / MemoryIndex (class javadoc example)",
   "title": "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)",
   "summary": "The MemoryIndex class javadoc shows an 'Example Usage' program that adds two fields to a MemoryIndex, parses '+author:james +salmon~ +fish* manual~' and prints \"it's a match\". Its first and fifth lines call new SimpleAnalyzer(version) and new QueryParser(version, \"content\", analyzer), but both Version-taking constructors were removed in 5.0.0 (LUCENE-5859), so the example has not compiled on any release since then, whatever type version is given. With new SimpleAnalyzer() and new QueryParser(\"content\", analyzer) the same example compiles and prints \"it's a match\" on main and 10.5.2, so only the javadoc is wrong.",
   "impact_class": "minor",
   "introduced_commit": "9938a39a872 (trunk, svn r1616901; LUCENE-5859 'Remove Version from Analyzer constructors', migrated as #6921, by Ryan Ernst (rjernst), author date = commit date 2014-08-08): it removed SimpleAnalyzer(Version) (leaving SimpleAnalyzer()) and the classic QueryParser(Version, String, Analyzer) (leaving QueryParser(String, Analyzer)) and updated MemoryIndexTest.java, but not the MemoryIndex.java class javadoc example. The released 5.x line got the same removal through the branch_5x bulk backport 55594bad9b0 (LUCENE-5944, Robert Muir, 2014-09-18, svn r1626055); 9938a39a872 itself is first released in 6.0.0. On branch_4x, cb9beac7079 (LUCENE-5859, Ryan Ernst, 2014-08-21, first released in 4.10.0) only deprecated both constructors, so 4.10.x still compiles the example. The two calls were written by 647b5091697 (trunk) / d8d5bf5e07d (branch_4x) ('code snippet improvements: fix out of date api usage and add syntax highlighting', Robert Muir, 2012-09-12, first released in 4.0.0) and were valid then [read]",
   "introduced_date": "2014-08-08 (9938a39a872, trunk, author date = commit date); released through the branch_5x backport 55594bad9b0 of 2014-09-18",
   "first_affected_version": "5.0.0 [exec] (the verbatim example compiles on 4.10.4 [exec], where both constructors still exist as deprecated, and fails on 5.0.0 with identical example text)",
   "affected_versions": "every release from 5.0.0 to 10.6.0 (RC1 4ae946e5a9b), branch_10x 657014b3c579, branch_11x f85446cb1af1 and main 645d4fe14a20; not fixed upstream (recheck 2026-10-29: both calls are still at lines 147 and 151 on main and branch_11x and at lines 115 and 119 on branch_10x and branch_10_6; the latest commit touching the file on main, bfe5c847d3c4 (#16383, author date 2026-07-27), does not change them). [exec] [read]. branch_10x and branch_11x: text only (that jar set has no memory or queryparser jar). Before 4.0.0 the example had an older, different form (not claimed). Not new in 10.6. Caveat: all runs used JDK 25 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1032.html",
   "repro": "repro/LFV-1032/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1028",
   "priority": "low",
   "priority_rank": 1110,
   "novelty": "known",
   "withheld": false,
   "area": "queryparser / flexible StandardQueryParser (class and constructor javadoc examples)",
   "title": "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)",
   "summary": "You copy the StandardQueryParser class javadoc's 'Typical usage, including configuration tweaks' (StandardQueryConfigHandler config = qpHelper.getQueryConfigHandler(); config.setAllowLeadingWildcard(true); config.setAnalyzer(new WhitespaceAnalyzer())) or the constructor javadoc's 'The same as:' (qp.getQueryConfigHandler().setAnalyzer(analyzer)) and expect it to compile. Instead javac rejects four lines: getQueryConfigHandler() is declared to return QueryConfigHandler, which cannot be assigned to StandardQueryConfigHandler, and neither config handler has setAllowLeadingWildcard or setAnalyzer (they offer only the key-based get/has/set/unset(ConfigurationKey, ...)). The setters are methods of StandardQueryParser itself, which is exactly what the constructor body calls (this.setAnalyzer(analyzer)), so the fix is javadoc only.",
   "impact_class": "minor",
   "introduced_commit": "343992fcbb4b31249f07354014723f18d0508d8a (Subversion trunk r800191, 'LUCENE-1567: New flexible QueryParser framework.', JIRA LUCENE-1567, migrated to GitHub as #2641; no pull request; committed by Michael Busch, CHANGES.txt credits the contribution to Luis Alves and Adriano Campos): it wrote both examples (then with the names OriginalQueryParserHelper / OriginalQueryConfigHandler: the usage block in contrib's queryParser/package.html and the constructor example in the helper's javadoc) while getQueryConfigHandler() already returned QueryConfigHandler, an attribute-based handler with no such setters, so the examples never compiled and this is not a regression. Later commits only renamed the classes (0b6769aa113, LUCENE-1782, 2009-08-07), moved the block (6e5b0f028f8, LUCENE-1862, 2009-09-01, into overview.html; ba57e92f227, 2012-04-22; f725b27e12a, LUCENE-10223 / PR #429, 2021-11-11, into the class javadoc, branch_9x ff9ee28c603) or changed the markup (376256316b0, 2cbf261032d, 378ca8d1bbf / #15573). LUCENE-2979 (2011, keys instead of attributes) rewrote the config API without updating the examples [read]",
   "introduced_date": "2009-08-03 (343992fcbb4); in the StandardQueryParser class javadoc since 2021-11-11 (f725b27e12a and its branch_9x backport ff9ee28c603, first released in 9.1.0)",
   "first_affected_version": "2.9.0 [exec] (the first release with the flexible query parser, then in contrib; 2.4.1 has no such API, so there is no unaffected release)",
   "affected_versions": "every release with the flexible query parser, 2.9.0 to 10.6.0 (RC1 4ae946e5a9b), plus branch_10x 657014b3c579 [read] and main 645d4fe14a20; not fixed upstream (upstream main still has StandardQueryParser.java:55-57 and :250, contents API 2026-10-29). [exec] [read]. Caveat: all runs on Linux aarch64 with JDK 25.0.3.",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15573",
    "https://github.com/apache/lucene/issues/624",
    "https://github.com/apache/lucene/issues/16821",
    "https://github.com/apache/lucene/issues/2641",
    "https://issues.apache.org/jira/browse/LUCENE-1567",
    "https://github.com/apache/lucene/issues/4053"
   ],
   "doc": "",
   "repro": "repro/LFV-1028/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1031",
   "priority": "low",
   "priority_rank": 1111,
   "novelty": "known",
   "withheld": false,
   "area": "queries / spans (package javadoc example)",
   "title": "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)",
   "summary": "The spans package overview says span queries 'may be freely intermixed with other Lucene queries' and shows how to restrict its John Kerry / George Bush span query to documents that also contain the word 'iraq'. That three-line example does not compile: new BooleanQuery() has had no public constructor since 6.0 (a BooleanQuery is built with BooleanQuery.Builder), the abstract Query class it is assigned to has no add(...) method, and TermQuery has never had a (String, String) constructor. Written with BooleanQuery.Builder, Occur.MUST and new TermQuery(new Term(\"content\", \"iraq\")) it compiles, so only the code in the javadoc is wrong.",
   "impact_class": "minor",
   "introduced_commit": "45c5ec45771 (Doug Cutting, 'Improved javadoc for span queries.', svn r150276, author date 2004-03-30; the message names no issue): it added the 'iraq' block to src/java/org/apache/lucene/search/spans/package.html already broken, because Query never had an add() method and TermQuery then had only TermQuery(Term) [read]. The third line broke later: 4aafacfbef4 (LUCENE-6570 'Make BooleanQuery immutable', #7628, Adrien Grand, author date 2015-06-18) made BooleanQuery Builder-only, and 6.0.0 is the first release without the public no-argument constructor. Later edits carried the three lines over unchanged: d51068ffd66 (LUCENE-2894, 2011, markup), 8f3a71443bd (LUCENE-6224, 2015, package.html to package-info.java), 4464cd87cc5 (LUCENE-9204, #152, 2021, move to the queries module), 378ca8d1bbf (#15573, 2026-01-15, markup only) [read]",
   "introduced_date": "2004-03-30 (45c5ec45771, author date: the block, broken from the start); 2015-06-18 (4aafacfbef4, LUCENE-6570, author date: the third broken line, released in 6.0.0)",
   "first_affected_version": "1.4 [exec] (the first final release with the block; its first tag is 1.4-rc3); the example has not compiled in any release",
   "affected_versions": "every release from 1.4 to 10.6.0 (the RC1 build, branch_10_6 4ae946e5a9b) and main 645d4fe14a20; not fixed upstream (main, branch_11x and branch_10_6 still carry the three lines, contents API 2026-10-29). 1.4 to 5.5.5: 2 broken lines (Query.add and TermQuery(String, String)); 6.0.0 to main: 3 (new BooleanQuery() too). [exec] [scan: the finder's bytecode scan of 158 jar sets, 1.9.1 to main, finds the called members missing in every one] [read]. Caveat: all runs used JDK 25 on Linux aarch64.",
   "security": "none",
   "upstream_links": [
    "https://lists.apache.org/thread/7tvqy4qhygt6y57z091gfsg27m7g2b7r",
    "https://github.com/apache/lucene/issues/7628",
    "https://issues.apache.org/jira/browse/LUCENE-6570",
    "https://github.com/apache/lucene/issues/7286",
    "https://issues.apache.org/jira/browse/LUCENE-6224",
    "https://github.com/apache/lucene/issues/15573"
   ],
   "doc": "",
   "repro": "repro/LFV-1031/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1020",
   "priority": "low",
   "priority_rank": 1112,
   "novelty": "new",
   "withheld": false,
   "area": "core / index merge policy (TemporalMergePolicy class javadoc example)",
   "title": "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)",
   "summary": "The TemporalMergePolicy class javadoc shows, under 'Configuration:', how to build the policy with a fluent chain: setTemporalField(\"timestamp\"), setBaseTimeSeconds(3600), setMinThreshold(4), setMaxThreshold(8) and setCompactionRatio(1.2), then passes it to IndexWriterConfig.setMergePolicy. The class has no setBaseTimeSeconds method: its setter is setBaseTimeInSeconds(long), renamed on a reviewer's suggestion while #15620 was in review, so the copied example fails with javac 'cannot find symbol: method setBaseTimeSeconds(int)'. With setBaseTimeInSeconds(3600) the example compiles and the getters return exactly the commented values, so only the javadoc is wrong.",
   "impact_class": "minor",
   "introduced_commit": "1596b7604b67 (main) and its branch_10x backport 4a2c3fd0901c (the one released in 10.5.0): the squash commits of PR #15620 'Add Temporal Merge Policy for time-series data' (opened by GitHub user churromorales; author date 2026-03-17), which added the class with the example already stale. Inside the PR the example matched the code in the first commit bd45e5dbce8e (2026-01-26: example and setter both setBaseTimeSeconds); 3560f73a24a6 (2026-02-11) applied a reviewer's suggestion (shubhamsrkdev, discussion_r2791054529) to rename the setter to setBaseTimeInSeconds(long), and b4bc4b7ff4b4 ('Changes per PR review', same day) edited the same example block (the exponential-buckets line), the @see tag and the tests, but left line 61 unchanged. These are the only commits on the file on main, branch_10x and branch_10_6 [read]",
   "introduced_date": "2026-03-17 (1596b7604b67 and 4a2c3fd0901c, author date); inside the PR the example became stale on 2026-02-11 (3560f73a24a6, author date)",
   "first_affected_version": "10.5.0 [exec] (the first release with TemporalMergePolicy; 10.4.0 and 9.12.3 do not have the class [exec])",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2, 10.6.0 (RC1 4ae946e5a9b), branch_10x 657014b3c579 and main 645d4fe14a20; not fixed upstream (upstream main HEAD still 645d4fe14a20 at 2026-10-29, and line 61 still reads '.setBaseTimeSeconds(3600)' there). [exec] [read]. Not affected: 10.4.0 and older and all 9.x, which have no TemporalMergePolicy (the repro fails there only with 'cannot find symbol: class TemporalMergePolicy'). Not new in 10.6: 10.5.0 to 10.5.2 already have it. Caveat: all runs used JDK 25 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1020.html",
   "repro": "repro/LFV-1020/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1019",
   "priority": "low",
   "priority_rank": 1113,
   "novelty": "new",
   "withheld": false,
   "area": "core / geo (Circle class javadoc example)",
   "title": "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)",
   "summary": "The javadoc of org.apache.lucene.geo.Circle shows 'Example usage': make a circle of 1 km around the Eiffel Tower, then build a query with LatLonShape.newDistanceQuery(\"location\", circle). Copied into code, that line does not compile on any release that has the example (10.3.0 and later), because the method has always needed a ShapeField.QueryRelation argument that says how indexed shapes must relate to the circle (for example INTERSECTS). With LatLonShape.newDistanceQuery(\"location\", ShapeField.QueryRelation.INTERSECTS, circle) it compiles and matches a point 500 m from the centre but not one 5 km away, so only the javadoc is wrong.",
   "impact_class": "minor",
   "introduced_commit": "bb8b1397b01 (#14534 'Improve user-facing docs for geo package', by jainankitk, author date 2025-05-06, merged 2025-05-07T00:06Z, milestone 10.3.0; the branch_10x commit af62580a673 has the same author date): it added the Circle class javadoc with the 'Example usage' block, whose query line calls a two-argument newDistanceQuery(String, Circle) that has never existed. LatLonShape.newDistanceQuery has had exactly one signature, (String, ShapeField.QueryRelation, Circle...), since it was added by d48bafb2999 (LUCENE-8707, #587, by Ignacio Vera, 2020-02-19; branch_8x 50168ab5bc8, released in 8.5.0), so the example could not compile on the day it was written. The PR's one review (an approval, 'Great!') and one comment (about the commit message) do not discuss the example. The only later commit touching Circle.java, 1518164afa3 (#15874, 2026-04-01), does not change it [read]",
   "introduced_date": "2025-05-06 (bb8b1397b01 and af62580a673, author date 2025-05-06T17:06:15-07:00 = 2025-05-07T00:06:15Z)",
   "first_affected_version": "10.3.0 [exec] (the first release with #14534; 10.2.2, cut from branch_10_2 after the merge, has no example [exec])",
   "affected_versions": "10.3.0, 10.3.1, 10.3.2, 10.4.0, 10.5.0, 10.5.1, 10.5.2, 10.6.0 (RC1 4ae946e5a9b), branch_10x 657014b3c579, branch_10_6, branch_11x f85446cb1af1 and main 645d4fe14a20; not affected: 10.2.2 and every earlier release (the Circle javadoc has no example; #14534 was never backported to 9.x). Not fixed upstream: main, branch_10x, branch_10_6 and branch_11x all still have the two-argument call at Circle.java:44 (2026-10-29). [exec] [read]. Caveat: all runs used JDK 25 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1019.html",
   "repro": "repro/LFV-1019/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1029",
   "priority": "low",
   "priority_rank": 1114,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / document suggesters (ContextSuggestField class javadoc example)",
   "title": "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)",
   "summary": "The ContextSuggestField javadoc shows how to add a suggestion with two contexts: document.add(new ContextSuggestField(name, \"suggestion\", Arrays.asList(\"context1\", \"context2\"), 4)). Copied into code, that line does not compile on any release, because the only constructor takes the weight third and the contexts last, as a varargs list: (name, value, weight, contexts...). Written as new ContextSuggestField(name, \"suggestion\", 4, \"context1\", \"context2\") it compiles, and a ContextQuery on context1 finds the suggestion with weight 4, so only the javadoc is wrong.",
   "impact_class": "minor",
   "introduced_commit": "be4d58c7740 (LUCENE-6459, apache/lucene#7518 '[suggest] Query Interface for suggest API'; the patch areek (Areek Zillur) wrote, committed by mikemccand (Michael McCandless), trunk r1682158, author date 2015-05-28; branch_5x 380bb29f395, r1682170): it added ContextSuggestField with this class-javadoc example while the only constructor was (String name, Collection<CharSequence> contexts, String value, int weight), so the example did not compile even then (javac against a signature stub of that constructor: 'String cannot be converted to Collection<CharSequence>'). cecebbc7506 (LUCENE-6515, #7573 'Suggest API cleanup', by areek, 2015-06-02; branch_5x 405f4b77337) then changed the constructor on purpose to (String, String, int, CharSequence...) and left the example unchanged, which gives today's 'List<T> conforms to int' error; neither intermediate state was released. git blame on main 645d4fe14a20 still attributes the example lines to be4d58c7740, and the only later commit to touch the block, 378ca8d1bbf3 (#15573, 2026-01-15), changed only its <pre> wrapper [read]",
   "introduced_date": "2015-05-28 (be4d58c7740 / 380bb29f395, LUCENE-6459); the constructor change that gives the current error: 2015-06-02 (cecebbc7506 / 405f4b77337, LUCENE-6515)",
   "first_affected_version": "5.3.0 [exec] (the first release with ContextSuggestField; it already has the broken example; 5.2.1 and earlier have no such class [exec])",
   "affected_versions": "every release from 5.3.0 to 10.5.2 (103 releases), 10.6.0 (RC1 4ae946e5a9b), branch_9_12, branch_10x 657014b3c579, branch_10_6, branch_11x f85446cb1af1 and main 645d4fe14a20; not affected: 5.2.1 and earlier (the class does not exist). Not fixed upstream: all of these branches still have the wrong call at ContextSuggestField.java:37 (2026-10-29; main rechecked the same day). [exec] [read]. Caveat: all runs used JDK 25 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1029.html",
   "repro": "repro/LFV-1029/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-984",
   "priority": "low",
   "priority_rank": 1115,
   "novelty": "new",
   "withheld": false,
   "area": "misc / index reordering (BPIndexReorderer class javadoc example)",
   "title": "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)",
   "summary": "The BPIndexReorderer javadoc shows 'typical usage': build a ForkJoinPool, hand it to reorderer.setForkJoinPool(pool), then call reorderer.reorder(reader, targetDir). If you copy that into your code it does not compile on any release since 9.12.0: setForkJoinPool no longer exists (removed in 10.0.0) and reorder now needs a third argument, the Executor to run on. Passing the same pool as that third argument (and deleting the setter line) compiles and works, so only the code shown in the javadoc is wrong.",
   "impact_class": "minor",
   "introduced_commit": "ff8b81afc59 (#13289 'Integrate merge-time index reordering with the intra-merge executor.', by jpountz, author date = merge date 2024-09-12; branch_9x backport a2290ecb237, same author date): it replaced reorder(CodecReader, Directory) by reorder(CodecReader, Directory, Executor) and removed setForkJoinPool on main (on branch_9x it kept setForkJoinPool as @Deprecated, 'Pass an executor to reorder(CodecReader, Directory, Executor) instead'), updated TestBPIndexReorderer, and left the class javadoc example as it was (none of its hunks touches the example; no CHANGES or MIGRATE entry). The example itself dates from 39f3777886c (#12489, 2023-09-14, the reorder line) and 36432fa6724 (#12568, 2023-09-19, the setForkJoinPool(pool) line), both valid when written [read]",
   "introduced_date": "2024-09-12 (ff8b81afc59, #13289, author and merge date; the branch_9x backport a2290ecb237 has the same author date)",
   "first_affected_version": "9.12.0 [exec] (only the 2-argument reorder fails there; setForkJoinPool still exists, deprecated); 10.0.0 [exec] is the first release where both calls fail",
   "affected_versions": "9.12.0-9.12.3 (1 broken call: reorder), every 10.x release from 10.0.0 to 10.5.2 (2 broken calls: setForkJoinPool and reorder), 10.6.0 (released 2026-10-29; branch_10_6 4ae946e5a9b) [exec] and main a9779ef3c193; not affected: 9.8.0-9.11.1 (the verbatim example compiles; the class did not exist before 9.8.0). Not fixed upstream: main 645d4fe14a20, branch_11x, branch_10_6 and branch_10x still carry both stale lines (2026-10-29). [exec] [read]. Caveat: all runs used JDK 25 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-984.html",
   "repro": "repro/LFV-984/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1034",
   "priority": "low",
   "priority_rank": 1116,
   "novelty": "new",
   "withheld": false,
   "area": "monitor / ConcurrentQueryLoader (class javadoc example)",
   "title": "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)",
   "summary": "The ConcurrentQueryLoader javadoc says 'Use as follows:' and shows a loop that first creates a List<QueryError> errors and passes it to new ConcurrentQueryLoader(monitor, errors). Copied into code, it does not compile on any release: Lucene has no QueryError class, and the only constructors are (Monitor) and (Monitor, int, int); the two lines are left over from Luwak, the project the monitor module was ported from, whose API had both. Written as new ConcurrentQueryLoader(monitor) without the list, the example compiles (the same form the module's own test uses), so only the javadoc is wrong.",
   "impact_class": "minor",
   "introduced_commit": "251dbe7cea8 (trunk) and its branch_8x copy b8773d13ad8, both 'LUCENE-8766: Add monitor subproject' (migrated as #9811, 'Add Luwak as a lucene module'), by Alan Woodward (romseygeek), author date 2019-06-13; the branch_8x commit is the one released in 8.2.0. They added ConcurrentQueryLoader with the class-javadoc example copied from Luwak while the class already had only the (Monitor) and (Monitor, int, int) constructors, so the example never compiled in any Lucene commit. The mismatch began on the never-merged PR branch apache/lucene-solr#648: its commit d58aa35f5b8 (2019-04-19, 'Refactor the Monitor to take Query objects rather than string representations') deleted QueryError.java and the error-list constructors and made close() throw the collected IOExceptions, but left the example unchanged; the branch was squashed into the two commits above. git blame on main 645d4fe14a20 still attributes example lines 43-48 to 251dbe7cea8; the later commits 2cbf261032d (LUCENE-9570 reformat, 2021-01-05) and 378ca8d1bbf3 (#15573, 2026-01-15, the <pre> markup) touched the block without fixing it [read]",
   "introduced_date": "2019-06-13 (251dbe7cea8 / b8773d13ad8, LUCENE-8766, author date); the API change that made the copied example stale: 2019-04-19 on the never-merged PR branch (d58aa35f5b8)",
   "first_affected_version": "8.2.0 [exec] (the first release of the monitor module: the verbatim example fails there with 'cannot find symbol: class QueryError', and new ConcurrentQueryLoader(monitor) compiles); 8.1.1 and earlier have no monitor module [exec]",
   "affected_versions": "every lucene-monitor release from 8.2.0 to 10.6.0 (57 versions to 10.5.2, and 10.6.0 = branch_10_6 4ae946e5a9b [exec]), branch_10x 657014b3c579, branch_11x f85446cb1af1 and main 645d4fe14a20; not affected: 8.1.1 and earlier (no monitor module). Not fixed upstream: upstream main is still at 645d4fe14a20 and the newest commit on the file is 378ca8d1bbf3 (#15573, 2026-01-15), which kept the stale lines (2026-10-29). [exec] [read]. Caveat: all runs used JDK 25 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1034.html",
   "repro": "repro/LFV-1034/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1040",
   "priority": "low",
   "priority_rank": 1117,
   "novelty": "new",
   "withheld": false,
   "area": "benchmark / search-quality package (quality/package-info.java: the package overview's TREC sample)",
   "title": "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)",
   "summary": "You start a search-quality evaluation from the benchmark quality package overview, which presents its code block as 'a sample code used to run the TREC 2006 queries 701-850 on the .Gov2 collection', and expect it to compile against the package's API. It does not, on main or on any release since 2.3.0: the sample calls qrun.execute(maxResults, judge, submitLog, logger), but QualityBenchmark has only execute(Judge, SubmissionReport, PrintWriter) and takes the result count from setMaxResults(int), so javac rejects the call (the DirectoryReader.open line also ends with ':' instead of ';'). The API change was deliberate (LUCENE-1116, 2008) and the in-tree QueryDriver does it right (setMaxResults, then the 3-argument execute); only the page was never updated.",
   "impact_class": "minor",
   "introduced_commit": "9e65cd554f2e (LUCENE-1116 = #2193 'contrib.benchmark.quality package improvements', Doron Cohen, svn era, no PR, author date 2008-01-03) replaced execute(int maxResults, Judge, SubmissionReport, PrintWriter) with execute(Judge, SubmissionReport, PrintWriter) plus setMaxResults(int) ('move control over max-docs-to-retrieve from benchmark constructor to a setter method (API change)'), and updated QueryDriver and TestQualityRun but not the package.html sample [exec]. The sample was added, then correct, by 98fa2d898d1 (LUCENE-836 = #1911, 2007-07-27). 647b5091697 (2012-09-12, 'code snippet improvements: fix out of date api usage', first in 4.0.0) rewrote the sample's reader lines, left the execute call and added the ':' typo on main line 41 [read].",
   "introduced_date": "2008-01-03 (9e65cd554f2, author date); the ':' typo 2012-09-12 (647b5091697)",
   "first_affected_version": "2.3.0 [exec], the first release with the quality package; it already contains 9e65cd554f2, so no release ever shipped a compiling version of the sample (it compiled only on trunk, 2007-07-27 to 2008-01-03)",
   "affected_versions": "every release from 2.3.0 to 10.6.0 (10.6.0 = branch_10_6 4ae946e5a9b [exec]), main 645d4fe14a20 and upstream main a518d9ae1777 (2026-10-29); not fixed upstream. [exec] [read]. branch_10x was decommissioned upstream on 2026-10-29 (#16911), which removed the file there; that is not a fix. Not new in 10.6. Caveat: all runs used JDK 25 on Linux aarch64; the 2007-2008 commit-level runs compile against the 2.3.0 core release jar.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1040.html",
   "repro": "repro/LFV-1040/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1021",
   "priority": "low",
   "priority_rank": 1118,
   "novelty": "new",
   "withheld": false,
   "area": "core / index (UpgradeIndexMergePolicy class javadoc example)",
   "title": "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)",
   "summary": "The UpgradeIndexMergePolicy javadoc says that for a fully customizable upgrade you can use this policy like any other merge policy and call forceMerge, and shows five lines that start with new IndexWriterConfig(Version.LUCENE_XX, new KeywordAnalyzer()). That two-argument constructor was removed in 5.0.0 (LUCENE-5871), so the example does not compile on any release since then, whatever real version constant you put in for the LUCENE_XX placeholder. With new IndexWriterConfig(new KeywordAnalyzer()) the same example compiles and, run on a 10.0.0 index, rewrites every segment to the current version and keeps every live document, so only the javadoc is wrong.",
   "impact_class": "minor",
   "introduced_commit": "872bd9145cd (trunk, svn r1617004; LUCENE-5871 'Remove Version from IndexWriterConfig', migrated as #6933, by Ryan Ernst (rjernst), author date = commit date 2014-08-09): it replaced IndexWriterConfig(Version matchVersion, Analyzer analyzer) with IndexWriterConfig(Analyzer analyzer) and updated callers in 451 files, including IndexUpgrader.java, but not UpgradeIndexMergePolicy.java, whose class javadoc example kept the Version argument. The released 5.x line got the same removal through the branch_5x bulk backport 55594bad9b0 (LUCENE-5944, Robert Muir, 2014-09-18, svn r1626055); 872bd9145cd itself is not an ancestor of the 5.0.0 tag. The LUCENE-5871 javadoc follow-up 5e5072d3c2d ('LUCENE-5859, LUCENE-5871: Remove Version.LUCENE_CURRENT from javadocs', Steven Rowe, 2014-08-21) fixed the same stale call in core's overview.html; this example uses the placeholder LUCENE_XX, not LUCENE_CURRENT. The example was written by 600a50bb2ae (LUCENE-3082, #4155, Uwe Schindler, 2011-05-09, first released in 3.2.0) and was valid then [read]",
   "introduced_date": "2014-08-09 (872bd9145cd, trunk, author date = commit date); released through the branch_5x backport 55594bad9b0 of 2014-09-18",
   "first_affected_version": "5.0.0 [exec] (the verbatim example compiles on 4.10.4 [exec], where IndexWriterConfig(Version, Analyzer) still exists, and fails on 5.0.0)",
   "affected_versions": "every release from 5.0.0 to 10.6.0 (RC1 4ae946e5a9b), branch_10x 657014b3c579 and main 645d4fe14a20; not fixed upstream (upstream main HEAD still 645d4fe14a20 at 2026-10-29, and line 37 still carries the call on main, branch_10x and branch_10_6; the latest commits touching the file, 54283150a81 (#16255, 2026-06-14) and 378ca8d1bbf (#15573, 2026-01-15), do not change it). [exec] [read]. branch_10x: static scan only (that jar set has no analysis-common jar for the repro). Before 3.2.0 the class does not exist (n/a). Caveat: all runs used JDK 25 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1021.html",
   "repro": "repro/LFV-1021/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1033",
   "priority": "low",
   "priority_rank": 1119,
   "novelty": "known",
   "withheld": false,
   "area": "facet / taxonomy merge (OrdinalMappingLeafReader class javadoc example)",
   "title": "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)",
   "summary": "The OrdinalMappingLeafReader javadoc says 'For re-mapping the ordinals during index merge, do the following:' and shows a recipe: merge the old taxonomy into the new one, then wrap each old segment in an OrdinalMappingLeafReader and add it to the new index. Copied into code it does not compile on any release since 5.0.0: it builds an IndexWriterConfig from a Version and passes a MultiReader to addIndexes (both removed in 5.0.0), calls a 2-argument OrdinalMappingLeafReader constructor (the only one also takes the source FacetsConfig), and calls the instance method addTaxonomy as if it were static. Written the way TaxonomyMergeUtils.merge does it (destTaxoWriter.addTaxonomy, IndexWriterConfig(analyzer), the 3-argument constructor wrapped with SlowCodecReaderWrapper.wrap, addIndexes(CodecReader...)), the same steps compile and give correct facet counts, so only the javadoc is wrong.",
   "impact_class": "minor",
   "introduced_commit": "no single commit: the example has not compiled in any release that carried it, and the four errors on main come from four changes. Headline (the three API-drift errors, the earliest of them): 1f37d6b4486 (trunk, svn r1612079; branch_4x 95c159ea65a, r1612081; Shai Erera, author date 2014-07-20, 'LUCENE-5801: OrdinalMappingAtomicReader should not wrap non-facet BinaryDocValues fields', JIRA LUCENE-5801 migrated as #6863): it replaced the class's (AtomicReader, int[]) constructor with (AtomicReader, int[], FacetsConfig) and updated TaxonomyMergeUtils, but left the class javadoc example calling the 2-argument form (main line 55). The other three: line 50, IndexWriterConfig(Version, Analyzer), removed by LUCENE-5871 (#6933; trunk 872bd9145cd, 2014-08-09; branch_5x 55594bad9b0, 2014-09-18); line 57, addIndexes(IndexReader...), replaced by LUCENE-6158 (#7220; b10d20a122c / e2b348cef08, 2015-01-07) and then LUCENE-6165 (#7227; ec43ca9fd8b / 1a394ff3950, 2015-01-08, addIndexes(CodecReader...)), each time updating TaxonomyMergeUtils but not the example; line 45, the static-style DirectoryTaxonomyWriter.addTaxonomy(srcTaxoDir, map), written by the fix for the outside report LUCENE-4788 (#5853; f3ee1dc3c51, message mislabeled LUCENE-4778, / 370fa20427b, 2013-02-21), never compiled because addTaxonomy has always been an instance method. The example itself dates from LUCENE-4304 (#5372; 81bff57343c / 6d6940a4df3, 2012-08-14), whose first line already called a nonexistent addTaxonomies(); LUCENE-5569 (#6631; 85bf3181737 + 83cbdfda3de, 2014-09-23/24) renamed the class and the example's type names and kept the calls; later edits (bab0b463371, 2014-11-28, doclint; 378ca8d1bbf3, #15573, 2026-01-15, markup) did not touch them [read]",
   "introduced_date": "2014-07-20 (1f37d6b4486 / 95c159ea65a, LUCENE-5801 follow-up); the other errors: 2013-02-21 (line 45, LUCENE-4788 fix), 2014-08-09 trunk / 2014-09-18 branch_5x (line 50, LUCENE-5871), 2015-01-07/08 (line 57, LUCENE-6158 and LUCENE-6165)",
   "first_affected_version": "5.0.0 [exec] (the first release of OrdinalMappingLeafReader, the LUCENE-5569 rename of OrdinalMappingAtomicReader; it already has all four errors). The predecessor's example never compiled either [exec]: 4.0.0-4.1.0 (1 error, the nonexistent addTaxonomies(), the error LUCENE-4788 reported), 4.2.0-4.6.1 (1 error, line 45), 4.10.0-4.10.4 (2 errors, lines 45 and 55); the class is absent in 4.7.0-4.9.1. No release that ships this example compiles it.",
   "affected_versions": "every release from 5.0.0 to 10.6.0 (RC1 4ae946e5a9b), branch_10x 657014b3c579, branch_10_6, branch_11x f85446cb1af1 and main 645d4fe14a20, with the same four errors at OrdinalMappingLeafReader.java:45, :50, :55 and :57 (main numbering); before 5.0.0 the class does not exist under this name (predecessor: see first_affected_version). Not fixed upstream: main, branch_10x, branch_10_6 and branch_11x still carry all four lines (GitHub contents API, read-only, 2026-10-29). [exec] [read]. Caveat: all runs used JDK 25 on Linux aarch64.",
   "security": "none",
   "upstream_links": [
    "https://issues.apache.org/jira/browse/LUCENE-4788",
    "https://github.com/apache/lucene/issues/5853",
    "https://issues.apache.org/jira/browse/LUCENE-5801",
    "https://github.com/apache/lucene/issues/6863",
    "https://issues.apache.org/jira/browse/LUCENE-5871",
    "https://github.com/apache/lucene/issues/6933"
   ],
   "doc": "",
   "repro": "repro/LFV-1033/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-988",
   "priority": "low",
   "priority_rank": 1120,
   "novelty": "new",
   "withheld": false,
   "area": "core / util/fst (FSTCompiler.compile() javadoc example)",
   "title": "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)",
   "summary": "The javadoc of FSTCompiler.compile() explains how to turn its result into an FST, and for an FST written to an ordinary IndexOutput it shows 'fst = new FST<>(fstMetadata, dataInput, new OffHeapFSTStore());'. Copied into code on any release since 9.12.0 this does not compile: OffHeapFSTStore now needs (IndexInput, offset, metadata) and the 3-argument FST constructor no longer exists, because #13524 changed both and left this javadoc as it was. The working form is FST.fromFSTReader(fstMetadata, new OffHeapFSTStore(indexInput, offset, fstMetadata)), with a null check because compile() returns null for an FST that accepts nothing; Lucene's own codecs and tests already use it, so only the javadoc is wrong.",
   "impact_class": "minor",
   "introduced_commit": "126834c09e6 (#13524 'Reduce overhead for FSTs in FieldReader', by Armin Braun (original-brownbear), approved and merged by jpountz, author date 2024-06-27; branch_9x backport 82b3f8efd49, same author date): it deleted FSTStore and the FST(FSTMetadata, DataInput, FSTStore) constructor, replaced OffHeapFSTStore's implicit no-argument constructor with (IndexInput, long, FSTMetadata), moved every code caller to FST.fromFSTReader(md, new OffHeapFSTStore(in, offset, md)) (Test2BFSTOffHeap, FSTTermsReader, FSTDictionary, NRTSuggester, both FieldReaders), and did not touch FSTCompiler.java (no CHANGES or MIGRATE entry for the removal). The example itself comes from 63d4ba938fe (#12831 'Make FSTCompiler.compile() to only return the FSTMetadata', by Dzung Bui (dungba88), author date 2024-02-06; branch_9x f3e2929a52c; first released in 9.10.0), valid when written; the only later edit to the block is the markup change 378ca8d1bbf (#15573, 2026-01-15) [read]",
   "introduced_date": "2024-06-27 (126834c09e6, #13524, author date; PR merged 2024-06-27T07:52Z; the branch_9x backport 82b3f8efd49 has the same author date)",
   "first_affected_version": "9.12.0 [exec] (the first release after #13524); 10.0.0 [exec] is the first 10.x release and affected from the start",
   "affected_versions": "9.12.0-9.12.3, every 10.x release from 10.0.0 to 10.5.2, 10.6.0 (released 2026-10-29; branch_10_6 4ae946e5a9b) [exec] and main a9779ef3c193; not affected: 9.10.0-9.11.1 (the verbatim example compiles) and every release up to 9.9.2 (no such example: compile() still returned FST<T>). Not fixed upstream: main 645d4fe14a20, branch_11x, branch_10_6 and branch_10x still carry the stale line (2026-10-29). [exec] [read]. Caveat: all runs used JDK 25 on Linux aarch64.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-988.html",
   "repro": "repro/LFV-988/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-797",
   "priority": "low",
   "priority_rank": 1121,
   "novelty": "new",
   "withheld": false,
   "area": "facet / taxonomy (DirectoryTaxonomyReader.getBulkPath: side effect on the ordinals argument of the category-cache path added by #15711)",
   "title": "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)",
   "summary": "You pass an array of taxonomy ordinals to DirectoryTaxonomyReader.getBulkPath, whose inherited TaxonomyReader javadoc says the method 'may change (reorder elements) its parameter', so you expect the array to hold the same ordinals afterwards, perhaps in another order, as it does in 9.0.0 to 10.4.0. Since 10.5.0 (#15711, which made getBulkPath use the category cache) the method packs the uncached ordinals into the front of your array and sorts only that prefix, so a cached ordinal that comes before an uncached one is overwritten and another entry is duplicated. With ordinal 2 cached, getBulkPath(new int[] {3, 2, 1}) returns the right labels [c, b, a] but leaves the array as [1, 3, 1].",
   "impact_class": "minor",
   "introduced_commit": "9ece7fd321ab118773ac74ea4375690dbe3beca3 on main ('Update DirectoryTaxonomyReader.java to let getBulkPath use cache (#15711)', by shubhamsrkdev, fixes #15705, approved by epotyom and msokolov, merged 2026-03-27 by msokolov) and its branch_10x cherry-pick d3118e0abf4 (2026-03-31, first released in 10.5.0) [read]. The javadoc note it made inaccurate came from #12769 (fb5f491643b, epotyom, 2023-11-09; first in 9.9.0 and 10.0.0), written when the method only sorted the whole array in place (LUCENE-9476 / #179, 1036c708db7, 2021).",
   "introduced_date": "2026-03-27 (main 9ece7fd321a); 2026-03-31 (branch_10x d3118e0abf4)",
   "first_affected_version": "10.5.0 [exec] (10.4.0, the last release before #15711, is not affected [exec]; the API exists since 9.0.0)",
   "affected_versions": "10.5.0, 10.5.1, 10.5.2 and main a9779ef3c193 [exec]. Not affected [exec]: all 30 releases from 9.0.0 to 10.4.0, including 9.12.3 (latest 9.x), where the whole array is sorted in place, a permutation; getBulkPath does not exist before 9.0.0 (8.11.4 jar). No 9.x release has the change. Not fixed upstream: upstream main 20ced71c1e6e (2026-10-27), branch_10x and branch_10_6 still contain the compaction and the unchanged 'reorder elements' note [read], so 10.6.0 (4ae946e5a9b) is affected too [exec]. All runs on aarch64 Linux with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-797.html",
   "repro": "repro/LFV-797/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-907",
   "priority": "low",
   "priority_rank": 1122,
   "novelty": "new",
   "withheld": false,
   "area": "search / CachingCollectorManager lifecycle (documentation; new public API in 10.6.0)",
   "title": "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",
   "summary": "You wrap a reusable CollectorManager in a CachingCollectorManager, run a search with it, then run a second search with the same instance and call isCached() and replay(secondPassManager), the workflow the class javadoc shows for one search. Nothing in its javadoc says an instance serves only one search, unlike TopScoreDocCollectorManager and TopFieldCollectorManager, which say 'a new collectorManager should be created for each search due to its internal states', while Lucene's stated norm (TotalHitCountCollectorManager) is that managers are generally reusable. Instead the manager keeps the per-slice caches of every search in one list that is never cleared, so replay() returns the hits of both searches (the repro: [0..9] instead of the second search's [3..9]) and one earlier overflow makes isCached() false for every later search, with no error.",
   "impact_class": "minor",
   "introduced_commit": "3afffeef5a8d3bcbdcff9f2376e1c5a357764197 on main (squash merge of apache/lucene#16247 'Introduce CachingCollectorManager to parallelize search when using CachingCollector', by gaobinlong) and its backport d60e550b47f (branch_10x, contained in branch_10_6). The class, its never-cleared cachingCollectors list and its javadoc without a single-use note all come from that commit; the parent 6f3c1d7ad69 has no such file [read]. A new class, not a regression.",
   "introduced_date": "2026-07-08 (author date 2026-07-08T09:27:53Z on both commits; PR merged 2026-07-08T09:27:54Z; backport committed 2026-07-08T09:29:13Z)",
   "first_affected_version": "10.6.0 (released 2026-10-29; branch_10_6 head 4ae946e5a9b [exec]); no earlier release has the class (compile error on 9.12.3, 10.4.0, 10.5.0 and 10.5.2 [exec])",
   "affected_versions": "main a9779ef3c193 [exec] and the branch_10_6 head 4ae946e5a9b, the 10.6.0 release line [exec]; CachingCollectorManager.java is byte-identical at 3afffeef5a8d, d60e550b47f, 4ae946e5a9b and a9779ef3c193 [read]. The 10.6.0 RC artifacts themselves were not run (the branch_10_6 head build was). Not affected: every release up to and including 10.5.2, where the class does not exist [exec]; before 10.6 GroupingSearch wrapped a single CachingCollector used once, with no manager to reuse [read]. Not fixed upstream: the only commit to the file on main (head c5ab3e57b9ba) and on branch_10_6 (head 4ae946e5a9b9) is #16247, and no open PR touches it (checked 2026-10-28) [read]. All runs with JDK 25 on aarch64 Linux.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-907.html",
   "repro": "repro/LFV-907/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b, jars built at that revision): the repro fails with -ea and -da, and 3 of 3 for a second test; 10.5.2 does not have CachingCollectorManager."
  },
  {
   "id": "LFV-959",
   "priority": "low",
   "priority_rank": 1123,
   "novelty": "new",
   "withheld": false,
   "area": "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)",
   "title": "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)",
   "summary": "You upgrade from Lucene 10.6 to 11.0 and use doc-values updates (for example IndexWriter.updateNumericDocValue) with a default IndexWriterConfig; you expect the 11.0 release notes or the migration guide to say so if the default write path changed, as they do for the query cache, which 11.0 turns off by default. Instead main turns incremental doc-values updates on by default (DEFAULT_MAX_DOC_VALUES_OVERLAYS = 8, against 0 in 10.6), so a one-document update writes a small sparse overlay (402 bytes of update files in the repro) instead of rewriting the column (2892 bytes), yet the only CHANGES.txt entry for the feature is the 10.6.0 one, which says 'Opt-in; enable with IndexWriterConfig#setMaxDocValuesOverlays(n)', and MIGRATE.md says nothing. Main did carry an 'Enabled by default' note until it was moved into the 10.6.0 section and then, correctly for 10.6.0, reworded to the release candidate's text.",
   "impact_class": "minor",
   "introduced_commit": "ea248114ac4e3d3a303f3c945c99863d25065882 (main, 'Rename SegmentInfos.VERSION_11_0 to VERSION_10_6', git author Jim Ferenczi, a direct push with no PR): it moved the GITHUB#16418 entry, which then said 'Enabled by default; disable with IndexWriterConfig#setMaxDocValuesOverlays(0)', from the 11.0.0 section to 10.6.0, leaving 11.0.0 with no record (partial); completed by 7cecf795236cfdc40607536db27ae21b923a4366 (main, 'Ensure 10.6.0 changelog in main is consistent with branch_10_6', git author Houston Putman, a direct push), which rewrote that entry to the release candidate's 'Opt-in' text, correct for 10.6.0, and so removed the last 'Enabled by default' wording from main's notes. The default itself is deliberate: on since 75eddfaff22 (PR #16418, default 16), lowered to 8 by 92d9f2c7faa (PR #16648, 'The feature is not yet released, so no CHANGES entry is needed') [read]",
   "introduced_date": "2026-09-01 (author date of ea248114ac4, 2026-09-01T11:35:36+02:00); completed 2026-10-21 (author date of 7cecf795236, 2026-10-21)",
   "first_affected_version": "unreleased (main and branch_11x only; if nothing changes, 11.0.0 would be the first release to ship the default with no note). 10.6.0 (released 2026-10-29; branch_10_6 4ae946e5a9b) is opt-in and documented correctly [exec]; 10.5.2, 9.12.3 and earlier have no setMaxDocValuesOverlays [exec]",
   "affected_versions": "main from ea248114ac4 (2026-09-01) to 7cecf795236^: partial (11.0.0 section silent; the 'Enabled by default' text misfiled under 10.6.0) [exec]; main from 7cecf795236 (2026-10-21) through a9779ef3c193: complete [exec]; main 645d4fe14a2 (author date 2026-10-28) has the same default and the same notes [exec]; branch_11x da3ea39fa597 and upstream main f815e679bf6c (2026-11-01) have the same default and no 11.0 note [exec]. Not affected: main 75eddfaff22 to ea248114ac4^ (its 11.0.0 section said 'Enabled by default') [exec]; branch_10_6 4ae946e5a9b (10.6.0 RC1) and the 10.x backport 3a6cd003aaf (default 0, 'Opt-in', consistent) [exec]; 10.5.2 and 9.12.3 (API absent; the independent reproduction's version-portable byte test passes there, a 1-document update rewrites the whole column) [exec]. All runs on Linux aarch64 with JDK 25.0.3",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-959.html",
   "repro": "repro/LFV-959/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1030",
   "priority": "low",
   "priority_rank": 1124,
   "novelty": "new",
   "withheld": false,
   "area": "index / forceMerge and index upgrade (lucene/MIGRATE.md 11.0 'Relaxed Index Upgrade Policy': Scenario 1 and 'Upgrade Example')",
   "title": "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)",
   "summary": "Lucene main's MIGRATE.md tells users who open a Lucene 9.x or 10.x index to upgrade its segments by opening an IndexWriter and calling forceMerge(1), with the comment 'Rewrites all segments to latest format' (line 179), and line 153 offers forceMerge() as a way 'to upgrade segment formats immediately'. With the default merge policy, forceMerge(1) does nothing on an index that already has one segment and no deletions: TieredMergePolicy reports it as already merged, so on Lucene's own single-segment 9.0.0 test index the segment is still version 9.0.0 with codec Lucene90 afterwards. The code behaves as designed (forceMerge only promises a segment count, and UpgradeIndexMergePolicy and IndexUpgrader exist for exactly this case); the guide should wrap the merge policy in UpgradeIndexMergePolicy or point to IndexUpgrader.",
   "impact_class": "minor",
   "introduced_commit": "2d8f0cb5289b5b948a73449f06a992a16f44c8aa, apache/lucene#15012 'Relax Lucene Index Upgrade Policy to Allow Safe Upgrades Across Multiple Major Versions' (markrmiller; squash merge, author and commit date 2025-09-18; the text was first written on the PR's only branch commit ce08448cf5, author date 2025-07-31) [read]. At that commit the example named only 'an index created with Lucene 10.x', and the commit changed no merge code, so it was already wrong for single-segment 10.x indexes. 8476457b8752 (#16741, javanna, 2026-10-15) lowered MIN_SUPPORTED_MAJOR to 9 and widened the example's comment to '9.x or 10.x', which extends the defect to 9.x indexes (the case the minimal repro uses). 999c1a45b4f (#15650, 2026-02-01) only reformatted the markdown. Not a code regression: the forceMerge no-op is old and intended (LUCENE-3082 2011, LUCENE-5481 2014, the current TieredMergePolicy condition from LUCENE-7976 2018)",
   "introduced_date": "2025-09-18 (merged; written 2025-07-31 on the PR branch); widened to 9.x indexes on 2026-10-15",
   "first_affected_version": "unreleased (main and branch_11x only; would first ship in 11.0.0)",
   "affected_versions": "main from 2d8f0cb5289 (2025-09-18) through 645d4fe14a20 [exec]; upstream main f815e679bf6c and branch_11x da3ea39fa597 (2026-11-01) carry the same text, 14 lines lower [read]; the 9.x-index case of the repro only from 8476457b8752 (#16741, 2026-10-15), before which main did not open 9.x-created indexes at all [read]. Not affected: every release, branch_10x (657014b3c57), branch_10_6 (4ae946e5a9b, 10.6.0 RC1) and branch_10_5 [read]. The forceMerge behaviour underneath is the same in 9.12.3, 10.0.0, 10.3.0, 10.3.1 and 10.5.2 [exec], but those releases make no such claim, so they are not affected; all runs used JDK 25 on Linux aarch64, which does not matter for this merge-selection logic",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1030.html",
   "repro": "repro/LFV-1030/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-945",
   "priority": "low",
   "priority_rank": 1125,
   "novelty": "new",
   "withheld": false,
   "area": "search / query cache (LRUQueryCache method javadocs and MIGRATE.md)",
   "title": "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)",
   "summary": "On main you install an LRUQueryCache, run a query so that it is cached, and call clearQuery(query) or clearCoreCacheKey(key), whose javadocs say 'Remove all cache entries for the given query' and '... for the given core cache key'. You expect the entries to be gone when the call returns, as on 10.x; instead #15558 made both methods only add the query or key to a pending set, so getCacheSize() still counts the entry and the next search is a cache hit (with correct documents) until cleanUp() runs. The deferral is deliberate and the class javadoc describes it, but the two method javadocs were left unchanged, and MIGRATE.md, whose 11.0 recipe builds a cache with no cleanup, never mentions the new cleanUp() or CacheCleanUpParameters duty.",
   "impact_class": "minor",
   "introduced_commit": "d50fb36d9af3 (GITHUB#15558 'Refactor QueryCache to improve performance', by sgup432, merged by msfroh; design issue #14222) [exec]. That commit made removal deferred and documented it in the class and 6-arg constructor javadocs, but left the method javadocs, whose text dates from LUCENE-6077 (86a6c37b473, 2014, clearCoreCacheKey) and LUCENE-6303 (e4d88cab5ca, 2015, clearQuery) and was last reformatted by 2d6ad2fee6df (2020) [read]. The MIGRATE.md #15558 section came later from #16756 (120b3bc18da, by javanna, 2026-10-07) and covers only the CacheKey signature and the callbacks; the 11.0 recipe with the 2-arg constructor is from #14187 (26387b4b00e, 2025-04-02) [read]",
   "introduced_date": "2026-04-14 (author date of d50fb36d9af, 2026-04-14T18:55:32+02:00; merged 16:55:32Z); MIGRATE.md section 2026-10-07 (#16756)",
   "first_affected_version": "unreleased (main / 11.0.0-SNAPSHOT only; #15558 was not backported to 10.x, so 10.6.0 (released 2026-10-29; branch_10_6 head 4ae946e5a9b) is unaffected [exec])",
   "affected_versions": "main from d50fb36d9af on [exec]; upstream main 645d4fe14a20 (2026-10-28) still has the same LRUQueryCache.java and MIGRATE.md text [read]. Not affected: branch_10_6 head 4ae946e5a9b (10.6.0 RC), 10.5.2, 10.0.0 and 9.12.3 [exec]; branch_10x [read]; 5.1.0-8.x [read]. All runs JDK 25.0.3 on Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-945.html",
   "repro": "repro/LFV-945/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1000",
   "priority": "low",
   "priority_rank": 1126,
   "novelty": "new",
   "withheld": false,
   "area": "search / query cache (LRUQueryCache callback javadoc and MIGRATE.md)",
   "title": "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)",
   "summary": "You subclass LRUQueryCache to keep per-index statistics in its callbacks, as the class javadoc suggests, and trust its sentence that the callbacks 'are called synchronously and under a lock', which on 10.x meant one cache-wide write lock around every insertion, eviction and clear callback, so plain fields were safe. On main, #15558 gave each partition (16 by default) its own lock, so insertion and eviction callbacks of different partitions run at the same time (2 at once in a deterministic JUnit, up to 3 in a stress where a plain counter loses updates), and clear() calls onClear() with no lock held. The partitioning itself is intended.",
   "impact_class": "minor",
   "introduced_commit": "d50fb36d9af3 (GITHUB#15558 'Refactor QueryCache to improve performance', by Sagar Upadhyaya (sgup432), merged by Michael Froh (msfroh); design issue #14222; the per-partition locks, the unlocked onClear() and the unchanged sentence are already in the PR's first partitioning commit ef7cf0ff101e, authored 2026-01-08, and d81d3815c4e8 (2026-04-13) rewrote the callback paragraph and kept the sentence) [exec]. The sentence itself dates from LUCENE-6157 (d7e0fd28dd9, Adrien Grand, 2015-01-05, then LRUFilterCache) and was only re-wrapped by 2d6ad2fee6d (LUCENE-9570, 2020) [read]. The MIGRATE.md #15558 section came later, from #16756 (120b3bc18dac, javanna, 2026-10-07), without a concurrency note [read]",
   "introduced_date": "2026-04-14 (squash commit d50fb36d9af3, author and commit date; PR opened 2026-01-09); MIGRATE.md section 2026-10-07 (#16756)",
   "first_affected_version": "unreleased (main / 11.0.0-SNAPSHOT since 2026-04-14, and branch_11x; #15558 was deliberately not backported, so every release with the class, 5.0.0 (LRUFilterCache) to 10.5.2, and 10.6.0 (released 2026-10-29; branch_10_6 4ae946e5a9b) are unaffected [exec])",
   "affected_versions": "main from d50fb36d9af3 (2026-04-14) to a9779ef3c193 [exec]; branch_11x [read]; upstream main 645d4fe14a20 (2026-10-28) [read]. Not affected [exec]: 9.10.0, 9.12.3, 10.5.2, the 10.6 RC branch_10_6 4ae946e5a9b9 (core jar only) and main's parent commit 55b4574a20d2 (history test program: one callback at a time); the 10.x-compatible JUnit passes on 10.5.2 and branch_10_6 (finder), the independent reproduction's JUnit on 10.5.2 (-ea and -da) and 9.12.3 (-ea), the intended-behaviour check's run on 10.5.2. [read] Every release tag with the class keeps all insertion, eviction and clear callbacks under one lock. Older and separate: onHit/onMiss run under the shared read lock since 9.11.0 (#13306), so those two could already overlap on 9.11-10.x; only the insertion/eviction/clear overlap is new on main. All runs JDK 25.0.3 on Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1000.html",
   "repro": "repro/LFV-1000/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-890",
   "priority": "low",
   "priority_rank": 1127,
   "novelty": "new",
   "withheld": false,
   "area": "index / deletion policies (SnapshotDeletionPolicy and PersistentSnapshotDeletionPolicy restart lifecycle, javadoc)",
   "title": "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)",
   "summary": "You restart an application that uses PersistentSnapshotDeletionPolicy, create the policy again over its save file with OpenMode.APPEND (whose javadoc says this opens the existing snapshots, 'initializing the class with the snapshots information'), and ask it which commits are snapshotted before you open an IndexWriter with it. You expect getSnapshots() and getIndexCommit(gen) to show the persisted snapshot that getSnapshotCount() counts, or the javadoc to say that the policy must first be passed to an IndexWriter. Instead getSnapshotCount() is 1 while getSnapshots() is empty and getIndexCommit(gen) returns null, which its javadoc says means 'not currently snapshotted'; this is by design (the IndexCommit objects come from the writer's onInit call), but no javadoc states the precondition.",
   "impact_class": "minor",
   "introduced_commit": "30e43c836ab10a4745e60ce8a2d18b4d58a210da (trunk; branch_4x backport 2d33a3bf9ef4): LUCENE-4973 'Persistent/SnapshotDeletionPolicy no longer require a unique id' (migrated as apache/lucene#6037; SVN-era patch by mikemccand, no PR). It replaced the id-based state with refCounts (generation -> count, loaded by the PersistentSnapshotDeletionPolicy constructor) and indexCommits (generation -> IndexCommit, filled only in SnapshotDeletionPolicy.onInit) and added getSnapshotCount() and getIndexCommit(long). The next day efeaac746ae (trunk; branch_4x c82d9836349), LUCENE-4976 'use single file to hold PersistentSnapshotDeletionPolicy state on disk' (#6040), added List<IndexCommit> getSnapshots() (empty before onInit) and the initCalled guard on snapshot()/releaseGen(). Both reached 4.4.0; no bisection inside 4.4.0 is possible. Later edits are cosmetic (3b67b174932 diamond, 2014; 2d6ad2fee6d reformat, 2020) [read]",
   "introduced_date": "2013-05-02 (30e43c836ab, LUCENE-4973) and 2013-05-03 (efeaac746ae, LUCENE-4976); both first released in 4.4.0 (tagged 2013-07-22)",
   "first_affected_version": "4.4.0 [exec] (the first release with the generation-based API; the follow-up's version probe fails there). 4.3.1 is the last unaffected release [exec]: getSnapshotCount(), getIndexCommit(long), List<IndexCommit> getSnapshots() and release(long) did not exist (the probe does not compile), and the id-based getSnapshots() of 3.1-4.3.1 listed the persisted snapshot before attachment (executed on 3.1.0, 4.0.0 and 4.3.1), although getSnapshot(id) already returned null before attachment",
   "affected_versions": "Every release from 4.4.0 through 10.6.0 and main a9779ef3c193. [exec] the follow-up's version probe (getSnapshotCount()=1, getSnapshots().size()=0, getIndexCommit(gen)=null before attachment; all three agree after a writer has opened) fails on 4.4.0, 4.5.0, 4.10.4, 5.0.0, 5.5.5, 6.6.6, 7.7.3, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main; the finder's JUnit fails 2 of 2 on main (-ea and -da), branch_10_6 4ae946e5a9b (10.6.0, released 2026-10-29), 10.5.2, 9.12.3 and with open PR #16482's two files shadowed; the independent reproduction's JUnit fails 4 of 6 on main (-ea and -da, two seeds), 10.5.2 and 9.12.3, and its framework-free main() on main (-ea and -da), 10.5.2, 9.12.3 and 8.11.4. In 4.4.0 only, IndexWriter still cloned its config, so even the instance the caller passed in stayed in this state after the writer opened; since 4.5.0 the passed instance is the writer's [exec]. [read] the code paths are unchanged since 2013 apart from cosmetic edits. Not fixed upstream: the newest commits on the two files are #14913 (PersistentSnapshotDeletionPolicy, author date 2025-07-14) and 2d6ad2fee6df (SnapshotDeletionPolicy, 2020-12-23), and open PR #16482 leaves onInit, the getters and their javadoc unchanged [read]. All runs on aarch64 with JDK 25.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-890.html",
   "repro": "repro/LFV-890/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-1008",
   "priority": "low",
   "priority_rank": 1128,
   "novelty": "new",
   "withheld": false,
   "area": "search / query cache (LRUQueryCache unified callback javadoc and MIGRATE.md)",
   "title": "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)",
   "summary": "You subclass LRUQueryCache to keep per-index RAM statistics in onCacheEntryInserted/onCacheEntryEvicted, whose javadoc says ramBytesUsed is 'the total RAM cost of this entry' (and of the evicted entry), so you expect each entry to give back at eviction what it added at insertion and an index's total to return to 0 once its entries are gone. Since #16657 the cache deliberately counts a query's own RAM once per distinct query and reports it only with the query's first inserted entry and with the entry that drops its last reference, usually entries of different segments or indices: in a two-segment index one entry is inserted with 344 bytes and evicted with 160, and with two indices sharing one cache index A keeps +184 bytes after it is closed while index B ends at -184. The dedup and the cache's own accounting are correct.",
   "impact_class": "minor",
   "introduced_commit": "fadd63e0eb4e (GITHUB#16657 'Fix LRUQueryCache hashCode/equals contract and account query RAM once per distinct query', by Sagar Upadhyaya (sgup432), approved and merged by Michael Froh (msfroh); putIfAbsent adds the query bytes only on the first reference and releaseQuery/remove return them only on the last, and the callback javadoc was left unchanged) [exec]. The 'total RAM cost of this entry' javadoc and the class-javadoc recommendation of the unified callbacks come from d50fb36d9af3 (GITHUB#15558, sgup432, 2026-04-14), when they matched the code (all five LRUQueryCache.java versions from d50fb36d9af3 to 1adb280101d9 pass the repro when shadowed) [exec]; the MIGRATE.md recommendation 'Prefer onCacheEntryInserted / onCacheEntryEvicted' came later from 120b3bc18dac (GITHUB#16756, javanna, 2026-10-07), without a note on the attribution [read]",
   "introduced_date": "2026-09-29 (fadd63e0eb4e, author and commit date 2026-09-29T20:56:09Z; PR opened 2026-09-10); callback javadoc 2026-04-14 (#15558); MIGRATE.md recommendation 2026-10-07 (#16756)",
   "first_affected_version": "unreleased (11.0.0: main since fadd63e0eb4e, 2026-09-29, and branch_11x; no release has the unified callbacks: every release up to 10.5.2, 10.6.0 (released 2026-10-29; branch_10_6 4ae946e5a9b) and branch_10x lack onCacheEntryInserted/onCacheEntryEvicted [exec])",
   "affected_versions": "main from fadd63e0eb4e (2026-09-29) to 645d4fe14a20 [exec]; branch_11x [read]; upstream main [read]. Not affected [exec]: the parent 1adb280101d9 and the four earlier LRUQueryCache.java versions back to d50fb36d9af3 (#16178, #16081, #15965, #15558), each shadowed over the 645d4fe14a20 build (3 of 3 pass). Not applicable: 10.5.2 and 9.12.3 [exec], the 10.6 RC branch_10_6 4ae946e5a9b [exec], branch_10x and every release tag [read]. On main the deprecated per-core pair onDocIdSetCache/onDocIdSetEviction still balances per core [exec]. All runs JDK 25.0.3 on Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1008.html",
   "repro": "repro/LFV-1008/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-931",
   "priority": "low",
   "priority_rank": 1129,
   "novelty": "new",
   "withheld": false,
   "area": "analysis-common, analysis-kuromoji, analysis-phonetic, analysis-opennlp / analysis factories (class javadoc <fieldType> schema examples)",
   "title": "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)",
   "summary": "You copy the <fieldType> example from the class javadoc of one of eight analysis factories (StopFilterFactory, for example) into a schema and expect well-formed XML whose elements name registered factories, as the other factory examples do (141 of the 149 example blocks are well-formed; 328 of the 332 elements name a registered factory). Instead six snippets are not well-formed XML (a class attribute with no closing quote after the class name, start tags with no '>' or '/>', a stray '/>' line, and '<-- other filters -->' instead of an XML comment), and two name a class that is not a factory: LimitTokenOffsetFilterFactory's example says solr.LimitTokenOffsetFilter (the filter, not its factory) and PatternTypingFilterFactory's own element says com.example.PatternTypingFilter. The PatternTyping example also lists solr.TokenAnalyzerFilter, a companion filter from a Solr patch that was never committed (a stale reference, not a typo), and its first javadoc sentence describes that companion filter rather than PatternTypingFilter.",
   "impact_class": "minor",
   "introduced_commit": "No single commit: eight independent hand-written examples, seven wrong from the commit that first wrote them and one (StopFilterFactory) broken by a later edit [read]. Per row: BeiderMorseFilterFactory f3869ef3ce4 (SOLR-2982, rmuir, then a Solr class; moved into Lucene by LUCENE-2510/LUCENE-4044); JapaneseIterationMarkCharFilterFactory a15331043f9 (LUCENE-4201 = #5273, Christian Moen); StopFilterFactory fa76c301470 (LUCENE-4963 = #6027, jpountz: removing the deprecated enablePositionIncrements attribute also dropped the '/>' that closed the tag; LUCENE-5211 499bd3688a3 later appended format=\"wordset\" to the still-open tag); LimitTokenOffsetFilterFactory af6fe4d1741 (LUCENE-6423 = #7482, dsmiley); OpenNLPTokenizerFactory and OpenNLPLemmatizerFilterFactory 3e2f9e62d77 (LUCENE-2899 = #3973, sarowe); DropIfFlaggedFilterFactory ab5671d367e (LUCENE-9574 = #10614, PR apache/lucene-solr#1979, gus-asf); PatternTypingFilterFactory c087f6f8c0a (LUCENE-9575 = #10615, PR apache/lucene-solr#1995, gus-asf).",
   "introduced_date": "2011-12-28 (oldest row, BeiderMorse, as Solr code) to 2021-01-23 (newest row, PatternTyping); per row (author dates): BeiderMorse 2011-12-28, JapaneseIterationMark 2012-07-10, Stop 2013-05-04, LimitTokenOffset 2015-04-22, both OpenNLP 2017-12-15, DropIfFlagged 2020-10-14, PatternTyping 2021-01-23",
   "first_affected_version": "4.0.0-BETA [exec] (JapaneseIterationMarkCharFilterFactory and BeiderMorseFilterFactory; first GA 4.0.0; 4.0.0-ALPHA has no Lucene analysis factories at all). Per row: StopFilterFactory 5.0.0 (all 24 releases 4.0.0-BETA..4.10.4 are well-formed), LimitTokenOffsetFilterFactory 5.2.0, both OpenNLP factories 7.3.0, PatternTypingFilterFactory and DropIfFlaggedFilterFactory 8.9.0 (8.x backports apache/lucene-solr#2493 and #2483); all eight together from 8.9.0 [exec]",
   "affected_versions": "Every release from 4.0.0-BETA through 10.6.0 (132 releases) has at least two of the broken examples and every release from 8.9.0 on has all eight (8.9.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.6.0), and so do branch_10x head 1309534296e and main a9779ef3c193. [exec] with the follow-up history probe, which reads the example text from each release's SHA-1-checked sources jar and resolves class names against that release's jars: 4.0.0-BETA, 4.0.0, 4.10.4, 5.0.0, 5.1.0, 5.2.0, 7.2.1, 7.3.0, 8.8.2, 8.9.0, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main (-ea and -da), and 10.6.0 (2026-11-01, -da); 4.0.0-ALPHA is not affected (no API). [read] all 140 release tags checked (131 in the history clone, 3.1 to 10.5.2, plus 8.8.2-8.11.4 from the lucene-solr repository) and both branch heads. The finder's JUnit fails 9 of 10 on main, 10.5.2 and 9.12.3, but it hard-codes the snippets, so on release jars it re-tests only the two class-name rows; the release dating rests on the history probe. Not fixed: upstream main 645d4fe14a20 (2026-10-28) has not touched the eight files since a9779ef3c193 [read].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-931.html",
   "repro": "repro/LFV-931/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-122",
   "priority": "low",
   "priority_rank": 1130,
   "novelty": "new",
   "withheld": false,
   "area": "search / sorting (SortedNumericSortField missing values; javadoc)",
   "title": "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",
   "summary": "You follow the SortedNumericSortField class javadoc on main ('Like sorting by string, this also supports sorting missing values as first or last, via SortField#STRING_FIRST or SortField#STRING_LAST') and build new SortedNumericSortField(\"f\", SortField.Type.LONG, false, SortedNumericSelector.Type.MIN, SortField.STRING_LAST). You expect documents without a value to sort last, or, if the sentinels are not supported, the constructor to reject them. Instead the constructor accepts the sentinel, and IndexSearcher.search with that sort, or IndexWriterConfig.setIndexSort with it, throws ClassCastException 'SortField$2 cannot be cast to class java.lang.Long', because a numeric sort needs a missing value of its own numeric type (for example Long.MAX_VALUE to sort missing documents last), as MIGRATE.md and the upstream tests show.",
   "impact_class": "minor",
   "introduced_commit": "f4f6d70c0c4 (apache/lucene#15486 'Remove deprecated SortField.setMissingValue method', by romseygeek, main only, no backport) [read]; the sentence itself dates from LUCENE-5748 (2014-06-12): 398af4596bd on trunk, first released in 6.0.0, and its branch_4x counterpart d1522d5fe78, first released in 4.9.0, where it pointed to setMissingValue(Object) and was accurate as a pointer",
   "introduced_date": "2025-12-09 (f4f6d70c0c4 merged to main)",
   "first_affected_version": "unreleased (main only, 11.0.0-SNAPSHOT; no release tag contains f4f6d70c0c4, so it would first ship in 11.0.0 unless fixed)",
   "affected_versions": "main from f4f6d70c0c4 (2025-12-09) through 645d4fe14a2 [exec]; not affected, because the javadoc says 'via setMissingValue(Object)': every release through 10.5.2 [read] and branch_10_6 (10.6.0, released 2026-10-29) and the unreleased branch_10x [read]; the underlying accept-then-ClassCastException behaviour for a wrong-typed missing value is older and is not part of this claim [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-122.html",
   "repro": "repro/LFV-122/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-948",
   "priority": "low",
   "priority_rank": 1131,
   "novelty": "new",
   "withheld": false,
   "area": "release notes / lucene/CHANGES.txt 10.6.0 New Features (GITHUB#16243 entry) x search / similarities (StableTflSimilarity)",
   "title": "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)",
   "summary": "You read the Lucene 10.6.0 release notes, whose GITHUB#16243 entry says StableTflSimilarity 'also supports k3 query-term frequency saturation', and write new StableTflSimilarity(1.2f, 0.917f, 7f) against the 10.6.0 jar. You expect it to compile, as it does on main; instead javac finds no (float, float, float) constructor and no getK3(), because the 10.x backport (#16322) deliberately left k3 out ('remove k3 which isn't in 10') and, on the feature author's review request, also dropped the k3 sentence, which a later, unrelated backport commit (3a75616c943, the #16300 backport) put back. The sentence ships in the RC1 source release's CHANGES.txt and Changes.html and is also in main's copy of the 10.6.0 section.",
   "impact_class": "minor",
   "introduced_commit": "3a75616c9437 (branch_10x, 'Backport changes to TestTermInSetQuery. #16300', by dweiss; a direct push with no PR of its own): its CHANGES hunk adds the #16300 entry and also rewrites the second line of the #16243 entry back to main's wording, re-adding the k3 sentence that the 10.x backport 8e40c912555 (#16322, by mccullocht, 2026-07-01) had removed on review request; branch_10_6 inherited it at its fork point 3e416dce059 (2026-10-14) [exec]. Main's copy of the 10.6.0 section has carried the sentence since the feature commit e3a7a733c8a (#16243, by txwei, 2026-07-01), where it is true of main's class; it became wrong for 10.6.0 when #16322 left k3 out of 10.x, and the release manager's clean-ups f79709fd57e (branch_10_6, 2026-10-20) and 7cecf795236 (main, 2026-10-21) left it in place [read]",
   "introduced_date": "2026-07-08 (author and commit date of 3a75616c943, 2026-07-08T18:54:34+02:00); wording origin on main e3a7a733c8a, 2026-07-01; branch_10_6 cut from branch_10x 2026-10-14",
   "first_affected_version": "10.6.0 (released 2026-10-29 from RC1, built from branch_10_6 4ae946e5a9b; tag releases/lucene/10.6.0). StableTflSimilarity and the GITHUB#16243 entry do not exist in 9.x or 10.0.0-10.5.2 [exec]",
   "affected_versions": "10.6.0 RC1 [exec]; branch_10x from 3a75616c943 to its head [exec]; main's copy of the 10.6.0 section [exec], text only on main, whose class does have k3 (the code-level JUnits pass 2 of 2 on main). Not affected: 9.x and 10.0.0-10.5.2 (class absent; exec on 9.12.3, 10.5.0 and 10.5.2) and branch_10x between 8e40c912555 and d60e550b47f [exec]. All runs JDK 25.0.3 on Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-948.html",
   "repro": "repro/LFV-948/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 artifacts (4ae946e5a9b): CHANGES.txt advertises a k3 parameter that the lucene-core jar does not have (2 of 2 fail with -ea and -da); 10.5.2 has neither StableTflSimilarity nor the entry."
  },
  {
   "id": "LFV-537",
   "priority": "low",
   "priority_rank": 1132,
   "novelty": "new",
   "withheld": false,
   "area": "suggest / spell (JaroWinklerDistance threshold)",
   "title": "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",
   "summary": "You want the plain Jaro similarity from JaroWinklerDistance, so, as the setThreshold javadoc says ('Set to a negative value to get the Jaro distance'), you call setThreshold(-1) and expect getDistance(\"martha\", \"marhta\") to return the Jaro value 0.9444. Instead it returns 0.9611, the Jaro-Winkler value: getDistance skips the Winkler bonus only when the Jaro value is below the threshold, which never happens for a negative threshold, so every pair gets the bonus, exactly as with threshold 0. Only a threshold of 1 or more gives plain Jaro; the sentence has been false since the class was added in 2008, so the javadoc is the side to fix by default.",
   "impact_class": "minor",
   "introduced_commit": "ce19aa28c01060dafae0b60b8005a22972c7ef94 (svn r669085, lucene/java/trunk; LUCENE-1297 'Allow other string distance measures in spellchecker', migrated as apache/lucene#2374; pre-GitHub, so no PR), which added JaroWinklerDistance together with the setThreshold sentence and the condition 'jw = j < getThreshold() ? j : j + bonus' [read]. The sentence was never true; never a regression.",
   "introduced_date": "2008-06-18",
   "first_affected_version": "2.4.0 (2008-10-06) [exec]",
   "affected_versions": "every release from 2.4.0 through 10.5.2 (151 releases), 10.6.0 [exec] and main ea57360912ed; upstream main and branch_10x unchanged on 2026-10-26 [exec]. Not affected: 2.3.2 and earlier, which have no JaroWinklerDistance [exec]. Not fixed upstream. All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-537.html",
   "repro": "repro/LFV-537/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-156",
   "priority": "low",
   "priority_rank": 1133,
   "novelty": "new",
   "withheld": false,
   "area": "index / ImpactsEnum shallow-advance contract (ImpactsSource javadoc, test-framework AssertingImpactsEnum); codecs / Lucene104 postings reader",
   "title": "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)",
   "summary": "You take an ImpactsEnum from TermsEnum#impacts, stand on a document, call advanceShallow(target) with a target in a later 256-doc block to peek at upcoming impacts, and then read the current document's freq(), positions or docIDRunEnd(); the javadoc forbids only nextDoc() and too-small advance() targets afterwards and says docID() does not change, so you expect the current document's own data and a working advance(target). Instead the default codec has already moved its streams to the target block on purpose: on main the positions of doc 0 read as [5] instead of [0], docIDRunEnd() claims docs 0 to 3327 all match although only every third does, and after freq() the legal advance(3000) returns doc 3005, which does not contain the term. Lucene's own callers always advance before reading, so the codec behaviour is intended; what is missing is this precondition in the ImpactsSource javadoc and a check for it in the test framework's AssertingImpactsEnum.",
   "impact_class": "minor",
   "introduced_commit": "f410df81136 (LUCENE-4198 'Give codecs the opportunity to index impacts', migrated as apache/lucene#5270, by jpountz; JIRA patch era, no PR): it added ImpactsEnum#advanceShallow, and its first impacts enum (Lucene50PostingsReader.BlockImpactsEverythingEnum) already repositioned the positions and doc streams on a shallow advance while docID() stayed; the contract text in force today is af680af77f3 (LUCENE-8142, #9190, 2018-05-02), moved unchanged to ImpactsSource by 0a1de2c4a57 (LUCENE-8312, 2018-05-25), and it never named the per-document methods [read]. Later commits changed which reads go wrong: 5974586b87f (LUCENE-8901, apache/lucene-solr#595) wrong freq() values (8.2.0-9.11.1); #13585 'Inline skip data into postings lists' (b4a8810b7ae, backport 59b7c28eb47) freq() correct but breaking the next advance() (9.12.0 on); #14390 (db00348ef18, backport 6bef45756a9) docIDRunEnd() on postings (10.2.0 on) [exec]",
   "introduced_date": "2018-01-31 (f410df81136); contract text 2018-05-02 (af680af77f3); symptom changes 2019-07-02 (LUCENE-8901), 2024-07-31 (#13585) and 2025-03-24 (#14390)",
   "first_affected_version": "8.0.0 [exec]; by symptom: wrong positions from 8.0.0, wrong freq() value 8.2.0-9.11.1, freq() then advance() corruption from 9.12.0, wrong docIDRunEnd() from 10.2.0 (the method first appeared there) [exec]",
   "affected_versions": "every release from 8.0.0 to 10.6.0 and main ea57360912ed (10.6.0 [exec]: the minimal test fails on the release jars with -ea and -da, advance(256) = 261). [exec] the follow-up's history probes and the independent reproduction's JUnit fail on 8.0.0, 8.1.1, 8.2.0, 8.11.4, 9.0.0, 9.8.0, 9.9.0, 9.11.1, 9.12.0, 9.12.3, 10.0.0, 10.1.0, 10.2.0, 10.3.2, 10.4.0, 10.5.2 and main (identical values with -ea and -da wherever both ran: 8.0.0, 8.11.4, 9.11.1, 9.12.3, 10.5.2, main); the finder's repro also fails on 9.11.1, 9.12.3, 10.0.0, 10.1.0 and 10.5.2, and its docIDRunEnd test on 10.2.0, 10.3.2 and 10.5.2; [read] the other 8.x-10.x releases (same javadoc text, same deferred-refill design). Not affected: 7.7.3 and earlier (no ImpactsEnum; 7.3.0-7.7.3 by git ls-tree, 7.7.3 by execution). Upstream main and branch_10x (1309534296e3) still carry the javadoc unchanged [read]. Not executed: offsets and payloads after a far shallow advance, x86, JDKs other than 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-156.html",
   "repro": "repro/LFV-156/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-149",
   "priority": "low",
   "priority_rank": 1134,
   "novelty": "known",
   "withheld": false,
   "area": "search / kNN visit limit (visitedLimit javadoc on LeafReader, TopKnnCollector and the kNN collector managers; HNSW and exhaustive vector search)",
   "title": "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)",
   "summary": "You call LeafReader#searchNearestVectors (or KnnVectorsReader#search with a TopKnnCollector) with visitedLimit L and expect what the javadoc says: L is 'the maximum number of nodes that the search is allowed to visit', so at most L vectors are scored. On 10.4.0 and later the search can score more: in the repro, a 50-vector default-codec segment with L = 1 scores all 50 vectors, an HNSW segment with L = 8 scores 20, and a Seeded search with 100 seeds and L = 2 scores 100, because vectors and entry points are scored in batches and counted only afterwards. Upstream made the limit best effort on purpose (#15057, #15075, #15500) and no wrong hits come back; only the public javadoc was never updated.",
   "impact_class": "minor",
   "introduced_commit": "71d4ad6780e (apache/lucene#14978 'Add a bulk scoring interface to RandomVectorScorer', by mccullocht, merged on main 2025-07-31; cac1a31b6a3 on the 10.3 line) starts the current, continuous mismatch: the exhaustive branch of Lucene99HnswVectorsReader still checks earlyTerminated() before each vector but counts visits only once per 64-ordinal batch, so the check cannot fire inside a batch [exec]; 8c1461e536d (apache/lucene#15500, benwtrent, merged 2025-12-15) widened it by bulk-scoring each upper-level neighbour list of the HNSW entry descent and every seed before counting them [exec]; the javadoc wording itself comes from 8ca372573db (apache/lucene#656, LUCENE-10382, 2022-02-17) and matched the released code in 9.1.0-9.7.0 [exec]; older, narrower mismatches: 861153020a1 (#12413, 9.8.0: visitedLimit = 0 on a multi-level graph visits 1 node), 05a336ea69e (#12806, 9.9.0: a large-k exhaustive branch with no limit check, closed again by df154cdc228 / #13202 in 9.11.0) and 8856a5f4eb7 (#14078, 10.2.0: the flat Lucene102BinaryQuantizedVectorsFormat ignores the limit) [exec]; the stale wording was copied onto new APIs after batching by b6e57da01a5 (#15063) and bfe5c847d3c (#16383, the fp16 overload, main only) [read]",
   "introduced_date": "2025-07-31 (#14978 merged; first release 10.3.0); 2025-12-15 (#15500 merged; first release 10.4.0); the javadoc wording dates from 2022-02-17 (#656)",
   "first_affected_version": "10.3.0 [exec] for the current, continuous mismatch with the default codec (exhaustive path when k >= the number of vectors in a segment: limit 1 -> 50 visits); 10.4.0 [exec] for small default-codec segments without a graph (#14963), the HNSW entry phase and Seeded searches (#15500); earlier, narrower mismatches: 9.8.0 [exec] (visitedLimit = 0 on a multi-level graph -> 1 visit), 9.9.0-9.10.0 [exec] (large-k exhaustive path, honoured again from 9.11.0), and the non-default flat Lucene102BinaryQuantizedVectorsFormat from 10.2.0 [read]",
   "affected_versions": "executed with an era variant of the repro (default codec, one segment, seed DEADBEEF, -ea unless marked) on Maven Central release jars and main: main ea57360912ed, 10.5.2 and 10.4.0 exceed the limit on every path tested (6 of 6 fail; main and 10.5.2 also with -da); 10.3.0 and 10.3.2 on the large-k exhaustive path, the flat binary-quantized format and visitedLimit = 0 (3 of 6); 10.2.2 on the flat binary-quantized format and visitedLimit = 0 only (2 of 6); 9.11.0 and 9.12.3 on visitedLimit = 0 only (1 of 4); 9.9.0 and 9.10.0 on the large-k path and visitedLimit = 0 (2 of 4); 9.8.0 on visitedLimit = 0 only (1 of 4); 9.7.0 consistent with the javadoc (0 of 4); 9.1.0 never exceeds the limit, but its graph searches throw 'The heap is empty' (LUCENE-10611, fixed in 9.3.0, not this defect); 9.0.0 has no visitedLimit parameter [exec]; commit-level builds bracket #14978 (96f862dfb81 vs 71d4ad6780e) and #15500 (367551036dd vs 8c1461e536d) [exec]; the finder repro fails 5 of 5 on main, 10.5.2, 10.4.0 and 8c1461e536d, 4 of 5 on 367551036dd, and does not compile on 10.3.2 [exec]; not executed: 9.2.x-9.6.x, 9.9.1-9.9.2, 9.11.1-9.12.2, 10.0.0-10.2.1, 10.3.1, 10.5.0 and 10.5.1 (inferred from the executed neighbours and commit containment) [read]; upstream main still carries the wording (head 645d4fe14a2, re-run 2026-10-29: finder 5 of 5 and the independent reproduction 4 of 4 fail with -ea and -da) [exec]; 10.6.0 (released 2026-10-29; branch_10_6 RC1 4ae946e5a9b) [exec] and branch_10x 657014b3c579 [read]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/15057",
    "https://github.com/apache/lucene/issues/14978",
    "https://github.com/apache/lucene/issues/15075",
    "https://github.com/apache/lucene/issues/15500",
    "https://github.com/apache/lucene/issues/14078",
    "https://github.com/apache/lucene/issues/15169"
   ],
   "doc": "",
   "repro": "repro/LFV-149/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-119",
   "priority": "low",
   "priority_rank": 1135,
   "novelty": "known",
   "withheld": false,
   "area": "index / SegmentInfos version check (javadoc)",
   "title": "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)",
   "summary": "You call SegmentInfos.readLatestCommit(dir, m) or readCommit(dir, file, m) and expect what their javadocs say: an IndexFormatTooOldException unless the commit's created major (readLatestCommit) or each segment's minVersion (readCommit) is strictly greater than m. Instead the code (SegmentInfos.java:529) rejects only a segment whose minVersion major is below m and ignores the created major, so a commit at exactly m loads, and readLatestCommit also loads a commit created at m-1 whose segments are all at m. The code is the intended behaviour (CHANGES GITHUB#14607 / GITHUB#15431, 'ignores indexCreatedVersionMajor'); the javadoc text is wrong.",
   "impact_class": "minor",
   "introduced_commit": "layered doc defect [read]: (1) 3813f5ab7c78 on main (branch_9x 1b349317f687), PR #12229, made readLatestCommit(Directory,int) public and wrote its 'created major ... strictly greater' javadoc while the code already accepted equality (gate 'indexCreatedVersion < minSupportedMajorVersion'; the same commit's test reads created-8 indexes with m = 8); 9.5.0 and 9.6.0 behave identically [exec], only the text changed; (2) a6f9bded8537 on main (c443cc9e1c39 for 9.12, c8018b220d17 on branch_10x), PR #14027, copied the 'strictly greater' wording to readCommit(Directory,String,int) when it became public; (3) dd70ed5801e3 on main (an earlier landing 3bf1011a4e2 was reverted by fb36f009b77) and fe59fdec5c56 on branch_10x, PR #14607 / backport #15431, replaced the created-major check with the inclusive per-segment minVersion check without updating either javadoc, which made readLatestCommit's created-major sentence false (the repro's created < m test passes on 10.3.2 and fails from 10.4.0 [exec])",
   "introduced_date": "2023-04-18 (#12229); 2024-12-02 (#14027); 2025-11-17 on main and 2025-11-25 on branch_10x (#14607 / #15431)",
   "first_affected_version": "9.6.0 ('strictly greater' in readLatestCommit's javadoc); 9.12.1 and 10.1.0 for readCommit's; 10.4.0 for the unambiguous part (readLatestCommit names the created major, which the code ignores since #15431) [exec]",
   "affected_versions": "the javadoc-asserting repro fails on 9.6.0, 9.12.0, 9.12.1, 9.12.3, 10.0.0, 10.1.0, 10.3.2, 10.4.0, 10.5.2 and main ea57360912ed (-ea and -da on main) [exec], with the javadoc text checked in the release sources jars; every release 9.6.0-10.5.2 by release tags [read]. By part: 'strictly greater' in readLatestCommit 9.6.0-10.5.2 and main; in readCommit 9.12.1-9.12.3, 10.1.0-10.5.2 and main; readLatestCommit's created-major subject 10.4.0-10.5.2 and main [exec]. Not affected: 8.x and earlier (overloads absent) and 9.0.0-9.5.0 (overloads package-private, no javadoc). Unreleased branch_10x and branch_10_6 carry both sentences [read]. readCommit's own created-major subject (10.4.0-10.5.2) was already fixed by others in #16766 (unreleased) and is not part of this row",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16766",
    "https://github.com/apache/lucene/issues/14607",
    "https://github.com/apache/lucene/issues/12872",
    "https://github.com/apache/lucene/issues/16571",
    "https://github.com/apache/lucene/issues/16847",
    "https://github.com/apache/lucene/issues/12229"
   ],
   "doc": "",
   "repro": "repro/LFV-119/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-497",
   "priority": "low",
   "priority_rank": 1136,
   "novelty": "new",
   "withheld": false,
   "area": "index / IndexReader reference counting (decRef javadoc)",
   "title": "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)",
   "summary": "The javadoc of IndexReader#decRef says 'If an exception is hit, the refCount is unchanged', so after a final decRef() that throws (for example because a reader-closed listener or the reader's doClose() throws IOException) getRefCount() should still be 1. Instead the count is 0, the reader is closed, and a retried decRef() throws AlreadyClosedException. The code is the intended side: LUCENE-5553 (2014) deliberately made a failing close really close the reader and still notify every listener, and removed the old put-back-on-failure code that the sentence described, so the fix is javadoc-only.",
   "impact_class": "minor",
   "introduced_commit": "beaa564674fd (lucene_solr_4_7 branch, first released in 4.7.1; the same change is e197d60cfe0 on branch_4x, first in 4.8.0, and a8b93f272f7 on trunk), LUCENE-5553 / apache/lucene#6615 'IndexReader#ReaderClosedListener is not always called on IndexReader#close()', committed by s1monw; an SVN-era JIRA patch, no GitHub PR [read]. It removed the '// Put reference back on failure' refCount.incrementAndGet() block and set closed = true before doClose(), but left the javadoc sentence, which LUCENE-2156 (dc3f92e6e58c, mikemccand, 2009-12-16, first in 3.1) had written together with that put-back block. For an exception from a closed listener the sentence was never true: listeners (3.6.0 on, read) were notified after the put-back block, and 4.7.0 already leaves the count at 0 on that path [exec]",
   "introduced_date": "2014-03-25 (LUCENE-5553 commits on all three branches; the sentence itself dates from 2009-12-16)",
   "first_affected_version": "4.7.1 [exec] (the doClose() path that the @throws clause names; 4.6.1 and 4.7.0 still restore the count [exec]); on the closed-listener path the sentence was already false in 4.7.0 [exec] and, by reading, since listeners were added in 3.6.0",
   "affected_versions": "every release from 4.7.1 through 10.6.0 and main ea57360912ed (10.6.0 [exec]: the minimal test fails on the release jars, -ea); not fixed upstream (upstream main a9779ef3c193 still has the sentence, fetched 2026-10-26) [exec]. Not affected on the doClose() path: 4.6.1 and 4.7.0 [exec], 3.1 to 4.7.0 [read]; before 3.1 the sentence does not exist. Historical side note, not part of this defect: from 4.7.1 to 5.5.x the doClose() IOException came back wrapped in RuntimeException, fixed in 6.0.0 by 0607f007bfa [exec]. All runs on aarch64 with JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-497.html",
   "repro": "repro/LFV-497/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-973",
   "priority": "low",
   "priority_rank": 1137,
   "novelty": "new",
   "withheld": false,
   "area": "queryparser / flexible core nodes (BoostQueryNode javadoc)",
   "title": "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)",
   "summary": "You read the javadoc of the flexible query parser's BoostQueryNode, which says in the class doc, the constructor @param and getValue that the boost value 'may vary from 0.0 to 1.0', and expect the parser to put only such values into the node. Instead boosts above 1.0 are ordinary syntax and pass through unchanged: StandardQueryParser's own javadoc examples jones^2 and (..)^2.5 give nodes with values 2.0 and 2.5, field boosts set with setFieldsBoost (5, 10) do the same, and BoostQuery accepts any finite boost >= 0. The code is right and the javadoc is wrong; nothing clamps or checks the range, and nothing should.",
   "impact_class": "minor",
   "introduced_commit": "343992fcbb4b31249f07354014723f18d0508d8a (Subversion lucene/java/trunk r800191, 'LUCENE-1567: New flexible QueryParser framework.', JIRA LUCENE-1567, migrated to GitHub as #2641; a JIRA patch by Luis Alves and Adriano Campos, committed by Michael Busch; there is no pull request). It created BoostQueryNode with all three sentences, while its own TestQPHelper already asserted term^2 -> term^2.0 and the query syntax page documented 'jakarta^4 apache', so the text never matched the code and this is not a regression [read]",
   "introduced_date": "2009-08-03 (author and commit date of 343992fcbb4)",
   "first_affected_version": "2.9.0 [exec] (the first release with the flexible query parser; 2.4.1 has no such API: compile_error [exec], and no lucene-queryparser artifact exists for it)",
   "affected_versions": "every lucene-queryparser version on Maven Central, 147 final releases 2.9.0 to 10.5.2 plus 4.0.0-ALPHA/BETA [read], plus 10.6.0 (branch_10_6 4ae946e5a9b), branch_10x and main; not fixed upstream (upstream main 645d4fe14a20 still has the text). Executed [exec]: 2.9.0, 3.6.2, 4.0.0, 8.11.4, 9.0.0, 9.12.3, 10.5.2 and main with a main() variant; 9.1.0, 9.12.3, 10.0.0, 10.5.2 and main with the JUnit (-ea; the JUnit does not compile on 9.0.0); 10.5.2, 9.12.3, branch_10_6 4ae946e5a9b and main with the JUnit (-da). Every run gives getValue() = 2.0 for jones^2, and the in-range control smith^0.5 = 0.5 passes everywhere.",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-973.html",
   "repro": "repro/LFV-973/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-943",
   "priority": "low",
   "priority_rank": 1138,
   "novelty": "new",
   "withheld": false,
   "area": "index / SegmentInfos (segments_N file-format javadoc vs its writer and reader)",
   "title": "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)",
   "summary": "You decode a segments_N commit file by following the SegmentInfos class javadoc, which gives the order Header, LuceneVersion, Version, NameCounter, SegCount, MinSegmentLuceneVersion, then per segment SegName, SegID, SegCodec, DelGen, DeletionCount, FieldInfosGen, DocValuesGen, UpdatesFiles, DocValuesOverlays, and types NameCounter as an Int32 and the fixed-width fields with links to DataOutput#writeInt/#writeLong (little-endian since 9.0). The writer instead puts an IndexCreatedVersionMajor VInt right after LuceneVersion, writes NameCounter as a VLong, writes Version, SegCount, DelGen, DeletionCount and the other fixed-width fields big-endian, and adds SoftDelCount, a flag byte plus the 16-byte SegmentCommitInfo id and the FieldInfosFiles set to every segment entry, so a parser built from the text reads the VInt 11 where Version should be and every later field is misaligned. Lucene's own reader matches the writer, so nothing breaks at runtime; only the documentation is wrong, and it has not matched the bytes since 4.9.0 (2014).",
   "impact_class": "minor",
   "introduced_commit": "a stack of omissions, oldest first: (1) FieldInfosFiles: 6ba5d793838 (branch_4x, the commit that first shipped, in 4.9.0) / c863a7251d5 (trunk), LUCENE-5618 and LUCENE-5636 (now apache/lucene#6680, #6698; Subversion era, no pull request), by shaie: it edited the segments_N grammar in the same diff and added writeStringSet(getFieldInfosFiles()) after DocValuesGen without listing it [exec]; (2) the SegID sentence 'the identifier of the Codec': 0f304eafb93 (branch_5x, LUCENE-5969, by rmuir, 5.0.0) [read]; (3) IndexCreatedVersionMajor VInt: 23b002a0fdf (LUCENE-7756, #8807, by jpountz, 7.0.0) [exec]; (4) NameCounter as VLong: 4c5ce2d646b (branch_7x) / ea36f5040c3 (master), LUCENE-7999 (#9047), by mikemccand, 7.2.0 [exec]; (5) SoftDelCount: 21f03a49532 (branch_7x) / fe83838ec37 (master), LUCENE-8341 (#9388), by s1monw, 7.4.0 [exec]; (6) SegmentCommitInfo id (flag byte plus 16 bytes): 2d63a9d1208 (branch_8x) / 113043b1ed2 (master), LUCENE-9324 (#10364, PR apache/lucene-solr#1434), by s1monw, 8.6.0 [exec]; (7) endianness links: b84e0c272b6 (LUCENE-9047, #10089, PR #107, by iverase, 9.0.0) made DataOutput#writeInt/#writeLong little-endian while segments_N deliberately stayed big-endian through CodecUtil.writeBE*, and the javadoc links were not revisited [exec]. 75eddfaff22 (#16418, by jimczi, 2026-08; backported as 3a6cd003aaf, #16554, released in 10.6.0) added DocValuesOverlays to the grammar with the same little-endian links and left the rest as it was. Leftovers: 'Generation' and 'Checksum' in the Int64 data-type row match no element (819eda82e33 LUCENE-2446, 4.8.0; b7047694256 LUCENE-5925, 5.0.0) [read]",
   "introduced_date": "2014-05-21 (author date of 6ba5d793838 and c863a7251d5: FieldInfosFiles, the oldest part still present); later parts 2014-10-24 (SegID wording), 2017-03-30 (IndexCreatedVersionMajor), 2017-10-24 (NameCounter VLong), 2018-05-26 (SoftDelCount), 2020-04-18 (SegmentCommitInfo id), 2021-05-03 (endianness links), 2026-08-13 (DocValuesOverlays added with the same links)",
   "first_affected_version": "4.9.0 [exec] (FieldInfosFiles; for the defect as claimed 4.8.1 is the last unaffected release [exec]: an update-free commit parses exactly as documented, and its separate, since-fixed UpdatesFiles mismatch of 4.6.0-4.8.1 is not part of this claim); later parts: 5.0.0 (SegID wording) [read], 7.0.0 (IndexCreatedVersionMajor, the first stale field a parser of a 7.0+ commit hits) [exec], 7.2.0 (NameCounter VLong) [exec], 7.4.0 (SoftDelCount) [exec], 8.6.0 (SegmentCommitInfo id) [exec], 9.0.0 (endianness links) [exec]",
   "affected_versions": "every release from 4.9.0 through 10.6.0 (10.6.0 run as its release revision, the branch_10_6 head 4ae946e5a9b) and main a9779ef3c193; not fixed upstream [exec]. Caveats: 8.8.2-8.11.4 are not tagged in the history clone (8.11.4 executed from checksum-verified release jars); upstream main 645d4fe14a20 (2026-10-28) still carries the text [read]; all runs used JDK 25 on Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-943.html",
   "repro": "repro/LFV-943/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-942",
   "priority": "low",
   "priority_rank": 1139,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / field infos (Lucene94FieldInfosFormat .fnm file-format javadoc vs its writer and reader)",
   "title": "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)",
   "summary": "You decode a field infos (.fnm) file of the default codec by following the Lucene94FieldInfosFormat javadoc, which gives each field as FieldName, FieldNumber, FieldBits, DocValuesBits, DocValuesGen, Attributes, DimensionCount, DimensionNumBytes, documents DocValuesBits as a norms nibble plus a doc-values nibble with codes 0..3, and lists only FieldBits 0x1, 0x2 and 0x4. The writer instead puts an IndexOptions byte right after FieldBits, writes a single doc-values code (SORTED_SET = 4, SORTED_NUMERIC = 5) followed by a skip-index byte, writes PointIndexDimensionCount and PointNumBytes only when the dimension count is non-zero, appends VectorDimension, VectorEncoding and VectorSimilarityFunction, and sets FieldBits 0x8 (soft-deletes field) and 0x10 (parent field), so a parser built from the text reads the IndexOptions byte of a text field (3) as 'SORTED doc values' and loses alignment on the first field. Lucene's own reader matches the writer, so nothing breaks at runtime; only the documentation is wrong, and its sequence has been since 5.0.0.",
   "impact_class": "minor",
   "introduced_commit": "layered. Primary part (the per-field sequence): 8f9f8a3252c73428e67bc5d390e58d1370e060ba (trunk) / 9ac215e4f99a8813b23ad700a05b154b37f728ff (branch_5x, the commit that shipped in 5.0.0), LUCENE-6013 'remove IndexableFieldType.indexed and FieldInfo.indexed' (now apache/lucene#7075; SVN era, no GitHub PR), by mikemccand: it moved IndexOptions out of FieldBits into its own byte written after FieldBits and added it to the type list and the tables but not to the sequence [read]. Every other layer changed the writer and reader together and left the javadoc as it was: DocValuesBits table 0..3 without SORTED_SET = 4 since b44aa618348 (LUCENE-4765, 4.2.0) and SORTED_NUMERIC = 5 since 398af4596bd (LUCENE-5748, 4.9.0); norms nibble dropped by 78e445ce579 (LUCENE-6006, 5.0.0); DimensionNumBytes written only for point fields since d3869edb96d (LUCENE-6861, 6.0.0); FieldBits 0x8 e7a0a12926c (LUCENE-8335, 7.4.0); PointIndexDimensionCount 1118299c338 (LUCENE-8496, 7.6.0); vector elements c02f07f2d5d (LUCENE-9322, 9.0.0); the Lucene94 class itself a693fe819b0 (apache/lucene#1054, LUCENE-10577, 9.4.0), which copied the stale Lucene90 text and added a VectorEncoding byte, described but not placed; FieldBits 0x10 df6bd25ce44 (#12829, 9.10.0); skip-index byte b59a357e586 (#13784, 10.0.0); IndexOptions 5 5158a52a082 / branch_10x 3a55cc9ac5e (#15584, 10.5.0); VectorEncoding 2 bfe5c847d3c (#16383, main only) [read]",
   "introduced_date": "2014-10-21 (author date of 8f9f8a3252c and 9ac215e4f99: the per-field sequence); 2013-02-20 (author date of b44aa618348: the first value missing from the DocValuesBits table); later layers 2014-06-12 to 2026-07-27 (see introduced_commit)",
   "first_affected_version": "5.0.0 [exec] for the per-field sequence (the last unaffected release is 4.10.4 [exec], whose documented Lucene46FieldInfosFormat sequence parses the file exactly to the footer); 4.2.0 [exec] for the incomplete DocValuesBits table; 9.4.0 [exec] is the first release of Lucene94FieldInfosFormat (5.0.0-9.3.0 carry the same text in the then-default Lucene50, Lucene60 and Lucene90FieldInfosFormat)",
   "affected_versions": "every release from 5.0.0 through 10.6.0 for the sequence (4.2.0-4.10.4 for the DocValuesBits table only; 10.6.0 run as its release revision, the branch_10_6 head 4ae946e5a9b) and main a9779ef3c193; not fixed upstream [exec]. Per part: IndexOptions missing from the sequence and the stale norms nibble 5.0.0 on; doc-values code 4 4.2.0 on, code 5 4.9.0 on; conditional DimensionNumBytes 6.0.0 on; FieldBits 0x8 7.4.0 on; PointIndexDimensionCount 7.6.0 on; vector elements 9.0.0 on (VectorEncoding 9.4.0 on); FieldBits 0x10 9.10.0 on; skip-index byte 10.0.0 on; IndexOptions 5 10.5.0 on (also branch_10x and branch_10_6); VectorEncoding 2 main only. Caveats: 8.9.0-8.11.3 are not tagged in the history clone (javadoc read at 8.8.x, behaviour executed on 8.11.4); upstream main 645d4fe14a20 (2026-10-28) holds a byte-identical file; all runs used JDK 25 on Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-942.html",
   "repro": "repro/LFV-942/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-934",
   "priority": "low",
   "priority_rank": 1140,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / segment info (Lucene99SegmentInfoFormat .si file-format javadoc vs its writer and reader)",
   "title": "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)",
   "summary": "You decode a segment info (.si) file of the default codec by following the Lucene99SegmentInfoFormat javadoc, which gives the sequence Header, SegVersion, SegSize, IsCompoundFile, Diagnostics, Files, Attributes, IndexSort, Footer and types SegVersion (and SegMinVersion) as a String. The writer instead stores the version as three Int32s (major, minor, bugfix), then a flag byte and, when it is 1, the minimum version as three more Int32s, then SegSize, IsCompoundFile and a HasBlocks byte, so a parser built from the text reads the Int32 major version 11 as a string length and gets 11 NUL characters instead of '11.0.0', and every later field is misaligned. Lucene's own reader matches the writer, so nothing breaks at runtime; only the documentation is wrong, and it has been since 5.0.0.",
   "impact_class": "minor",
   "introduced_commit": "three stages: (1) a922e8919145243c5afc4d6e43448a8c2806eea7 (trunk, svn r1629769) / 776682ba9c36b9543980cd959ca0a62488a6318a (branch_5x, svn r1629775, the commit that first shipped, in 5.0.0), LUCENE-5992 'encode version using 3 ints, not String' (now apache/lucene#7054; a JIRA patch, no GitHub PR), by mikemccand: it changed the Lucene50 segment info writer and reader from writeString(version) to three writeInt calls and left the javadoc's String typing [read]; (2) 23b002a0fdf (LUCENE-7756, apache/lucene#8807, by jpountz; the history clone also holds an identical commit fd9689cb36a of the same date) added SegMinVersion, typed String and left out of the sequence, while the writer stored a flag byte plus three Int32s from the start [exec]; (3) 6677109ee60 / branch_9x 26043819a5b (PR apache/lucene#12685, by s1monw) created Lucene99SegmentInfoFormat by copying the stale Lucene90 javadoc and added HasBlocks to the type list and descriptions but not to the sequence [exec]. The String typing was correct when written (f330cf65adc, LUCENE-4055, 2012).",
   "introduced_date": "2014-10-06 (author date of a922e891914 and 776682ba9c3: SegVersion); 2017-03-30 (author date of 23b002a0fdf: SegMinVersion); 2023-10-23 (author date of 6677109ee60: HasBlocks and the Lucene99 class)",
   "first_affected_version": "5.0.0 [exec] (SegVersion; the last unaffected release is 4.10.4 [exec], whose different class Lucene46SegmentInfoFormat documented the String version the writer then wrote); 7.0.0 [exec] for the SegMinVersion gap; 9.9.0 [exec] for the HasBlocks gap and the first release of Lucene99SegmentInfoFormat",
   "affected_versions": "every release from 5.0.0 through 10.6.0 (10.6.0 run as its release revision, the branch_10_6 head 4ae946e5a9b) and main a9779ef3c193; not fixed upstream [exec]. The stale text lives in Lucene50SegmentInfoFormat (5.0-6.1), Lucene62 (6.2-6.6), Lucene70 (7.0-8.5), Lucene86 (8.6-8.11), Lucene90 (9.0-9.8) and Lucene99 (9.9-main). Before 9.0 an Int32 is big-endian, so the documented readString returns an empty string; since 9.0 it is little-endian and returns as many NUL or garbage characters as the major version number. Caveats: the 8.9-8.11 sources are not in the history clone (javadoc read at 8.8.1, behaviour executed on 8.11.4); upstream main 645d4fe14a20 (2026-10-28) still carries the text [read]; all runs used JDK 25 on Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-934.html",
   "repro": "repro/LFV-934/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-939",
   "priority": "low",
   "priority_rank": 1141,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / terms dictionary (Lucene103BlockTreeTermsWriter .tim/.tmd file-format javadoc vs its writer and reader)",
   "title": "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)",
   "summary": "You decode the terms metadata (.tmd) and terms dictionary (.tim) files of the default codec by following the Lucene103BlockTreeTermsWriter javadoc, which says .tmd is Header, NumFields, FieldStats... with a RootCodeLength and root-code bytes in each FieldStats, and that every .tim field starts with a PostingsHeader. The writer instead puts the postings writer's header (an IndexHeader plus the block size) once into .tmd, right after its own header and before NumFields, writes no PostingsHeader into .tim and, since the trie terms index of 10.3.0, writes no root code; a parser built from the text reads NumFields as 63 (the first byte of the codec magic) and, even with that header skipped, takes SumTotalTermFreq for RootCodeLength. Lucene's own reader matches the writer, so nothing breaks at runtime; only the documentation is wrong.",
   "impact_class": "minor",
   "introduced_commit": "two stages plus a wording point: (A, PostingsHeader placement) 87a3bef50f8c08404ee8bd66ca868caf5dd072cb (main) / 0dac659cd17 (branch_8x backport, the commit that first shipped, in 8.6.0), LUCENE-9353 'Move terms metadata to its own file' (apache/lucene-solr#1473, by jpountz): it changed postingsWriter.init(termsOut, state) to init(metaOut, state), which moved the postings header from .tim to the new .tmd, and left the javadoc as it was [read]; carried forward by #90 (5f5d1949e92, 2021-04-20, 9.0.0: wrote the .tmd grammar without the postings header) and #823 (main 2d278a0efe2 / branch_9x 47bc1fff4d7, 2022-04-20, 9.2.0 through the branch_9x commit: the per-field 'FieldDict --> PostingsHeader' wording); (B, root code) 878e23f77390058b6787e0a0537de9087d1019b3 (main) / 65fd8648eb6 (branch_10x backport #14563, in 10.3.0), #14333 'A specialized Trie for Block Tree Index' (by gf2121): it created Lucene103BlockTreeTermsWriter from Lucene90BlockTreeTermsWriter, replaced the FST elements of FieldStats by TrieRootNodeFp and IndexEndFp, but kept RootCodeLength, Byte^RootCodeLength and the note 'RootCode points to the root block' [exec]; (C, minor wording) 'Header --> CodecHeader' while IndexHeaders are written, since LUCENE-5969 (4675aaf55d4 main line 2014-10-21, 0f304eafb93 branch_5x 2014-10-24) [exec]",
   "introduced_date": "2020-06-16 (author date of 87a3bef50f8 and 0dac659cd17: PostingsHeader placement); 2025-04-14 (author date of 878e23f7739 on main: root code; backport 65fd8648eb6 authored 2025-05-09); 2014-10-21 / 2014-10-24 (CodecHeader wording, LUCENE-5969)",
   "first_affected_version": "8.6.0 [exec] for the PostingsHeader placement (last unaffected release 8.5.2 [exec]); 10.3.0 [exec] for RootCodeLength/RootCode, the first release of Lucene103BlockTreeTermsWriter (last unaffected 10.2.2 [exec], FST era); 5.0.0 [exec] for the minor CodecHeader-vs-IndexHeader wording (4.10.4 [exec] unaffected)",
   "affected_versions": "PostingsHeader placement: 8.6.0 through 8.11.4, every 9.x and 10.x release through 10.6.0 (10.6.0 run as its release revision, the branch_10_6 head 4ae946e5a9b) and main a9779ef3c193; RootCode: 10.3.0 through 10.6.0 (the same branch_10_6 run) and main; not fixed upstream [exec]. Before 9.0 the stale text lived in the then-current block-tree writer class (BlockTreeTermsWriter, 8.6-8.11) and in Lucene90BlockTreeTermsWriter (9.x-10.2); the 8.6-8.11 javadoc did not document .tmd at all. Upstream main 645d4fe14a20 (2026-10-28) still carries the lines [read]; all runs used JDK 25 on Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-939.html",
   "repro": "repro/LFV-939/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-972",
   "priority": "low",
   "priority_rank": 1142,
   "novelty": "new",
   "withheld": false,
   "area": "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)",
   "title": "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)",
   "summary": "You index ordinary documents with the default codec and look up the files in the index directory in the 'Summary of File Extensions' table of the codec's package documentation, which says it 'summarizes the names and extensions of the files' of this format version. Seven extensions the default codec writes are missing (.fdm, .tvm, .tmd, .psm, .dvs, .dvp, .vemf); the vector row lists '.vec, .vem, .veq, vex', but the default Lucene99HnswVectorsFormat it links writes .vec, .vemf, .vem and .vex (.veq comes only from the optional scalar-quantized formats) and 'vex' lacks its dot; and Lucene104PostingsFormat's own 'Files and detailed format' list leaves out .tmd and .psm. Lucene itself reads and writes all these files correctly; each format change since 8.5.0 that added a file updated at most its own class javadoc, never this overview.",
   "impact_class": "minor",
   "introduced_commit": "accumulated staleness, one layer per format change. Earliest still-present layer: 136dcbdbbce (main) / 597141df6b6 (branch_8x, first in 8.5.0), LUCENE-9147 'Move the stored fields index off-heap' (apache/lucene-solr#1179, migrated issue apache/lucene#10187), by jpountz: it started writing .fdm and .tvm and documented .fdm in the stored-fields format javadoc but not in the codec table [exec]. Later layers: 87a3bef50f8 / 0dac659cd17 (LUCENE-9353, apache/lucene-solr#1473, jpountz: .tmd, 8.6.0); f2bf5339e53 / 6623c42553b (#12582, benwtrent: wrote the '.vec, .vem, .veq, vex' row while the HNSW format itself still wrote .veq) and a47ba3369f4 / 448e6112954 (#12729, benwtrent: moved .veq to separate formats and added .vemf without touching the row), both first in 9.9.0; b4a8810b7ae / 59b7c28eb47 (#13585, jpountz: .psm, 9.12.0); 37b6d65a7d6 / 71a214ce53c (#15976, romseygeek: .dvs, 10.5.0); 1160d3c8a25 / 977dfa876d2 (#16540, sgup432: .dvp, 10.6.0). The undotted 'vex' was dotted in 10.2.x (#14078) and came back in 10.3.0, when #14333 / #14563 created lucene103/package-info.java from the older text. Correction of an earlier attribution: LUCENE-9456 (8.7.0) only moved more metadata into the existing .fdm and .tvm files (8.6.3 and 8.7.0 write the same set)",
   "introduced_date": "2020-02-05 (author date of 136dcbdbbce and 597141df6b6: .fdm and .tvm); later layers 2020-06-16 (.tmd), 2023-10-24 and 2023-11-10 (the vector row), 2024-07-31 (.psm), 2026-04-22 (.dvs), 2026-09-11 (.dvp)",
   "first_affected_version": "8.5.0 [exec] (.fdm and .tvm missing; the last unaffected release is 8.4.1 [exec], and 8.0.0 also passes); the wrong vector row (.veq credited to the default format, .vemf missing, undotted 'vex') from 9.9.0 [exec]",
   "affected_versions": "every release from 8.5.0 through 10.6.0 (the branch_10_6 head 4ae946e5a9b) and main a9779ef3c193; not fixed upstream. By part [follow-up]: .fdm/.tvm 8.5.0-10.6.0; .tmd (table and postings list) 8.6.0-10.6.0; .veq misattributed and .vemf missing 9.9.0-10.6.0 (the 10.2.x row also lists .veb/.vemb); undotted 'vex' 9.9.0-10.1.0 and 10.3.0-10.6.0 (dotted in 10.2.0-10.2.2; 10.6.0 by reading); .psm (table and postings list) 9.12.0-10.6.0; .dvs 10.5.0-10.6.0; .dvp 10.6.0, branch_10x and main [exec]. 8.8.2-8.11.3 are inferred (not tagged in the history clone; same codec, and the 8.8.1 and 8.11.4 tables are identical). Out of scope: the 8.6-9.12 stale points row, fixed for 10.0.0 by #13801. Caveats: all runs used JDK 25.0.3 on Linux aarch64; upstream main 645d4fe14a20 (2026-10-28) has not changed either file",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-972.html",
   "repro": "repro/LFV-972/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-938",
   "priority": "low",
   "priority_rank": 1143,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / norms (Lucene90NormsFormat .nvm file-format javadoc vs Lucene90NormsConsumer / Lucene90NormsProducer)",
   "title": "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)",
   "summary": "You decode the norms metadata (.nvm) file of the default codec by following the Lucene90NormsFormat javadoc, which says each Entry is FieldNumber (Int32), DocsWithFieldAddress (Int64), DocsWithFieldLength (Int64), NumDocsWithField (Int32), BytesPerNorm (byte), NormsAddress (Int64). Since the jump tables of Lucene 8.0 the writer stores two more fields right after DocsWithFieldLength, an Int16 jump-table entry count and a byte dense rank power, so a parser built from the text reads NumDocsWithField as 67108863 instead of 3 (the bytes FF FF and FF of the two missing fields plus the first byte of the real count) and every later field is shifted. Lucene's own reader matches the writer, so nothing breaks at runtime; only the documentation is wrong (it also labels the file '.dvm', the doc-values extension).",
   "impact_class": "minor",
   "introduced_commit": "c13645bd4c65f052e7f35df8e33d3dbfe6d7cd58 (master) / 5bb6a5b42c406dcc072554527f59b10ff41f2a8c (branch_8x cherry-pick, the commit that first shipped, in 8.0.0), LUCENE-8585 'Create jump-tables for DocValues at index-time' (now apache/lucene#9631; it landed as a direct commit, the GitHub PR apache/lucene-solr#525 was closed without merge), by tokee: it added meta.writeShort(jumpTableEntryCount) and meta.writeByte(denseRankPower) to the new Lucene80NormsConsumer in all three branches and created Lucene80NormsFormat with the Lucene70 Entry grammar unchanged (it did update the .nvd line and the lucene80 package-info prose about jump tables) [read]. Carried forward by 4d7b2aebfe01e2a8d0407c179238bb5e092b8d2a (LUCENE-9705, apache/lucene-solr#2392, by jtibshirani), which created Lucene90NormsFormat as a verbatim copy (first release 9.0.0); the file has not changed since. Two older cosmetic parts with their own origin: the '(.dvm)' label comes from 6384ae9fb70 (LUCENE-5743, by rmuir, 4.9.0) and the BytesPerNorm (Entry) / BytesPerValue (notes, .nvd grammar) naming mix from 9128bdbaf54 (LUCENE-7475, by jpountz, 7.0.0)",
   "introduced_date": "2019-01-18 (author date of c13645bd4c6 and of the branch_8x cherry-pick 5bb6a5b42c4, committed 2019-01-21); 2021-02-22 (4d7b2aebfe0, the copy into Lucene90NormsFormat); cosmetic parts 2014-06-10 (6384ae9fb70, '.dvm' label) and 2016-10-05 (9128bdbaf54, BytesPerNorm naming)",
   "first_affected_version": "8.0.0 [exec] (the missing Entry fields; the last unaffected release is 7.7.3 [exec], whose Lucene70NormsFormat grammar matched its writer exactly); 9.0.0 [exec] is the first release of Lucene90NormsFormat; the '.dvm' label is older (4.9.0 [read])",
   "affected_versions": "every release from 8.0.0 through 10.6.0 (10.6.0 run as its release revision, the branch_10_6 head 4ae946e5a9b) and main a9779ef3c193; not fixed upstream [exec]. The stale Entry lives in Lucene80NormsFormat (default in 8.0-8.11, and the frozen backward-codecs copy in every 9.x and 10.x release; removed from main by #15712) and Lucene90NormsFormat (9.0 to main, used by every default codec since). Before 9.0 an Int32 is big-endian, so for a 4-document field the documented NumDocsWithField reads -256 there and 83886079 since 9.0: the same FF FF FF bytes in the other byte order. Caveats: all runs used JDK 25 on Linux aarch64; upstream main 645d4fe14a20 (2026-10-28) still carries the text [read]; the zero-docs writer branch was read in code only",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-938.html",
   "repro": "repro/LFV-938/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-970",
   "priority": "low",
   "priority_rank": 1144,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / live docs (Lucene90LiveDocsFormat .liv file-format javadoc vs its writer and reader)",
   "title": "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)",
   "summary": "You decode a live-docs (.liv) file of the default codec by following the Lucene90LiveDocsFormat javadoc, which gives the layout 'IndexHeader, Generation, Bits'. The writer instead stores the deletes generation inside the IndexHeader (as its suffix, in base 36), then the bit words, then a 16-byte codec footer, so there is no Generation field after the header: a decoder that reads one there gets the first word of the bit set, and one that skips it finds 16 bytes the grammar does not mention. The type list also defines 'SegmentHeader' while the grammar says 'IndexHeader'; Lucene's own reader matches the writer, so nothing breaks at runtime, only the documentation is wrong.",
   "impact_class": "minor",
   "introduced_commit": "c4bf601b68f04a7f8ea1cbddea0b77a9858c48b2 (lucene5969 feature branch, svn r1633514, LUCENE-5969 'Add Lucene50Codec', now apache/lucene#7031; svn era, no GitHub PR; by rmuir): it moved the generation into the IndexHeader suffix (writeIndexHeader(..., Long.toString(gen, Character.MAX_RADIX))), removed output.writeLong(gen) and the 'Generation --> Int64' type line, but kept 'Generation' in the grammar; it reached the 5.0.0 release line as 0f304eafb93 (branch_5x, svn r1633993) and trunk as ff50c35fc22 [exec]. Secondary parts [read]: the missing Footer dates from the first Lucene50LiveDocsFormat, afee9af13f2 (2014-09-26), whose grammar 'SegmentHeader,Bits' already omitted the footer the writer appended; the SegmentHeader/IndexHeader label mismatch comes from c4bf601b68f plus 5dcd24bf04c ('LUCENE-5969: fix precommit, improve file format docs', the same day, which renamed the grammar's first element to IndexHeader and kept Generation). The text was copied unchanged into Lucene90LiveDocsFormat by f0a2f1fe039 (LUCENE-9705, apache/lucene-solr#2274, 2021)",
   "introduced_date": "2014-10-22 (author date of c4bf601b68f, lucene5969 branch); 2014-10-24 (0f304eafb93 on branch_5x, ff50c35fc22 on trunk); the footer omission is older, 2014-09-26 (afee9af13f2); all before the 5.0.0 release",
   "first_affected_version": "5.0.0 [exec] (the first release with this binary .liv format; in 4.10.4 and older the default codec writes .del through Lucene40LiveDocsFormat, and neither Lucene50LiveDocsFormat nor Lucene90LiveDocsFormat exists [exec]; SimpleText's plain-text .liv files, written since 4.0.0, are a different format); no release ever shipped the correct state, because the Int64 Generation element was added (15b8b1e66d9, 2014-09-26) and removed (c4bf601b68f / 0f304eafb93, 2014-10-22/24) during 5.0 development",
   "affected_versions": "every release with the .liv format, 5.0.0 through 10.6.0 (the branch_10_6 head 4ae946e5a9b) and main a9779ef3c193; not fixed upstream [exec]. The text lives in Lucene50LiveDocsFormat (5.0.0-8.x) and Lucene90LiveDocsFormat (9.0.0-main). Caveats: the release-tag clone has no 8.8.2 or 8.9.0-8.11.4 tags (8.11.4 bytes executed, its javadoc not read); upstream main 645d4fe14a20 (2026-10-28) still carries the lines [read]; all runs used JDK 25 on Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-970.html",
   "repro": "repro/LFV-970/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-974",
   "priority": "low",
   "priority_rank": 1145,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / doc values (Lucene90DocValuesFormat class javadoc prose vs Lucene90DocValuesConsumer)",
   "title": "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)",
   "summary": "You read the Lucene90DocValuesFormat javadoc to learn how the default codec stores the terms of SORTED and SORTED_SET doc values, and it says they are written in chunks of 16 terms, each starting with one term written in full while the others share prefixes. Since Lucene 9.0 the writer instead uses blocks of 64 terms: only the first term of each block is stored in full, and the other 63 are prefix-coded and then compressed with LZ4, a step the javadoc never mentions, so in the .dvd file only terms 0, 64, 128, ... appear in clear, not 0, 16, 32, .... The same javadoc says a lookup table is used for numeric fields with fewer than 256 unique values, but a field with exactly 256 is also table-compressed; Lucene's own reader matches the writer, so nothing breaks at runtime, only the documentation is wrong.",
   "impact_class": "minor",
   "introduced_commit": "a7a02519f0a5652110a186f4909347ac3349092d (LUCENE-9843 'Remove compression option on default codec's docvalues', now apache/lucene#10882; landed from a JIRA patch, no GitHub PR; committed by rmuir, CHANGES credits the patch to jdconrad; main only, never on branch_8x): it removed the doc-values compression modes so that terms dictionaries always use 64-term LZ4 blocks, and its diff of Lucene90DocValuesFormat.java deleted TERMS_DICT_BLOCK_SHIFT = 4 (the 16-term constant) but left the 'chunks of 16' sentence untouched [read]. Older parts [read]: the sentence itself comes from c2f37e0de2d (2013-08-19, 'javadocs/cleanups', Lucene45DocValuesFormat, by rmuir), when it was true (ADDRESS_INTERVAL = 16), and was copied into Lucene90DocValuesFormat by 4d7b2aebfe0 (LUCENE-9705, apache/lucene-solr#2392, 2021-02-22); the '(< 256)' wording comes from 2c6bf041900 (2013-08-16, 'bump 4.5 codec', by rmuir) and was off by one from the start (the writer has always dropped the table only when size() > 256). A narrower earlier form: LUCENE-9663 (5856c0f176c on main, b61b19c746a on branch_8x, apache/lucene-solr#2302) made the sentence wrong for the non-default BEST_COMPRESSION mode of Lucene80DocValuesFormat in 8.9.0-8.11.4",
   "introduced_date": "2021-05-06 (author and commit date of a7a02519f0a, the main part); 2013-08-16 (2c6bf041900, the '< 256' wording); 2021-02-09 author / 2021-02-15 commit (5856c0f176c, LUCENE-9663, the non-default-mode form, on branch_8x as b61b19c746a on 2021-03-17)",
   "first_affected_version": "9.0.0 [exec] for the main claim in the default codec (the last unaffected release is 8.11.4 [exec], whose default BEST_SPEED mode really writes 16-term chunks); 8.9.0 [exec] for the narrower form in the non-default BEST_COMPRESSION mode; 4.5.0 [exec] for the '< 256' wording (4.4.0 [exec] behaves the same but its javadoc gives no number)",
   "affected_versions": "every release from 9.0.0 through 10.5.2 (33 releases), 10.6.0 (the branch_10_6 head 4ae946e5a9b) and main a9779ef3c193; not fixed upstream [exec]. For 'chunks of 16' before 9.0: 8.9.0-8.11.4 are affected only in the non-default BEST_COMPRESSION mode [exec], and 8.8.2 and older are not affected [exec]. The '< 256' wording is inexact in every release from 4.5.0 [exec]; the frozen backward-codecs Lucene80DocValuesFormat repeats both sentences (not part of this finding). Caveats: all runs used JDK 25 on Linux aarch64; the releases between the executed ones were read from the tags; upstream main 645d4fe14a20 (2026-10-28) still has the stale lines 77 and 101 [read]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-974.html",
   "repro": "repro/LFV-974/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-971",
   "priority": "low",
   "priority_rank": 1146,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / compound files (Lucene90CompoundFormat .cfe file-format javadoc vs the Lucene90CompoundFormat writer / Lucene90CompoundReader)",
   "title": "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)",
   "summary": "You decode the compound entry table (.cfe) of a default-codec segment by following the Lucene90CompoundFormat javadoc, which says the file is Header, FileCount and then FileCount entries of FileName, DataOffset, DataLength, each holding 'a String with that file's name'. The writer also appends a 16-byte codec footer (the .cfs line just above lists its Footer, the .cfe line does not) and stores each name with the segment name stripped, for example '.nvd' for _0.nvd, so a parser built from the text ends 16 bytes early (byte 134 of 150 in the minimal repro, byte 502 of 518 in the hunt's 20-document test) and cannot find the sub-files by the names it read. Lucene's own reader checks the footer and puts the segment name back, so nothing breaks at runtime; only the documentation is wrong (the type line also lists an unused 'Checksum', which belongs to the linked CodecFooter grammar, so dropping it is cleanup).",
   "impact_class": "minor",
   "introduced_commit": "Missing .cfe Footer (the main part): c189d0fb74dd1632c18d7c87d490516ff08b3fae (trunk, LUCENE-2446 'add checksums to index files', migrated as apache/lucene#3520; JIRA patch era, no PR) added CodecUtil.writeFooter to the .cfe writer and ', Footer' to the .cfs line only (plus 'Checksum' to the type line); the branch_4x backport 819eda82e33 put the Footer on the .cfe line instead, so 4.8.0-4.10.4 documented it. It reached the release line with 55594bad9b07af90de4ab2a2fb0bac8e8c2b0b3c (branch_5x, LUCENE-5944 bulk backport of trunk, apache/lucene#7006), which replaced the 4.x text with the trunk text; carried forward by LUCENE-5969 (apache/lucene#7031, 5893b1da299, Lucene50CompoundFormat) and LUCENE-9705 (apache/lucene-solr#2268, eafeb664340, Lucene90CompoundFormat). FileName wording: the writer stores stripSegmentName(file) since LUCENE-2455 (d6dd2e234e1 trunk / 06b82e04ee9 branch_3x, 2010), after which the older 'that file's name' sentence was stale; 25a59d8902e / 49b3257d451 ('merge/cleanup outdated javadocs', 2012-06-11) moved it into the public CompoundFileDirectory javadoc that the format overview links [read]",
   "introduced_date": "2014-04-01 (author date of c189d0fb74d on trunk); 2014-09-18 (author date of 55594bad9b0, the release-line commit); FileName part: 2010-05-26/27 (LUCENE-2455) and 2012-06-11 (moved into the public format docs)",
   "first_affected_version": "5.0.0 [exec] for the missing .cfe Footer (the last unaffected release is 4.10.4 [exec]: 4.8.0-4.10.4 list the Footer on the .cfe line; 4.0.0-4.7.2 wrote no footer, so their footer-less line was right); FileName wording 4.0.0 [exec] in the public format docs (3.1 in an internal class javadoc [read]); 9.0.0 [exec] is the first release of Lucene90CompoundFormat",
   "affected_versions": "every release from 5.0.0 through 10.6.0 (the branch_10_6 head 4ae946e5a9b) and main a9779ef3c193; FileName part also 4.0.0-4.10.4; not fixed upstream (main 645d4fe14a20 on 2026-10-28 has the same text) [exec]",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-971.html",
   "repro": "repro/LFV-971/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-941",
   "priority": "low",
   "priority_rank": 1147,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / vectors (Lucene99FlatVectorsFormat .vemf and Lucene99HnswVectorsFormat .vem and .vex file-format javadoc vs their writers and readers)",
   "title": "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)",
   "summary": "You decode the vector metadata (.vemf, .vem) or the HNSW graph (.vex) files of the default codec by following the Lucene99FlatVectorsFormat and Lucene99HnswVectorsFormat javadocs, which list each field as '[int32] field number, [int32] vector similarity function ordinal, [vlong] offset, ...' and each neighbour list as '[vint] count, array[vint] delta-encoded ordinals'. Both writers instead store an extra int32, the vector encoding (BYTE or FLOAT32), between the field number and the similarity, and since 10.3 they write the neighbour deltas with group-varint, so a parser built from the text reads the encoding as the similarity (a COSINE float field comes out as DOT_PRODUCT), gets the offset, length, dimension and count wrong, and decodes wrong neighbours from the first list of 4 or more neighbours on. Lucene's own readers match the writers, so nothing breaks at runtime; only the documentation is wrong, the metadata part since 9.4.0 and the .vex part since 10.3.0.",
   "impact_class": "minor",
   "introduced_commit": "two parts: (1) the missing encoding int32: a693fe819b04f07942bb1bcbc28169838f1becfc (main) / 87a8f7d48f3 (branch_9x cherry-pick, the commit that first shipped, in 9.4.0), LUCENE-10577 'enable quantization of HNSW vectors to 8 bits' (apache/lucene#1054), by msokolov: it added meta.writeInt(field.getVectorEncoding().ordinal()) to the then-default Lucene94HnswVectorsWriter and readVectorEncoding to the reader, and edited the .vec and .vem level lines of the Lucene94 javadoc but not the field number / similarity lines [read]; the stale text was carried into the two classes named here when they were created, by f2bf5339e53 / branch_9x 6623c42553b (apache/lucene#12582, Lucene99HnswVectorsFormat, by benwtrent) and a47ba3369f4 / branch_9x 448e6112954 (apache/lucene#12729, Lucene99FlatVectorsFormat, by benwtrent), both first released in 9.9.0; (2) the .vex neighbour encoding: a6c99125599 (main) / a0de4374446 (branch_10x), apache/lucene#14932 'GroupVarInt Encoding Implementation for HNSW Graphs', by aylonsk: VERSION_CURRENT = VERSION_GROUPVARINT and writeGroupVInts for the neighbour deltas, with no change to the class javadoc's .vex list [read]. The stale lines were correct when written: '[int32] field number' in 5b36af3cd79 (LUCENE-9844, 2021-03-18), the similarity line in 6d4b5eaba35 (2021-04-25) and the .vex vint lines in d0be9ab57c9 (#11860, 2022-12-07)",
   "introduced_date": "2022-08-10 (author date of a693fe819b0 and 87a8f7d48f3: the encoding int32); 2023-10-24 and 2023-11-10 (author dates of f2bf5339e53 and a47ba3369f4: the Lucene99 HNSW and flat classes created with the stale list); 2025-08-06 (author date of a6c99125599 and a0de4374446: group-varint .vex)",
   "first_affected_version": "9.4.0 [exec] for the missing encoding int32, through the then-default Lucene94HnswVectorsFormat .vem javadoc (the last unaffected release is 9.3.0 [exec], whose Lucene92 writer wrote no encoding int); 9.9.0 [exec] for the two classes named in the title, which exist from 9.9.0 and were wrong from creation; 10.3.0 [exec] for the .vex group-varint part (last unaffected 10.2.2 [exec])",
   "affected_versions": "every release from 9.4.0 through 10.6.0 (10.6.0 run as its release revision, the branch_10_6 head 4ae946e5a9b) and main a9779ef3c193 for the metadata part, and 10.3.0 through 10.6.0 and main for the .vex part; not fixed upstream [exec]. Before 9.9 the stale lines live in Lucene94HnswVectorsFormat (9.4) and Lucene95HnswVectorsFormat (9.5-9.8), still present in backward-codecs on main. Caveats: upstream main 645d4fe14a20 (2026-10-28) still carries the lines [read]; all runs used JDK 25 on Linux aarch64",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-941.html",
   "repro": "repro/LFV-941/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-255",
   "priority": "low",
   "priority_rank": 1148,
   "novelty": "new",
   "withheld": false,
   "area": "codecs / term vectors (Lucene90TermVectorsFormat .tvd file-format javadoc vs Lucene90CompressingTermVectorsWriter / Reader)",
   "title": "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)",
   "summary": "You decode a .tvd chunk of the default term-vectors format by following its javadoc, which says the Flags Bit is 1 when all fields of the chunk have the same options, that FieldNums is a delta-encoded list, and that AvgCharsPerTerm is absent unless some field has both positions and offsets. The writer does the opposite on all three: it writes 0 for 'same options' (then one flag per distinct field) and 1 otherwise, it stores the plain sorted field numbers (fields 1, 3, 6 are stored as 1, 3, 6, which summed as deltas give 1, 4, 10), and it writes one AvgCharsPerTerm value per distinct field whenever any field has offsets, so a parser built from the text misreads the chunk. Lucene's own reader matches the writer, so nothing breaks at runtime; only the documentation is wrong, and it has been since it was written in 2013.",
   "impact_class": "minor",
   "introduced_commit": "94b17a28de5280a2963ed70a8f5d3a8ee0590cd6 (trunk, svn r1441732) / e3710747d87ad6b89341d1f7de57577c0b301a89 (branch_4x, svn r1441760), LUCENE-4733 'Make CompressingTermVectorsFormat the new default term vectors format' (now apache/lucene#5798; JIRA patch LUCENE-4733-javadocs.patch, no GitHub PR), by jpountz [read]. The writer it describes came 12 days earlier (5837fe83bd8 trunk / 4a62a579a70 branch_4x, LUCENE-4599, apache/lucene#5664) and is byte-identical at 94b17a28de5, with today's encoding for all three statements, so the text never matched a committed encoding; not a regression. The text was copied unchanged into Lucene50TermVectorsFormat (33bdf278cba, LUCENE-5969, 5.0.0) and Lucene90TermVectorsFormat (f8be421ae1f, LUCENE-9705, apache/lucene-solr#2334, 9.0.0), and re-laid out without correction by 891b192dcff (apache/lucene#129, LUCENE-9456) and 6ebf959502c (apache/lucene#130), so git blame on main points at #130. 'FieldNumDelta' predates LUCENE-4733 (term-vector format docs of 12eee6df5a9, 2004); that the name was inherited is an inference from the code",
   "introduced_date": "2013-02-02",
   "first_affected_version": "4.2.0 [exec] (Lucene42TermVectorsFormat: the version-specific byte-level probe finds all 3 statements contradicted and its reader-rule control passes; 4.1.0 has neither CompressingTermVectorsFormat nor Lucene42TermVectorsFormat [exec], so the format and its description did not exist); 9.0.0 [exec] for Lucene90TermVectorsFormat",
   "affected_versions": "every release from 4.2.0 through 10.6.0 and main ea57360912ed through 645d4fe14a2 [exec]; not fixed upstream [exec]. Caveats: 8.8.2-8.11.3 are not in the clone and are counted as affected by inference from 8.8.1 [read] and 8.11.4 [exec]; upstream main, branch_10x, branch_10_6 and branch_9_12 hold the same file blob as main ea57360912ed (GitHub API, 2026-10-26); all runs used JDK 25",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-255.html",
   "repro": "repro/LFV-255/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  },
  {
   "id": "LFV-957",
   "priority": "low",
   "priority_rank": 1149,
   "novelty": "new",
   "withheld": false,
   "area": "release notes / lucene/CHANGES.txt 10.6.0 Improvements (CheckIndex / CorruptSegmentInfoException entry, GITHUB#7820)",
   "title": "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)",
   "summary": "You read the Lucene 10.6.0 release notes (CHANGES.txt or the generated Changes.html of RC1) and follow the issue link of the entry 'CheckIndex now reports which segment's .si file could not be read'. You expect it to lead to GITHUB#7820, the issue the feature commit, CheckIndex.java and main's copy of the entry all name; instead the entry says GITHUB#17820 and its GitHub issue link (number 17820) returns 404. The extra digit was added when #16788 was backported to branch_10x and branch_10_6 (main's commit of the same PR kept 7820), and it ships in the RC1 source release.",
   "impact_class": "minor",
   "introduced_commit": "1b61ada0305 (branch_10_6, the 10.6.0 RC1 line) and its twin 081f0abb6e3 (branch_10x): the direct-push backports (no PRs of their own) of apache/lucene#16788 'SegmentInfos: Ensure IOExceptions are not hidden behind CorruptSegmentInfoException' (authored by Alexander Reelsen, pushed by Alan Woodward). Their identical CHANGES hunk changes '* GITHUB#7820:' to '* GITHUB#17820:' while adding the #16788 wording and credit; main's commit of the same PR, 330ee57b167, keeps GITHUB#7820 [exec]. The entry itself was correct since the feature commit f30bd1b9b4f (#16476, main, 2026-10-05), its branch_10x backport 6758e9c3c5c and the branch_10_6 cut 3e416dce059 [exec]",
   "introduced_date": "2026-10-22 (commit dates: branch_10x 081f0abb6e3 2026-10-22, branch_10_6 1b61ada0305 2026-10-22; both carry the #16788 author date 2026-10-21, which main's correct 330ee57b167 shares, so the author date does not date the typo)",
   "first_affected_version": "10.6.0 (released 2026-10-29 from RC1, built from branch_10_6 4ae946e5a9b; tag releases/lucene/10.6.0). The entry and the CorruptSegmentInfoException feature are new in 10.6.0, so no earlier release can carry the wrong number [exec]",
   "affected_versions": "10.6.0 RC1 [exec]; branch_10_6 from 1b61ada0305 to its head 91eaab4fb29 (line 119 on 2026-11-01; line 112 in RC1 4ae946e5a9b) and branch_10x from 081f0abb6e3 to its last head 657014b3c57 (line 138; #16911 decommissioned the branch on 2026-10-29) [exec]. Not affected: main at every commit checked (f30bd1b9b4f, 330ee57b167, 7cecf795236, a9779ef3c193 line 552, upstream head 645d4fe14a2 line 562: GITHUB#7820) [exec]; branch_10_6 before 1b61ada0305 (3e416dce059, 88c0bd4c346) and branch_10x before 081f0abb6e3 (6758e9c3c5c, 9f18a6bceea) [exec]; 9.x and 10.0.0-10.5.2 (entry absent) [exec]. Main's copy of the entry has the older pre-#16788 wording (from the release-manager sync 7cecf795236, which ran before the backports); that is an expected interim state, not a separate defect. All runs JDK 25.0.3 on Linux aarch64; the checks read only text, so the classpath and -ea/-da do not change the result",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-957.html",
   "repro": "repro/LFV-957/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b): CHANGES.txt cites a GitHub issue number (17820) that does not exist (both checks fail); 10.5.2 does not have the entry."
  },
  {
   "id": "LFV-1087",
   "priority": "low",
   "priority_rank": 1150,
   "novelty": "new",
   "withheld": false,
   "area": "build-tools / documentation build (DocumentationConfigPlugin.MarkdownTemplateTask.withProjectList: the 'API Javadocs' list of the documentation front page docs/index.html)",
   "title": "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)",
   "summary": "You open the front page of the Lucene 10.6.0 documentation (docs/index.html in the binary release, or a documentation build of main) and click benchmark-jmh in its 'API Javadocs' list. You expect that module's javadocs, as for the other 31 entries; instead the page does not exist, because benchmark-jmh's build disables its site javadocs ('No special javadocs for JMH benchmarks') and the Java port of the documentation build lists every module that has a renderSiteJavadoc task without checking that the task is enabled, which the Groovy build up to 10.5.2 did. Adding '&& t.getEnabled()' to that filter removes exactly this entry and nothing else.",
   "impact_class": "minor",
   "introduced_commit": "a0bd3c5f3c6 (apache/lucene#15350 'Move documentation gradle scripts to java', by dweiss, merged 2025-10-22, main) and its branch_10x backport f6fce7e42c5 (#16592 'Build infra modernization (backport)', by dweiss, merged 2026-09-05; the commit that put it in 10.6.0) [read] [exec]. Latent condition older than the bug: #12663 (603cd41ca1a, 2023-10-12, first released in 10.0.0) added lucene/benchmark-jmh with renderSiteJavadoc disabled and a published-project exclusion spelled ':lucene:benchmarks-jmh', so the module counts as published and gets the (disabled) task; in 10.0.0-10.5.2 the Groovy enabled filter hid it [exec].",
   "introduced_date": "2025-10-22 (a0bd3c5f3c6, author date = commit date 2025-10-22T14:08:45Z) on main; 2026-09-05 (f6fce7e42c5, author date = commit date 2026-09-05T09:48:44Z) on branch_10x",
   "first_affected_version": "10.6.0 [exec] (released 2026-10-29, revision 4ae946e5a9b: the test fails on the docs/ of the sha512-verified lucene-10.6.0.tgz, -ea and -da; 10.5.2 passes)",
   "affected_versions": "10.6.0 (released 2026-10-29) [exec]; unreleased main 12.0.0-SNAPSHOT [exec], branch_11x [exec] and branch_10_6, the 10.6.1 line [exec]. Not affected: 10.0.0 to 10.5.2 [exec] and 9.x [exec].",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1087.html",
   "repro": "repro/LFV-1087/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 (4ae946e5a9b): the front-page link check fails 1 of 1 with -ea and -da on the release's docs/ (benchmark-jmh/index.html is listed but missing); 10.5.2 passes 1 of 1 with -ea and -da."
  },
  {
   "id": "LFV-1086",
   "priority": "low",
   "priority_rank": 1151,
   "novelty": "new",
   "withheld": false,
   "area": "build-tools / documentation build (DocumentationConfigPlugin createDocumentationIndex template binding; lucene/documentation index.template.md)",
   "title": "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)",
   "summary": "You open the documentation front page of Lucene 10.6.0 (docs/index.html) and read the Migration Guide entry. You expect 'What changed in Lucene 10; how to migrate code from Lucene 9.x.', as 10.5.2 says, because the template computes the previous major as ${project.majorVersion-1}; instead it says 'how to migrate code from Lucene 0.x.' (a main build says 'Lucene 12; ... from Lucene 2.x.'). Since the build's version globals became Java (#14862 on main, backported to 10.x in #16592), the template gets majorVersion as the String '10', and Groovy's String minus 1 deletes the first '1' character instead of subtracting; binding the value as an int restores 'from Lucene 9.x' (main: '11.x').",
   "impact_class": "minor",
   "introduced_commit": "a7fc3d0ae8314ebf1236eea3076096b836d19ca8 (apache/lucene#14862 'Gradle plugins to java, batch 1' by dweiss, main; PR text 'no functional changes are expected'): it replaced the build's int majorVersion ('\"majorVersion\" is an integer with just the major version', 'm[0][1] as int') with LuceneBuildGlobalsExtension's 'public String majorVersion' [read]. a0bd3c5f3c6 (#15350, 2025-10-22) carried the same String into the Java documentation task (DocumentationConfigPlugin: Map.entry(\"majorVersion\", buildGlobals.majorVersion)). On the 10.x line it arrived with f6fce7e42c5 (#16592 'Build infra modernization (backport)' by dweiss, branch_10x) [exec]. The template line and its int closure date from LUCENE-9321 (06df50e759a, 2020-05-17, first in 9.0.0; LUCENE-9577 only moved the template) and were correct until then; #14764 (42123980c25, 2025-06-14) changed the template to ${project.majorVersion-1} while the value was still an int, which was harmless [exec]. A regression of the build's value type, not a day-one bug",
   "introduced_date": "2025-07-01 on main (a7fc3d0ae83, author date = commit date 2025-07-01T11:34:44+02:00); 2026-09-05 on branch_10x (f6fce7e42c5, author date = commit date 2026-09-05T11:48:44+02:00)",
   "first_affected_version": "10.6.0 [exec] (released 2026-10-29; the only release tag that contains f6fce7e42c5); last unaffected 10.5.2 [exec]",
   "affected_versions": "10.6.0 (released 2026-10-29, tag releases/lucene/10.6.0 -> 4ae946e5a9b) [exec]; unreleased main since a7fc3d0ae83 [exec], branch_11x [exec], branch_10_6, the 10.6.1 line [exec] and branch_10x since f6fce7e42c5 [exec]. Not affected: every release 9.0.0 to 10.5.2 [read]. The 10.6.0 site page (lucene.apache.org/core/10_6_0/index.html) was not yet published on 2026-11-02 (HTTP 404, while 10_6_0/MIGRATE.html is live), so today the text ships in the binary distribution's docs/ and reaches the site when the page is published",
   "security": "none",
   "upstream_links": [],
   "doc": "bugs/LFV-1086.html",
   "repro": "repro/LFV-1086/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": true,
   "new_in_10_6_note": "10.6.0 RC1 (4ae946e5a9b, the released 10.6.0): its docs/index.html fails the test with -ea and -da ('from Lucene 0.x'); the 10.5.2 release page passes with -ea and -da ('from Lucene 9.x')."
  },
  {
   "id": "LFV-040",
   "priority": "low",
   "priority_rank": 1152,
   "novelty": "known",
   "withheld": false,
   "area": "index / deletion policies",
   "title": "PersistentSnapshotDeletionPolicy.getLastSaveFile reads nextWriteGen without synchronization (benign data race)",
   "summary": "You call getLastSaveFile while other threads snapshot or release commits. You expect the latest save file. Instead it reads nextWriteGen without synchronization and can see a stale value; persistence itself is unaffected.",
   "impact_class": "minor",
   "introduced_commit": "efeaac746ae1 (LUCENE-4976)",
   "introduced_date": "2013-05-03",
   "first_affected_version": "unknown (not yet bisected)",
   "affected_versions": "since 2013 [read]; main [exec]",
   "security": "none",
   "upstream_links": [
    "https://github.com/apache/lucene/issues/16482"
   ],
   "doc": "",
   "repro": "repro/LFV-040/",
   "triage_status": "",
   "triage_by": "",
   "triage_date": "",
   "triage_link": "",
   "triage_note": "",
   "triage_hide": false,
   "new_in_10_6": false,
   "new_in_10_6_note": ""
  }
 ],
 "notes": [
  "AI-assisted findings; apart from the rows with a maintainer triage (the triage_* fields), not yet triaged by a human Lucene committer; this site files nothing upstream.",
  "Withheld rows keep only id, the module part of the area, priority, novelty and the withheld line.",
  "Rows are in the table's order: by priority tier, then by rank among the rows shown in full; the withheld rows of a tier follow, by id."
 ]
}
