All findings · Lucene finding · LFV-1021 · upgradeindexmergepolicy-javadoc-example-uses-removed-iwc-version-ctor

UpgradeIndexMergePolicy's javadoc example calls an IndexWriterConfig constructor removed in Lucene 5.0

The only code example in the UpgradeIndexMergePolicy class javadoc starts with new IndexWriterConfig(Version.LUCENE_XX, new KeywordAnalyzer()), but IndexWriterConfig has not taken a Version since 5.0.0. Copied as shown, the example does not compile on any release from 5.0.0 to 10.6.0, whatever real version you put in for LUCENE_XX.

Summary

Priority
Low, rank 1257The UpgradeIndexMergePolicy example has failed loudly at compile time since 5.0, but the class is experimental and its javadoc points readers to IndexUpgrader, so few copy it.
Impact
minor
Since
5.0.0 (the example was valid in 3.2.0 to 4.10.4)introduced 2014-08-09 · over 12 years
Affected
5.0.0 to 10.6.0, and main (documentation only)
Status
documented
Found by
a compile check of javadoc code examples (non-formal)

AI-assisted page: this finding was first signalled by code reading or testing and then checked with AI tools; the checks it went through, and what each found, are under Prior reports, history and checks. Not yet triaged by a human. Snapshot of 2026-11-06.

The finding in 30 seconds

The example sits in a <pre><code> block of the class javadoc. Javadoc does not compile such blocks, so when IndexWriterConfig lost its Version argument in 5.0.0, nothing failed here.

Summary card of the bug, four steps left to right. 1, the user copies the only code example of the class javadoc: new IndexWriterConfig(Version.LUCENE_XX, new KeywordAnalyzer()) (javadoc line 37). 2, javac matches it: 2 arguments, but the constructors take 0 or 1, IndexWriterConfig() and IndexWriterConfig(Analyzer): no suitable constructor, with any version constant. 3, removed in 2014: LUCENE-5871 removed the Version argument in 451 files, including IndexUpgrader, but not this javadoc; stale since 5.0.0 (4.10.4 still compiles). 4, the fix: drop the Version argument, new IndexWriterConfig(new KeywordAnalyzer()), which compiles and upgrades all 5 segments of a 10.0.0 index (javadoc only). Expected: the copied example compiles, and forceMerge(1) rewrites the old segments to the current version. Actual: compile error, nothing runs; javac: no suitable constructor found for IndexWriterConfig(Version,KeywordAnalyzer). Footer: documentation only, the error is loud and javac lists IndexWriterConfig(Analyzer) as a candidate; an opt-in, @lucene.experimental merge policy that main's MIGRATE.md names as an upgrade option; stale in 5.0.0 to 10.6.0 and on main; executed on main 645d4fe14a20; without the Version argument the block merges the 5 old segments of a 10.0.0 index into one 11.0.0 segment and numDocs stays 35.
The javadoc example next to the real IndexWriterConfig constructors: the example passes two arguments, and since 5.0.0 only () and (Analyzer) exist. Without the Version argument it compiles and upgrades a 10.0.0 index. Select the still to open it at full size. Generated with AI, checked against the code.
  1. You want to upgrade an old index yourself, so you open the UpgradeIndexMergePolicy javadoc. It says "for a fully customizable upgrade, you can use this like any other MergePolicy and call forceMerge" and shows five lines.
  2. You copy them and put a real constant, say Version.LATEST, in for the LUCENE_XX placeholder. You expect the code to compile and forceMerge(1) to rewrite the old segments.
  3. Instead javac stops on the first line: no suitable constructor found for IndexWriterConfig(Version, KeywordAnalyzer). IndexWriterConfig has only two constructors, () and (Analyzer), so no version constant can help.
  4. The two-argument constructor was removed in 2014 (LUCENE-5871, released in 5.0.0); that change updated IndexUpgrader but not this javadoc. Without the Version argument, the same five lines compile and upgrade every segment of a 10.0.0 index, and the live-document count stays the same.

Who is affected

Developers doing a custom index upgrade with this opt-in, experimental policy who start from its only example: one compile error every time, on 5.0.0 to 10.6.0 and main. Main's migration guide now names the class as an upgrade option. Documentation only: nothing runs differently.

Mechanism, terms and numbers349 words

UpgradeIndexMergePolicy (@lucene.experimental) is the merge policy that rewrites segments written by older Lucene versions when you call forceMerge; IndexUpgrader uses it internally. Its class javadoc says "In general one would use IndexUpgrader, but for a fully customizable upgrade, you can use this like any other MergePolicy and call IndexWriter#forceMerge(int):" and shows five lines. The first is IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_XX, new KeywordAnalyzer());. IndexWriterConfig has only IndexWriterConfig() and IndexWriterConfig(Analyzer), so the example fails with no suitable constructor found for IndexWriterConfig(Version,KeywordAnalyzer) on every release from 5.0.0 to 10.6.0 and on main, with any real constant in place of the placeholder. The example was written in 2011 and was valid then; LUCENE-5871 (2014) removed the Version argument across 451 files, including IndexUpgrader, and missed this javadoc. With new IndexWriterConfig(new KeywordAnalyzer()) the example compiles, and run on the 10.0.0 backward-compatibility index it rewrites every segment to the current version and leaves the live-document count (numDocs()) unchanged. Nothing in Lucene behaves wrongly; only the example is stale.

The example (main 645d4fe14a20, UpgradeIndexMergePolicy.java)

linetextexists?
33-34"In general one would use IndexUpgrader, but for a fully customizable upgrade, you can use this like any other MergePolicy and call IndexWriter#forceMerge(int):"(prose)
37IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_XX, new KeywordAnalyzer());no two-argument constructor
38iwc.setMergePolicy(new UpgradeIndexMergePolicy(iwc.getMergePolicy()));yes (line 59)
39-41new IndexWriter(dir, iwc), w.forceMerge(1), w.close()yes

The real constructors

IndexWriterConfig.java:141 public IndexWriterConfig() (uses StandardAnalyzer) and :151 public IndexWriterConfig(Analyzer analyzer). The error is about the number of arguments, not the placeholder: javac fails the same way with Version.LATEST and with Version.LUCENE_10_0_0. On main this javadoc line is the only IndexWriterConfig(Version and the only LUCENE_XX left under lucene/.

Why nothing caught it

Javadoc does not compile <pre><code> blocks. IndexUpgrader, which LUCENE-5871 did update, builds its own config with new IndexWriterConfig(null) (IndexUpgrader.java:138).

Not claimed

The placeholder LUCENE_XX itself (the reader is meant to pick a version), the undeclared dir and the missing imports and exception handling (normal for a fragment); the test fills these in, visibly. No runtime defect.

Exposure and likelihood118 words
  • Who. Readers of the UpgradeIndexMergePolicy class javadoc who copy its example. No query, document or index file reaches it.
  • Default vs opt-in. The policy is opt-in and @lucene.experimental, and the javadoc points most users to IndexUpgrader. No configuration or special input is involved: the copied example always fails.
  • Scale. One error on every release from 5.0.0 (February 2015) to 10.6.0, and on main.
  • Slightly more relevant on main. MIGRATE.md's "Relaxed Index Upgrade Policy" section tells users upgrading old indexes: "Optional: Call forceMerge() or use UpgradeIndexMergePolicy to upgrade segment formats immediately".
  • Effect. A compile error, not wrong behaviour; javac lists IndexWriterConfig(Analyzer) as an alternative.
  • Priority. Low; the same kind of defect as other stale javadoc examples.

Minimal repro

One JUnit class with one test. It compiles the five javadoc lines with javax.tools against the jars on the test class path; it adds only the imports, an enclosing class and the dir parameter, and puts Version.LATEST in for the placeholder, visibly. No Lucene indexing or search code runs, and nothing is random.

TestUpgradeIndexMergePolicyJavadocExample.java (one test, public API)66 lines
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.lucene.index;

import java.net.URI;
import java.util.List;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;
import org.apache.lucene.tests.util.LuceneTestCase;

public class TestUpgradeIndexMergePolicyJavadocExample extends LuceneTestCase {

  // Expected: the class-javadoc example compiles (LUCENE_XX -> LATEST); actual: no IndexWriterConfig(Version, Analyzer).
  public void testClassJavadocExampleCompiles() throws Exception {
    String source =
        """
        import org.apache.lucene.analysis.core.KeywordAnalyzer;
        import org.apache.lucene.index.*;
        import org.apache.lucene.store.Directory;
        import org.apache.lucene.util.Version;
        class Example {
          void example(Directory dir) throws Exception {
        IndexWriterConfig iwc = new IndexWriterConfig(Version.LATEST, new KeywordAnalyzer());
        iwc.setMergePolicy(new UpgradeIndexMergePolicy(iwc.getMergePolicy()));
        IndexWriter w = new IndexWriter(dir, iwc);
        w.forceMerge(1);
        w.close();
          }
        }
        """;
    JavaFileObject unit =
        new SimpleJavaFileObject(URI.create("string:///Example.java"), JavaFileObject.Kind.SOURCE) {
          @Override
          public CharSequence getCharContent(boolean ignoreEncodingErrors) {
            return source;
          }
        };
    DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
    List<String> options =
        List.of(
            "-classpath", System.getProperty("java.class.path"),
            "-d", createTempDir().toString(),
            "-proc:none");
    boolean compiled =
        ToolProvider.getSystemJavaCompiler()
            .getTask(null, null, diagnostics, options, null, List.of(unit))
            .call();
    assertTrue(diagnostics.getDiagnostics().toString(), compiled);
  }
}
Command
# $LUCENE: a built checkout (./gradlew jar); $REPRO: the directory holding org/apache/lucene/index/Test...java
# $DEPS: junit 4.13.2, randomizedtesting-runner 2.9.2, hamcrest 3.0
V=11.0.0-SNAPSHOT
CP=$LUCENE/lucene/core/build/libs/lucene-core-$V.jar:$LUCENE/lucene/codecs/build/libs/lucene-codecs-$V.jar:$LUCENE/lucene/analysis/common/build/libs/lucene-analysis-common-$V.jar:$LUCENE/lucene/test-framework/build/libs/lucene-test-framework-$V.jar:$DEPS
javac -d out -cp "$CP" $REPRO/org/apache/lucene/index/TestUpgradeIndexMergePolicyJavadocExample.java
java -ea -Dtests.seed=DEADBEEF -cp "out:$CP" org.junit.runner.JUnitCore org.apache.lucene.index.TestUpgradeIndexMergePolicyJavadocExample
# assertions off, same result: java -da -Dtests.asserts=false ...
Expected
The copied example compiles (with a real version in for LUCENE_XX).
Observed
One javac error, no suitable constructor found for IndexWriterConfig(Version,KeywordAnalyzer), with assertions on and off, on main and on the 10.6.0 jars.

All files of this repro: repro/LFV-1021/

More files, environment, full output248 words

The block in the test was checked mechanically against UpgradeIndexMergePolicy.java:37-41 at 645d4fe14a20: it is verbatim apart from Version.LUCENE_XX -> Version.LATEST.

/Example.java:7 in the output is line 7 of the compiled snippet, which is line 37 of UpgradeIndexMergePolicy.java. lucene-codecs is on the class path because the test framework loads SimpleTextCodec (without it the run stops in LuceneTestCase's static initializer with NoClassDefFoundError); lucene-analysis-common holds KeywordAnalyzer.

No separate regression test is suggested: this test copies the example, so it would not notice a later edit of the javadoc, and Lucene has no harness that compiles javadoc examples (LUCENE-8488, #9534).

Environment

lucenemain 645d4fe14a20 (11.0.0-SNAPSHOT); the 10.6.0 release jars give the same error
jdkOpenJDK 25.0.3 (build 25.0.3+9-LTS)
osLinux aarch64 (the only platform run; the defect is a source-level constructor mismatch)

Observed output

# the command above, main 645d4fe14a20, seed DEADBEEF, -ea (-da identical); lines in order; left out: the banner (ending in Time: 1.165), the remaining runner frames (...) and the script's closing EXIT=1
There was 1 failure:
1) testClassJavadocExampleCompiles(org.apache.lucene.index.TestUpgradeIndexMergePolicyJavadocExample)
java.lang.AssertionError: [/Example.java:7: error: no suitable constructor found for IndexWriterConfig(org.apache.lucene.util.Version,org.apache.lucene.analysis.core.KeywordAnalyzer)
IndexWriterConfig iwc = new IndexWriterConfig(Version.LATEST, new KeywordAnalyzer());
                        ^
    constructor org.apache.lucene.index.IndexWriterConfig.IndexWriterConfig() is not applicable
      (actual and formal argument lists differ in length)
    constructor org.apache.lucene.index.IndexWriterConfig.IndexWriterConfig(org.apache.lucene.analysis.Analyzer) is not applicable
      (actual and formal argument lists differ in length)]
	at __randomizedtesting.SeedInfo.seed([DEADBEEF:9A7EBD6A0F12FB11]:0)
	at org.junit.Assert.fail(Assert.java:89)
	at org.junit.Assert.assertTrue(Assert.java:42)
	at org.apache.lucene.index.TestUpgradeIndexMergePolicyJavadocExample.testClassJavadocExampleCompiles(TestUpgradeIndexMergePolicyJavadocExample.java:64)
	...
FAILURES!!!
Tests run: 1,  Failures: 1

# the same test on the 10.6.0 release jars, -da: tests_run=1 failures=1, the same single diagnostic

Why it looks unintended

  • The javadoc offers the block as the way to do "a fully customizable upgrade", and every other line in it exists.
  • It was valid when written (2011) and broke by omission: LUCENE-5871 updated 451 files, including IndexUpgrader, but not this one.
  • The same change's javadoc follow-up fixed the identical stale call in core's overview.html.
The full argument198 words
  • Offered as working code. "for a fully customizable upgrade, you can use this like any other MergePolicy and call IndexWriter#forceMerge(int):", then the example.
  • History. LUCENE-3082 (#4155, Uwe Schindler, 2011-05-09) added the class and the example (600a50bb2ae on trunk, first released in 4.0.0; 535d974518b on branch_3x, which reached 3.2.0); IndexWriterConfig(Version, Analyzer) existed then (3.1.0 to 4.10.4). LUCENE-5871 (872bd9145cd, #6933, Ryan Ernst, 2014-08-09) replaced it with IndexWriterConfig(Analyzer) in 451 files, including IndexUpgrader.java, not this one.
  • The project fixed the same call elsewhere. 5e5072d3c2d ("LUCENE-5859, LUCENE-5871: Remove Version.LUCENE_CURRENT from javadocs", Steven Rowe, 2014-08-21) changed new IndexWriterConfig(Version.LUCENE_CURRENT, analyzer) to new IndexWriterConfig(analyzer) in overview.html, the only file it changed. Its title targets Version.LUCENE_CURRENT; this example uses the placeholder LUCENE_XX, which is most likely why it was missed (an inference: how the sweep was done is not recorded).
  • No record accepts it. No issue, PR, CHANGES or MIGRATE text calls the example deliberate; the 25 comments on #6933 never mention the class.
  • Precedent. Issue #12666 (a stale Analyzer class-javadoc example) was fixed by PR #12693, merged by msokolov on 2023-10-18 as an ordinary doc fix. The open outside PR #16949 is a current batch of such fixes.
The devil's-advocate check179 words

Strongest case for "intended" or "noise": the block is schematic (LUCENE_XX is not a constant, dir is undeclared; Uwe Schindler used the same placeholder line as an API sketch on #4155); the class is @lucene.experimental and the javadoc says "In general one would use IndexUpgrader"; Lucene does not compile javadoc code, and the error is loud with the right constructor named; committers edited this javadoc twice in 2026 (#15573 markup, #16255 a typo fix in the sentence just above the example, line 33) and left the example alone.

Why it fails: the placeholder asks for a version, but no version makes a two-argument call to a one-argument constructor compile. Experimental status allows API change; it does not make the class's own example right. The 2026 edits were sweeps over 252 and 282 files. The project fixed the identical call in overview.html in 2014, and main's MIGRATE.md now sends upgrading users to this class. Every verifier and the adjudication called it real; it was kept at Low as "a removed-API call with concrete copy-paste impact (not a wording slip)".

Suggested fix

Recommended Drop the Version argument in the example (validated)

Drop the Version argument: new IndexWriterConfig(new KeywordAnalyzer()) (javadoc only, one line). Validated: the patched example compiles on main and on 10.6.0, upgrades every segment of a 10.0.0 index with the live-document count unchanged, and TestUpgradeIndexMergePolicy passes.

- *  IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_XX, new KeywordAnalyzer());
+ *  IndexWriterConfig iwc = new IndexWriterConfig(new KeywordAnalyzer());
All options and trade-offs3 options ยท 319 words

One fix was validated, with the one-line diff applied to 645d4fe14a20; the alternatives were not run.

Drop the Version argument in the example (validated) (recommended)

Javadoc only, lucene/core/src/java/org/apache/lucene/index/UpgradeIndexMergePolicy.java:37.

- *  IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_XX, new KeywordAnalyzer());
+ *  IndexWriterConfig iwc = new IndexWriterConfig(new KeywordAnalyzer());

Trade-offs

None for users: documentation only, and no CHANGES entry is strictly needed. It keeps the author's KeywordAnalyzer (an analysis-common class named in a core javadoc, as before); a maintainer may prefer the next option for that reason. Any backport is the maintainers' call.

What the checks validated

  • The example block extracted from the patched file (which differs from 645d4fe14a20 only on line 37), compiled by the same one-test check: passes 1 of 1 on main with assertions on and off and on the 10.6.0 jars. The stock block fails the same test, so the test detects the bug.
  • A separate control runs the corrected five lines on the 10.0.0 backward-compatibility index: every segment is rewritten to Version.LATEST and numDocs() is unchanged (assertions on and off). It runs the corrected Java lines; the rendered page is checked by renderJavadoc (next item).
  • ./gradlew :lucene:core:test --tests "org.apache.lucene.index.TestUpgradeIndexMergePolicy" -Ptests.seed=DEADBEEF: 5 tests, 0 failures, 1 skipped (testSimulateAppendOnly, inherited from BaseMergePolicyTestCase, where it is @Nightly).
  • ./gradlew :lucene:core:checkGoogleJavaFormat and :lucene:core:renderJavadoc pass, and the rendered class page shows new IndexWriterConfig(new KeywordAnalyzer()) and no LUCENE_XX.

Use new IndexWriterConfig() or new IndexWriterConfig(null) (not run)

An upgrade adds no documents, so the analyzer does not matter; IndexUpgrader itself uses new IndexWriterConfig(null), and new IndexWriterConfig() stays inside core.

Trade-offs

A slightly larger rewrite of the example, and just as valid; neither variant was compiled or run here.

Follow-up: compile-check javadoc examples

The generic wish of LUCENE-8488 (#9534, "Javadoc examples should be kept in sync with actual compiled code", open).

Trade-offs

Would stop this class of drift, but it is a build-infrastructure change, not part of this fix.

How it was found

No formal method. A probe compiled javadoc code examples against the main jars and hit this error; the hunt then extracted the block mechanically, checked in 159 core jars which API members exist, and wrote the one-test repro. Independent verifiers reproduced it with their own tests.

The method in full92 words
  • First signal. A probe compiled core, search, index and geo javadoc examples against the stock main 645d4fe14a20 jars and got the constructor error on this block (2026-10-29).
  • Hunt. A hunt unit for javadoc examples re-ran the lead, extracted the block mechanically, and ran a bytecode scan over 159 Lucene core jars for every API member the example calls, with boundaries cross-checked by javac. The scan finds IndexWriterConfig(Version, Analyzer) in 3.1.0 to 4.10.4 and in none of the 110 builds from 5.0.0 to main.
  • Tier. Non-formal: it compiles documentation code and scans jars.

Prior reports, history and checks

Prior reports

No prior report found (a search result, not a proof): GitHub issues and PRs (with the migrated JIRA archive), commits, the dev@, java-user@, issues@ and commits@ lists, downstream repositories and the web were searched on 2026-10-29; re-checked 2026-11-01. The open #16922 and its fix PR #16949 cover a different javadoc in the same file.

Searches3 searches

Related, not reports: #16922 (open, 2026-10-27: the shouldUpgradeSegment javadoc shows si.getVersion(), lines 63-66) and #16949 (open, its fix; edits line 65 only); #6933 (LUCENE-5871, made the example stale; never mentions the class); #4155 (wrote the example); #6945 and #15573 (later edits that left it alone); #15225, #4624 and #9534 (generic proposals for better or compiled examples).

Others file javadoc fixes almost daily (#16904, #16922, #16949), and #16949's author is sweeping stale snippets.

What was searched, when, and what turned up
WhereWhenHowFound
Scripted searches, 2 runs2026-10-2951 and 55 queries (identifiers; symptoms and LUCENE-5871) over GitHub issues, PRs and commits, downstream repositories, dev@, java-user@, issues@, commits@, the JIRA archive and the web#4155 and #6933 (origin), #16922 (different snippet), generic context
GitHub and lists, manual2026-10-2950 issue/PR phrasings (apache/lucene and GitHub-wide); commit search and the file's full history; the changed files of all 415 open PRs; direct lists.apache.org and JIRA queries; 13 web searchesno report; no open PR touched the file on main
Re-check2026-11-01issue and PR search for LUCENE_XX, UpgradeIndexMergePolicy, IndexWriterConfig(Version; the changed files of all 52 PRs updated since 2026-10-29; issues created since then; line 37 on main, branch_11x and branch_10_60 for LUCENE_XX; only #16949 touches the file (line 65, not 37); #16922 open with 0 comments; line 37 unchanged

History

Valid from 3.2.0 (2011) to 4.10.4; stale since LUCENE-5871 (872bd9145cd, 2014-08-09), which reached 5.0.0 through the branch_5x backport 55594bad9b0. Every release from 5.0.0 to 10.6.0 is affected.

Versions tested5 rows
  • 2011-05-09 600a50bb2ae (trunk) and 535d974518b (branch_3x) (LUCENE-3082, #4155, Uwe Schindler): the class and the example; first released in 3.2.0 through the branch_3x commit.
  • 2014-08-09 872bd9145cd (LUCENE-5871, #6933, Ryan Ernst): IndexWriterConfig(Version, Analyzer) becomes IndexWriterConfig(Analyzer); IndexUpgrader updated, this javadoc not.
  • 2014-08-21 5e5072d3c2d: the same stale call fixed in overview.html only.
  • 2014-09-18 55594bad9b0 (LUCENE-5944, branch_5x backport): brings the removal to 5.x; it is in the 5.0.0 tag, 872bd9145cd itself is not.
  • 2026 378ca8d1bbf (#15573) and 54283150a81 (#16255) edit the javadoc around the example and leave line 37 unchanged.
  • branch_10x, where the hunt found the same text, was decommissioned upstream on 2026-10-29 (#16911).
Versions and branches executed, with results
Version or commitVerdictResult
main 645d4fe14a20; upstream main f815e679bf6c affectedfails with the single error, -ea and -da (upstream main read, not run: line 37 unchanged)
10.6.0 affectedfails with the single error (release jars, -da)
10.5.2, 9.12.3 affectedfails with the same error
6.0.0, 5.0.0 affectedfails: the constructor cannot be applied to the given types
4.10.4 compilesnot affected: IndexWriterConfig(Version, Analyzer) still exists

Independent checks

A finder, an independent reproducer, a reviewer from another model family (OpenAI GPT-5.6) with lenses, a devil's-advocate check, an adjudication and an audit. All found it real; the adjudication confirmed it with high confidence as a Low documentation defect.

Checks and verdicts215 words

The refute review executed code on an older checkout whose javadoc text is identical; the intended-lens review could not run code, and the javac runs made for it are recorded separately.

Each independent check and its verdict
CheckVerdictWhat it found
Finder reproduced (doc)Bytecode scan of 159 core jars plus the compile check: fails on main (-ea, -da), 10.6.0 RC1, 10.5.2 and 9.12.3; the fix check and the runtime control pass.
Refute lens (OpenAI GPT-5.6) real, highReproduced with three seeds, -ea and -da; the fixed source passes; intended argument weak.
Reproducer realOwn test: fails on main (-ea, -da), 10.5.2 and 9.12.3; the control without the Version argument passes.
Intended lens (OpenAI GPT-5.6) real, mediumRead-only; intended argument weak. A separate javac run fails with LATEST and LUCENE_10_0_0 and passes with the fix.
Devil's advocate real, high (Low doc defect)Re-ran on main (-ea, -da) and 10.5.2; javap shows the constructor in 4.10.4 and not in 5.0.0; found the overview.html precedent.
Adjudication and audit confirmed (high), minorRe-ran on main (-ea and -da); the one-test repro fails and its fixed twin passes.
Brief verified; fix validatedMinimal test fails on main (-ea, -da) and on 10.6.0; the patched block passes; TestUpgradeIndexMergePolicy passes with the fix.

Diagram file

The diagram as a still image, generated with AI and checked against the code. It is under 10 MB, the limit for a GitHub attachment.

Sources and provenance

Finding record, Lucene and upstream sources, repro files and diagram notes1,378 words

Finding record

LFV-1021, snapshot of 2026-11-06

Registry 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)
Area
core / index (UpgradeIndexMergePolicy class javadoc example)
Priority
Low, rank 1257: The UpgradeIndexMergePolicy example has failed loudly at compile time since 5.0, but the class is experimental and its javadoc points readers to IndexUpgrader, so few copy it.
Impact class
minor
Impact note
Documentation only, with no runtime effect: a developer who does a custom index upgrade with this @lucene.experimental merge policy (the javadoc itself says 'In general one would use IndexUpgrader') and copies the class javadoc example gets a compile error on every release since 5.0.0, whatever real version constant they put in for the LUCENE_XX placeholder; dropping the Version argument fixes it, and no configuration, scale or special input is involved.
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.
Introduced
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: git log, git show, git blame and git merge-base --is-ancestor in the full-history clone; exec: release runs, see affected_versions] (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: 4.10.4 compiles; 5.0.0, 6.0.0, 9.12.3, 10.5.2, the 10.6.0 RC1 and main (-ea and -da) fail with the constructor error; the pre-9.0 runs use an import-only port of the test (LuceneTestCase package) and the junitcore runner] [read: a bytecode scan of 159 core jars finds IndexWriterConfig(Version, Analyzer) in 3.1.0-4.10.4 and in none of the 110 builds from 5.0.0 to main; the example text at line 37 is identical at 3.2, 3.6.2, 4.0.0, 4.10.4, 5.0.0, 6.0.0, 9.0.0, 9.12.3, 10.5.2 and main]. 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.
Status
documented (brief, checks and a per-finding doc exist)
Verification
Confirmed by AI-run checks: an independent repro, a cross-model review that agreed, an intended-behaviour check, a prior-report search and a skeptical audit; not yet triaged by a person.
Found by
non-formal
Upstream and prior reports
none found (searched 2026-10-29; the finder's, the independent reproduction's, the intended-behaviour check's and the adjudication's searches agree): two scripted search runs (51 and 55 queries over GitHub issues, PRs and commits, downstream repositories, the dev@, java-user@, issues@ and commits@ lists, the JIRA archive and the web; 0 errors), 50 manual GitHub search phrasings (apache/lucene and GitHub-wide, including the .NET port and three downstream search-engine repositories), GitHub commit search plus the full local history of the file, the changed files of all 415 open apache/lucene PRs (none touches UpgradeIndexMergePolicy.java on main; #16911 only deletes branch_10x), direct lists.apache.org and JIRA queries, 13 web searches and 22 issue reads with comments. Read but not the same bug: #16922 (open, by hidingmyname, 2026-10-27, 0 comments, no linked PR: the shouldUpgradeSegment method javadoc in the same file shows si.getVersion() where the code uses si.info.getVersion(), a different snippet, API and fix line (lines 63-66 vs 37); it does not mention the class example, IndexWriterConfig or LUCENE_XX), #6933 (LUCENE-5871, the change that made the example stale; its 25 comments never mention the class), #4155 (LUCENE-3082, wrote the example, valid then), #6945 (LUCENE-5883) and #15573 (later edits of the file that left the example as it was), #8722, #8574, #9052, #9311, #5626 and #8067 (behaviour of the class), #15225 and #4624 (generic proposals to check javadoc examples, naming none). Recheck: upstream main still 645d4fe14a20; line 37 still carries the call on main, branch_10x and branch_10_6; none of the 36 issues and PRs updated since 2026-10-28 names the class, LUCENE_XX or IndexWriterConfig(Version, and none of their 28 PRs changes UpgradeIndexMergePolicy.java; search 'LUCENE_XX' returns 0 and 'UpgradeIndexMergePolicy' still has #16922 as its newest item (0 comments, no cross-references). Tracking issue #16937 does not name it.
Lucene commit tested
main 645d4fe14a20 (2026-10-28): the minimal test fails with assertions on and off (standalone, with a plain javac/java command); the 10.6.0 release jars give the same single error; 4.10.4 (passes), 5.0.0, 6.0.0, 9.12.3 and 10.5.2 (fail) were run in the version-history runs. The fix was checked with the one-line diff applied to 645d4fe14a20: the patched example compiles on main and on 10.6.0, and TestUpgradeIndexMergePolicy passes (5 tests, 0 failures, one nightly test skipped); ./gradlew :lucene:core:checkGoogleJavaFormat and :lucene:core:renderJavadoc pass, and the rendered class page shows the corrected line. Upstream main f815e679bf6c (2026-11-01) was read, not run: line 37 is unchanged.

Lucene and upstream sources

Finding record
  • lucene/core/src/java/org/apache/lucene/index/UpgradeIndexMergePolicy.java:33-41 (class javadoc: 'for a fully customizable upgrade, you can use this like any other MergePolicy and call IndexWriter#forceMerge(int):' and the example, the stale call at :37), :50 (@lucene.experimental), :63-66 (the shouldUpgradeSegment javadoc of #16922); lucene/core/src/java/org/apache/lucene/index/IndexWriterConfig.java:141, :151 (the only constructors, () and (Analyzer))
The finding in 30 seconds
  • a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/index/UpgradeIndexMergePolicy.java:26-52 (class javadoc; :33-34 prose, :36 <pre><code class="language-java">, :37 the stale call, :38-41, :50 @lucene.experimental), :59 (UpgradeIndexMergePolicy(MergePolicy))
  • a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/index/IndexWriterConfig.java:141, :151 (the only constructors)
  • a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/index/IndexUpgrader.java:138, :148 (new IndexWriterConfig(null)), :180 (setMergePolicy(new UpgradeIndexMergePolicy(...)))
  • a Lucene main checkout (645d4fe14a20): git grep 'LUCENE_XX' and 'IndexWriterConfig(Version' over lucene/ (only lucene/core/src/java/org/apache/lucene/index/UpgradeIndexMergePolicy.java:37)
Who is affected
  • a Lucene main checkout (645d4fe14a20) lucene/MIGRATE.md:136 (Relaxed Index Upgrade Policy), :153 (UpgradeIndexMergePolicy named)
Why it looks unintended
  • a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/index/UpgradeIndexMergePolicy.java:33-41
  • a Lucene clone: releases/lucene-solr/4.10.4 IndexWriterConfig.java:170 (IndexWriterConfig(Version matchVersion, Analyzer analyzer)); releases/lucene-solr/5.0.0 IndexWriterConfig.java:162 (only IndexWriterConfig(Analyzer))
  • a Lucene clone: git merge-base --is-ancestor: 535d974518b (branch_3x, LUCENE-3082) in releases/lucene-solr/3.2, 600a50bb2ae (trunk) not; 600a50bb2ae in releases/lucene-solr/4.0.0
Suggested fix
  • a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/index/IndexUpgrader.java:138 (new IndexWriterConfig(null))
  • GitHub API (read-only, 2026-11-01): issue #9534 title and state (open)
  • a Lucene main checkout (645d4fe14a20) lucene/test-framework/src/java/org/apache/lucene/tests/index/BaseMergePolicyTestCase.java:412-413 (@Nightly testSimulateAppendOnly); lucene/core/src/test/org/apache/lucene/index/TestUpgradeIndexMergePolicy.java:24 (extends BaseMergePolicyTestCase)
History
  • a Lucene clone: git merge-base --is-ancestor: 55594bad9b0 in releases/lucene-solr/5.0.0, 872bd9145cd not; releases/lucene-solr/5.0.0 UpgradeIndexMergePolicy.java:37 (same stale line)

Other statements trace to the hunt's working files (models, logs, reviews and briefs), which are not published.

Repro files

About the diagrams

Made from executed runs on main 645d4fe14a20: the diagram's own probe compiled the copied block (with LATEST and with LUCENE_10_0_0) and the corrected block, and ran the corrected block on the 10.0.0 backward-compatibility index; the release results are the brief's and the follow-up's runs. Every value on screen is asserted against those outputs and source snapshots. The PNG is the summary frame.

Built 2026-11-06 from the hunt's record of this finding and its doc file. Lucene main under test in this hunt: ea57360912ed. Every listed finding was re-run on Lucene main e1faeba08bde on 2026-11-02.