Three of the overview's five examples call APIs that were removed or changed after the page was written.
- An FST (finite state transducer) maps sorted keys to outputs in a compact byte array; Lucene uses FSTs for its terms index, synonyms and suggesters. The
org.apache.lucene.util.fstclasses (FSTCompilerbuilds one,FSTholds it,Utilqueries it) let you build your own; they are marked@lucene.experimental. - The package overview, the javadoc of the package's
package-info.java, is the one place that shows the whole flow end to end: five code blocks that share one FST of cat=5, dog=7, dogs=12 and state their printed values in comments.
- You copy the five examples of the
org.apache.lucene.util.fstpackage overview into one method, in page order, adding only imports. They build an FST of cat=5, dog=7, dogs=12, look up "dog", look up the key whose value is 12, iterate, and ask for the 3 cheapest paths. - You expect it to compile against Lucene 10.5.2 or main and print what the comments say: 7, then dogs, then cat 5 and dog 7.
- Instead javac reports 6 errors in 3 of the 5 examples:
new FSTCompiler<Long>(INPUT_TYPE.BYTE1, outputs)(that public constructor was removed in 9.9.0),Util.getByOutput(fst, 12)(removed in 9.0.0, with no named replacement), and four reads of.input/.outputonUtil.Result(a record since 10.0.0, so onlyinput()/output()are public). - Why: the examples sit inside
<pre>in a javadoc comment, which nothing compiles. Three API changes updated every caller in the code but not the page; the 9.0.0 change even deleted the page's link togetByOutputand kept the example that calls it. - With
FSTCompiler.Builder, the record accessors and the lookup-by-value example removed, the page's own examples compile and print 7, the sorted pairs cat 5, dog 7, dogs 12, then cat 5, dog 7: the values in the page's comments, with the iteration's pairs in between.
Developers who build or query FSTs directly with the experimental util.fst API and start from the package overview, its one end-to-end example. Every copy fails to compile, on every release since 9.0.0, and the lookup-by-value example shows a feature that no longer exists. No runtime effect: nothing wrong ever runs.
Mechanism, terms and numbers604 words
The org.apache.lucene.util.fst package overview (package-info.java) is the package's only end-to-end usage example: five code blocks that share one FST built from cat=5, dog=7, dogs=12 (build it, look up a key, look up by value, iterate in sorted order, N shortest paths), with the printed values in comments. Copied in page order with only imports added, they fail to compile on main with 6 javac errors in 3 of the 5 blocks: the public FSTCompiler(INPUT_TYPE, Outputs) constructor was removed in 9.9.0 (#12715; FSTCompiler.Builder is the API), Util.getByOutput was removed in 9.0.0 (LUCENE-8638, #249, which deleted the page's link to it but kept the code block), and Util.Result became a record in 10.0.0 (#13328), so .input / .output are private and need input() / output(). No release since 9.0.0 ships a compiling version of the page (1 error in 9.0.0-9.8.0, 2 in 9.9.0-9.12.3, 6 in 10.0.0-10.6.0 and main). It is a documentation defect only: nothing wrong ever runs. With a javadoc-only fix (three corrections: Builder, accessors, drop the lookup-by-value block, which has no named replacement; plus a one-word comment update) the page's blocks compile and print the values in their comments, with the iteration's sorted pairs in between.
The page's code sits inside <pre><code> in a javadoc comment. The javadoc build checks {@link} targets but never compiles code inside <pre>, so three API changes that each updated their callers in code left the page behind:
page line (package-info.java) | example code | what changed | first release |
|---|---|---|---|
:45 (construction) | new FSTCompiler<Long>(INPUT_TYPE.BYTE1, outputs) | the only constructor is now private, with 7 parameters (FSTCompiler.java:161-168); the public way is new FSTCompiler.Builder<>(inputType, outputs).build() (:242, :260, :351). Removed by #12715 (CHANGES: "Remove public constructor of FSTCompiler. Please use FSTCompiler.Builder instead.") | 9.9.0 |
:66 (retrieval by value) | Util.getByOutput(fst, 12) | removed by LUCENE-8638 (#249, 666c7a25907; CHANGES: "Remove many deprecated methods and classes including FST.lookupByOutput()"), deprecated since 8.2.0; no public getByOutput-style method on main and no named replacement | 9.0.0 |
:92-95 (N shortest paths) | paths.topN.get(i).input / .output | Util.java:429 is public record Result<T>(IntsRef input, T output) {}: the components are private fields with public accessors input() / output() (#13328, 942065cc3e7; MIGRATE: "record's fields are only available with accessor methods"). TopResults.topN is still a public field (Util.java:442) | 10.0.0 |
666c7a25907 also deleted the overview's bullet {@link org.apache.lucene.util.fst.Util#getByOutput Lookup-by-output} when the outputs are in sorted order (e.g., ordinals or file pointers) (a dangling link fails the javadoc build) and kept the code block that calls it. #12831 (2024) later edited line 52 of the construction block for the new compile() API and left line 45.
The page's own blocks, extracted mechanically from package-info.java at 645d4fe14a20 (only imports added), compiled against the core jar of the same commit (condensed: javac's messages verbatim, file paths, source and caret lines, the reason: and type-variable lines dropped, lines mapped to page lines):
error: constructor FSTCompiler in class FSTCompiler<T> cannot be applied to given types; (line 45)
required: INPUT_TYPE,double,Outputs<Long>,boolean,DataOutput,float,int
found: INPUT_TYPE,PositiveIntOutputs
error: cannot find symbol symbol: method getByOutput(FST<Long>,int) location: class Util (line 66)
error: input has private access in Result (line 92)
error: output has private access in Result (line 93)
error: input has private access in Result (line 94)
error: output has private access in Result (line 95)
6 errorsThe other two blocks, "Retrieval by key" (:57-60) and "Iterate over key-value pairs in sorted order" (:72-80), compile and print 7 and the sorted pairs. The page's warning that keys must be added in Unicode code point order, not String.compareTo order (:38-40), is correct and unaffected.
Exposure and likelihood164 words
- Who. Users of
FSTCompiler,FST,UtilandBytesRefFSTEnumwho build a custom dictionary, suggester or term index and learn the API from the package overview. The published javadoc shows the same page: an independent verifier found the stale lines on the published 10.3.1 and 9.12.0 package-summary pages. - Default vs opt-in. No configuration is involved; anyone who copies the examples hits it, every time. The classes are
@lucene.experimental, an expert API, which is why the impact class is minor. - What they lose. Time: they have to find
FSTCompiler.Builderand the record accessors on their own (CHANGES and MIGRATE name them, the page does not). And a wrong belief: "Retrieval by value" advertises lookup by output, which the public API no longer offers. - Scale. 3 of 5 examples, 6 errors on main and all of 10.x; the page has not compiled as shipped in any release since 9.0.0 (2021).
- Not affected. Lucene's behaviour, results and indexes. javac names the missing members at once.
One JUnit class, one test, using Lucene's Java-public classes (two of them, BytesRefBuilder and IntsRefBuilder, are @lucene.internal) plus javax.tools. It holds the code lines of the three failing examples verbatim (comment-only lines left out), compiles them in-process and asserts that they compile. Run it with gradle as a core util.fst test, or against the built jars.
/*
* 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.util.fst;
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 TestFstPackageExamples extends LuceneTestCase {
// Expected: the package-info.java construction, by-value and shortest-paths examples compile; actual: 6 javac errors.
public void testPackageOverviewExamplesCompile() throws Exception {
String source =
"""
import java.util.Comparator;
import org.apache.lucene.util.*;
import org.apache.lucene.util.fst.*;
import org.apache.lucene.util.fst.FST.Arc;
import org.apache.lucene.util.fst.FST.INPUT_TYPE;
class Example {
void example() throws Exception {
String inputValues[] = {"cat", "dog", "dogs"};
long outputValues[] = {5, 7, 12};
PositiveIntOutputs outputs = PositiveIntOutputs.getSingleton();
FSTCompiler<Long> fstCompiler = new FSTCompiler<Long>(INPUT_TYPE.BYTE1, outputs);
BytesRefBuilder scratchBytes = new BytesRefBuilder();
IntsRefBuilder scratchInts = new IntsRefBuilder();
for (int i = 0; i < inputValues.length; i++) {
scratchBytes.copyChars(inputValues[i]);
fstCompiler.add(Util.toIntsRef(scratchBytes.toBytesRef(), scratchInts), outputValues[i]);
}
FST<Long> fst = FST.fromFSTReader(fstCompiler.compile(), fstCompiler.getFSTReader());
IntsRef key = Util.getByOutput(fst, 12);
System.out.println(Util.toBytesRef(key, scratchBytes).utf8ToString()); // dogs
Comparator<Long> comparator = new Comparator<Long>() {
public int compare(Long left, Long right) {
return left.compareTo(right);
}
};
Arc<Long> firstArc = fst.getFirstArc(new Arc<Long>());
Util.TopResults<Long> paths = Util.shortestPaths(fst, firstArc, fst.outputs.getNoOutput(), comparator, 3, true);
System.out.println(Util.toBytesRef(paths.topN.get(0).input, scratchBytes).utf8ToString()); // cat
System.out.println(paths.topN.get(0).output); // 5
System.out.println(Util.toBytesRef(paths.topN.get(1).input, scratchBytes).utf8ToString()); // dog
System.out.println(paths.topN.get(1).output); // 7
}
}
""";
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);
}
}
# copy the file into $LUCENE/lucene/core/src/test/org/apache/lucene/util/fst/, then:
./gradlew :lucene:core:test --tests org.apache.lucene.util.fst.TestFstPackageExamples -Ptests.seed=DEADBEEF
# assertions off: add -Ptests.asserts=false (not run under gradle; a standalone -da run fails the same way)
# or plain javac/java against the built jars; $DEPS = junit 4.13.2, randomizedtesting-runner 2.9.2, hamcrest 3.0
CP=$LUCENE/lucene/core/build/libs/lucene-core-11.0.0-SNAPSHOT.jar:$LUCENE/lucene/codecs/build/libs/lucene-codecs-11.0.0-SNAPSHOT.jar:$LUCENE/lucene/test-framework/build/libs/lucene-test-framework-11.0.0-SNAPSHOT.jar:$DEPS
javac -d out -cp "$CP" $REPRO/org/apache/lucene/util/fst/TestFstPackageExamples.java
java -ea -cp "out:$CP" -Dtests.seed=DEADBEEF org.junit.runner.JUnitCore org.apache.lucene.util.fst.TestFstPackageExamples
- Expected
- The three examples compile: javac reports no errors.
- Observed
- 6 javac errors: the FSTCompiler constructor cannot be applied, getByOutput is not found, and input/output have private access in Util.Result (4 times).
More files, environment, full output349 words
The test holds the code lines of the construction, retrieval-by-value and N-shortest-paths blocks verbatim and in page order from package-info.java (HTML entities decoded; the four comment-only lines 38-40 and 65 left out; 24 of the blocks' 28 non-blank lines, compared mechanically), adds only imports and an enclosing method, compiles them with javax.tools against the test's own classpath, and asserts that javac succeeds. No randomness, single thread; the seed does not matter. The two blocks that compile (retrieval by key, iteration) are left out to keep it minimal.
Under gradle, as an ordinary core test, it fails the same way: the assertion message is javac's diagnostic list, starting with the constructor error.
Regression test (optional): this same test with the three blocks as the fix rewrites them. It passes after the fix and fails again if FSTCompiler.Builder or the Util.Result accessors change shape; it cannot see later edits of the page itself, since the page is not on the test classpath. For a javadoc-only change a committer may not want a test at all. ./gradlew tidy (google-java-format) re-wraps its long comment line and the List.of(...) options; the test passes the lint and forbidden-APIs checks.
| lucene | main 645d4fe14a20 (11.0.0-SNAPSHOT); the published 10.5.2 and 10.6.0 jars fail with the same 6 errors, 9.12.3 with 2 |
|---|---|
| jdk | OpenJDK 25.0.3 (2026-04-21 LTS) |
| os | Linux aarch64 (the result does not depend on the platform) |
java.lang.AssertionError: [/Example.java:12: error: constructor FSTCompiler in class org.apache.lucene.util.fst.FSTCompiler<T> cannot be applied to given types;
FSTCompiler<Long> fstCompiler = new FSTCompiler<Long>(INPUT_TYPE.BYTE1, outputs);
^
required: org.apache.lucene.util.fst.FST.INPUT_TYPE,double,org.apache.lucene.util.fst.Outputs<java.lang.Long>,boolean,org.apache.lucene.store.DataOutput,float,int
found: org.apache.lucene.util.fst.FST.INPUT_TYPE,org.apache.lucene.util.fst.PositiveIntOutputs
reason: actual and formal argument lists differ in length, /Example.java:21: error: cannot find symbol
IntsRef key = Util.getByOutput(fst, 12);
^
symbol: method getByOutput(org.apache.lucene.util.fst.FST<java.lang.Long>,int)
location: class org.apache.lucene.util.fst.Util, /Example.java:31: error: input has private access in org.apache.lucene.util.fst.Util.Result
System.out.println(Util.toBytesRef(paths.topN.get(0).input, scratchBytes).utf8ToString()); // cat
^, /Example.java:32: error: output has private access in org.apache.lucene.util.fst.Util.Result
System.out.println(paths.topN.get(0).output); // 5
^, /Example.java:33: error: input has private access in org.apache.lucene.util.fst.Util.Result
System.out.println(Util.toBytesRef(paths.topN.get(1).input, scratchBytes).utf8ToString()); // dog
^, /Example.java:34: error: output has private access in org.apache.lucene.util.fst.Util.Result
System.out.println(paths.topN.get(1).output); // 7
^]
at org.junit.Assert.fail(Assert.java:89)
at org.junit.Assert.assertTrue(Assert.java:42)
at org.apache.lucene.util.fst.TestFstPackageExamples.testPackageOverviewExamplesCompile(TestFstPackageExamples.java:87)
tests_run=1 failures=1 (main 645d4fe14a20, seed DEADBEEF, with -ea and with -da)- The page calls the blocks examples and states their printed values (
// 7,// dogs); it has no pseudo-code disclaimer, and only imports are missing. - Maintainers fixed compile errors on this page before: LUCENE-6112 (2014) and the LUCENE-9089 follow-up (2020).
- LUCENE-8638 deleted the page's link to
getByOutputbut kept the example that calls it.
The full argument217 words
- The contract is the page. Headings "FST Construction example", "Retrieval by key", "Retrieval by value", "Iterate over key-value pairs in sorted order", "N-shortest paths by weight", and the printed values in
// xcomments (package-info.java:35-96). Every identifier the blocks use is declared on the page. - Upstream keeps this page compiling. LUCENE-6112 (#7174, 2014, "Compile error with FST package example code", fixed as "Fix compile error in FST package example code"); the LUCENE-9089 follow-up
59a8e83520e("update FST usage example", Tomoko Uchida, 2020-04-29), which rewrote the blocks for the then-newFSTCompilerandTopResults; #12831 (2024), which updated line 52 for thecompile()change. - Oversight. None of #249, #12715, #12831 or #13328 discusses the page's code (threads read). CHANGES and MIGRATE record the removals as deliberate API changes (naming the replacements for the constructor and the record fields), so the page documents APIs the project itself retired.
- Boundary isolated by execution. Each commit's own page was compiled against core built at that commit. The code blocks are the same at both commits (the 2020 text, which differs from today's at line 52, changed by #12831 in 2024, and in markup). They compile and print the commented values and the sorted pairs at
a37844aedd5(the parent of666c7a25907) and fail with thegetByOutputerror at666c7a25907.
The devil's-advocate check231 words
Strongest case for "not a bug" (built by the intended-behaviour checkers): (a) the FST API is @lucene.experimental; on the #12715 review Mike McCandless wrote that the FST API is internal, so the old constructor could be removed without deprecation; (b) Lucene does not compile javadoc code: LUCENE-8488 (#9534, "Javadoc examples should be kept in sync with actual compiled code") is still open, and on #15225 Robert Muir wrote that code examples should be kept "extremely minimal" because "the maintenance cost is very high and we don't have great validation for these"; (c) the failure is loud, and CHANGES and MIGRATE name the replacements for the constructor and the record fields; (d) the blocks are fragments.
Why it fails: experimental status explains why the API could change, not why the package's own overview keeps showing the removed forms; the lack of validation explains how the drift got in, and nobody upstream has said stale examples are acceptable (LUCENE-8488 and #15225 point the other way); a loud error lowers the impact, but the lookup-by-value block still advertises a removed capability; and the fragments need only imports. Verdict: not intended, a documentation defect (Low). To concede: the example itself uses two @lucene.internal helpers (BytesRefBuilder, IntsRefBuilder), so this is a trivial documentation cleanup that maintainers may reasonably resolve by trimming or deleting the examples instead, in line with the views above.
Recommended Update the three stale calls, drop the lookup-by-value example (validated)
Update the javadoc only: build with new FSTCompiler.Builder<Long>(INPUT_TYPE.BYTE1, outputs).build(), read paths.topN.get(i).input() / .output(), and remove the "Retrieval by value" example, whose API was removed in 9.0.0 with no named replacement. The patched page's examples compile and print the values in their comments, plus the sorted pairs from the iteration block.
- * FSTCompiler<Long> fstCompiler = new FSTCompiler<Long>(INPUT_TYPE.BYTE1, outputs);
+ * FSTCompiler<Long> fstCompiler = new FSTCompiler.Builder<Long>(INPUT_TYPE.BYTE1, outputs).build();
...
- * Retrieval by value:
- * IntsRef key = Util.getByOutput(fst, 12); (whole block removed)
...
- * System.out.println(Util.toBytesRef(paths.topN.get(0).input, scratchBytes).utf8ToString()); // cat
- * System.out.println(paths.topN.get(0).output); // 5
+ * System.out.println(Util.toBytesRef(paths.topN.get(0).input(), scratchBytes).utf8ToString()); // cat
+ * System.out.println(paths.topN.get(0).output()); // 5
(the same for get(1))All options and trade-offs4 options ยท 473 words
Option A was validated in a scratch worktree of 645d4fe14a20; the others were not run.
In package-info.java: use FSTCompiler.Builder in the construction block, the record accessors in the N-shortest-paths block, remove the "Retrieval by value" block, and change "provided to Builder" to "provided to FSTCompiler" in the construction comment. 1 file, +6/-14, javadoc only.
- * FSTCompiler<Long> fstCompiler = new FSTCompiler<Long>(INPUT_TYPE.BYTE1, outputs);
+ * FSTCompiler<Long> fstCompiler = new FSTCompiler.Builder<Long>(INPUT_TYPE.BYTE1, outputs).build();
...
- * Retrieval by value:
- * IntsRef key = Util.getByOutput(fst, 12); (whole block removed)
...
- * System.out.println(Util.toBytesRef(paths.topN.get(0).input, scratchBytes).utf8ToString()); // cat
- * System.out.println(paths.topN.get(0).output); // 5
+ * System.out.println(Util.toBytesRef(paths.topN.get(0).input(), scratchBytes).utf8ToString()); // cat
+ * System.out.println(paths.topN.get(0).output()); // 5
(the same for get(1))Trade-offs
Smallest change; keeps the package's only end-to-end example and stops advertising a removed feature. It does not prevent future drift, since nothing compiles the page.
What the checks validated
Yes, in a scratch worktree of 645d4fe14a20. The diff applies cleanly. The patched page's own examples, extracted mechanically from package-info.java (only imports added), compile and print 7 cat 5 dog 7 dogs 12 cat 5 dog 7, the values in the page's comments plus the iteration's sorted pairs; the stock page gives the 6 errors. With gradle and the fix applied, the 9 org.apache.lucene.util.fst suites (38 tests, including the minimal test with the corrected blocks) pass with assertions on and off; renderJavadoc, checkGoogleJavaFormat, ecjLintMain and forbiddenApisMain of core pass. On the stock tree the minimal test fails with the 6 errors. The hunt's compile-and-run check of the patched page also passes, and a mutant with a wrong documented order fails, so the output comparison is not vacuous.
As A, but replace the "Retrieval by value" block with a sentence such as "Lookup by output was removed in 9.0 (LUCENE-8638)."
Trade-offs
Tells readers of older articles why the feature is gone; adds a history remark to a usage page, which Lucene usually leaves to CHANGES and MIGRATE.
What the checks validated
Not run (text only).
Move the examples into a test source and reference them from the javadoc (for example with {@snippet file=...}), or keep a test that mirrors them (the direction of LUCENE-8488).
Trade-offs
Prevents the next drift, but needs new build plumbing (main uses no {@snippet} today) and carries the maintenance cost maintainers warned about on #15225; a bigger discussion than this bug needs.
What the checks validated
Not run.
Keep only a pointer to FSTCompiler.Builder, Util and the enums, or remove the code blocks.
Trade-offs
No drift possible, but the package loses its only end-to-end usage example. Acceptable if a committer prefers it.
What the checks validated
Not run.
Downstream projects that copied this page's examples into their own code or docs need the same three edits; Lucene's behaviour and indexes are unaffected.
No formal method. While checking whether Lucene's javadoc code examples still compile, an AI tool extracted this page's five examples, compiled them against main and every release jar, and used javap to date each API removal. Independent verifiers and a reviewer from another model family (OpenAI GPT-5.6) reproduced it with their own tests.
The method in full130 words
- Lead. A first pass that checks javadoc examples compiled the five blocks verbatim against the stock main jars and got all six errors (2026-10-29).
- Hunt. The hunt extracted the blocks mechanically (HTML entities decoded, only imports added), compiled them with javac against the core jar of every release 8.0.0-10.5.2, a 10.6 build of
4ae946e5a9b(then RC1, now the 10.6.0 tag), branch_10x and main (both with each release's own page and with main's page), scanned the three APIs withjavap, and wrote a compile-and-run JUnit test that compares the printed lines with the documented values; a mutant with a wrong documented order fails, so the comparison is not vacuous. The one-test repro used here keeps only the compile step. - Tier. Non-formal: compiling documentation code and scanning jars for API members.
No prior report of these errors. The nearest item, open issue #10094 (2019), is an older, already fixed compile error on the same page. No open PR touches the page as of 2026-11-01.
Searches5 searches
Closest items, none this bug:
- #10094 (LUCENE-9052, 2019, still open): this page's construction example did not compile on 8.3 because
scratchByteswas aBytesRef, which has nocopyChars; the report's corrected code switches toBytesRefBuilderand keeps the oldBuilder, the valid 8.x API. Fixed on main in 2020 by59a8e83520e, before any of the three current errors existed; it names none of them. Its only comment (2023) says it was fixed by #249, which is the PR that removedgetByOutputand left the block behind. - #7174 (LUCENE-6112, 2014) and the LUCENE-9089 follow-up (#10131, 2020): earlier, fixed compile drifts of the same page.
- #249, #12695 / #12715, #12831, #13328: the changes that broke or edited the page; none mentions its code.
- #9534 (LUCENE-8488) and #15225: generic proposals about javadoc examples; they name no example.
- #16821 (an open issue) with its open PR #16936, and the open PRs #16904 and #16949: outside reports and fixes of stale javadoc examples in other files, so such reports and PRs are being opened and reviewed now (#16904 has an approving review; none is merged as of 2026-11-01). #16949 does not touch the FST page.
| Where | When | How | Found |
|---|---|---|---|
| Scripted searches | 2026-10-29 | GitHub issues/PRs (16), commits (3), downstream (2), dev@ / java-user@ / issues@ / commits@ (20), JIRA archive (4), web (10) | no report; #10094 is an older, different defect |
| GitHub, manual | 2026-10-29 | about 36 queries: getByOutput, "lookup-by-output", "new FSTCompiler", "FSTCompiler.Builder" example, INPUT_TYPE.BYTE1, paths.topN.get, FST package-info / package-summary / example / "does not compile", recency windows | earlier, fixed drifts of the page only |
| Open PRs | 2026-10-29 | changed files of all 415 open apache/lucene PRs | none touches the page |
| GitHub, items updated since the last check | 2026-11-01 | all 58 issues and PRs updated since 2026-10-29, and the changed files of the 47 PRs among them | none touches util/fst; #16949 fixes other stale javadoc examples |
| Upstream main | 2026-11-01 | the page's blob and commit history on main f815e679bf6c and branch_10_6 | unchanged; last change #15573 (markup only) |
Broken by LUCENE-8638 (#249, 2021-08-18), which removed Util.getByOutput but kept the example; first release 9.0.0. #12715 (9.9.0) and #13328 (10.0.0) added the other errors. The 2020 text compiled on main until then (executed at a37844aedd5, the parent of the 2021 commit); no release tested ships the examples compiling.
Versions tested6 rows
- Written by
59a8e83520e(LUCENE-9089 follow-up, Tomoko Uchida, 2020-04-29). The examples as written then compiled on main (executed ata37844aedd5, 2021-08-18; the only page change in between,2d6ad2fee6d, touched only whitespace in the code blocks). Today's text differs at line 52 (#12831, 2024) and in markup. - Introduced by
666c7a25907(#249, LUCENE-8638, Michael Sokolov, 2021-08-18; first release 9.0.0): removedUtil.getByOutputand the page's link to it, kept the block. - Made worse by #12715 (
63759a463de/6cd78318eab, 2023-11-14, first release 9.9.0: public constructor removed) and #13328 (942065cc3e7, 2024-09-11, first release 10.0.0:Util.Resulta record). - Before 9.0.0 4.x-8.x ship an older text (written for the old
BuilderAPI, with aBytesRefscratch andMinResult) that fails with 4 errors from a different drift (4.10.4, 5.1.0, 7.7.3, 8.11.4):copyCharson aBytesRef(anIntsRefmismatch on 4.10.4),BytesReftoBytesRefBuilder,MinResultand the 4-argumentshortestPaths; none is aboutBuilder. #10094 reported part of that drift (thecopyCharserror). In no release tested do the examples compile as shipped.
| Version or commit | Verdict | Result |
|---|---|---|
main 645d4fe14a20; upstream main f815e679bf6c | affected | 6 errors (-ea and -da); upstream read, same page blob |
| 10.0.0 to 10.5.2, 10.6.0 | affected | 6 errors (the page as shipped; release scan of every 10.x jar up to 10.5.2 and of a 10.6 jar built from the tag commit 4ae946e5a9b; the fact check ran the released 10.6.0 jar with its own page: 6) |
| 9.9.0 to 9.12.3 | affected | 2 errors: the constructor and getByOutput |
| 9.0.0 to 9.8.0 | affected | 1 error: getByOutput |
main a37844aedd5 (parent of 666c7a25907) | not affected | the page's blocks as of that commit (the 2020 text) compile and print the commented values and the sorted pairs |
| 4.10.4, 5.1.0, 7.7.3, 8.11.4 | fails loudly | older page text, 4 errors from a different, earlier drift |
Six independent looks: the finder, a refute reviewer from another model family (OpenAI GPT-5.6), an independent reproducer, a second GPT-5.6 reviewer with an intended-behaviour lens, a devil's advocate and an adjudication. All agree it is a real, Low documentation defect; the brief re-ran the repro and validated the fix, and fact checks confirmed the core claims.
Checks and verdicts297 words
Each check ran separately; the refute reviewer and the independent reproducer wrote and executed their own tests.
| Check | Verdict | What it found |
|---|---|---|
| Finder | bug (documentation) | Release-by-release javac and javap scans; compile-and-run test fails on main, 10.5.2, 9.12.3 (2 errors), a jar built from 4ae946e5a9b (then 10.6.0 RC1, now tagged 10.6.0) and branch_10x; the fix passes, a mutant fails. |
| Refute lens (OpenAI GPT-5.6) | real, high confidence | Own tests fail javac on the documented forms under 3 seeds; a current-API control compiles; the proposed fix prints 7, the sorted pairs and cat/5, dog/7; it ran on an earlier main, ea57360912ed. |
| Independent reproducer | real | Own test: 6 errors on main and 10.5.2, 2 on 9.12.3 (-ea and -da); javap confirms when each API went away. |
| Intended lens (OpenAI GPT-5.6, reading only) | real, medium confidence | Rated the "experimental API, illustrative snippet" case moderate and rejected it; confidence lowered only because it could not run Java. |
| Devil's advocate | real, Low | Rejected the experimental-API, uncompiled-javadoc, loud-error and fragment arguments; re-ran the repro on main, 10.5.2 and 9.12.3 and the fix check. |
| Adjudication | confirmed, high; minor | Re-ran two independent repros (6 errors each) and the fix check (pass); kept it as a Low documentation defect. |
| This doc's brief | real; fix validated | Repro re-run stock and with the corrected blocks (-ea, -da); the page check and gradle checks in a scratch worktree. |
| Fact checks of this doc | real; core claims hold | An independent fact check re-ran the repro on main (-ea, -da) and on the published 10.5.2, 10.6.0 and 9.12.3 jars, scanned 23 releases with its own extractor and re-ran the fix; a reviewer from another model family (OpenAI GPT-5.6) re-read every claim. Their wording and provenance corrections are applied. |
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.
- PNG 423 KB
Finding record, Lucene and upstream sources, repro files and diagram notes1,509 words
- Registry 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)
- Area
- core / util/fst (package overview examples, package-info.java)
- Priority
- Low, rank 1242: The util.fst package overview has several examples that fail to compile, with no runtime effect and only users of the experimental FST API affected.
- Impact class
- minor
- Impact note
- Documentation only, with no runtime effect: a developer who copies the util.fst package overview's usage examples (the package's only end-to-end FST example) gets compile errors on every release since 9.0.0 (1 in 9.0.0-9.8.0, 2 in 9.9.0-9.12.3, 6 in 10.0.0-10.6.0 and main) and has to find FSTCompiler.Builder and the record accessors input()/output() on their own, while the 'Retrieval by value' feature the page shows no longer exists at all; the util.fst classes are @lucene.experimental, and no configuration, scale or special input is involved.
- 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.
- Introduced
- 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: the page's blocks compile and print the documented values on core built at the parent a37844aedd5 and fail with the getByOutput error at 666c7a25907, with identical block text]. 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: git log, show and blame in the full-history clone; git tag --contains in a Lucene clone] (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: the finder's JUnit fails on main (-ea and -da), 10.5.2 -da, 9.12.3 -da (2 errors), 10.6.0 RC1 jars -da and branch_10x jars -da; the independent reproduction's own JUnit fails on main, 10.5.2 and 9.12.3 (-ea and -da); the history check, each release's page as shipped against that release's jars, fails on 9.0.0 and 9.8.0 (1 error), 9.9.0 and 9.12.3 (2), 10.0.0, 10.5.2 and main (6); the re-run fails on main with -ea and -da] [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.
- 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, with the finder's searches and the adjudication's re-check as context; recheck 2026-10-29): scripted searches over GitHub issues, PRs and commits, downstream repositories, the dev@, java-user@, issues@ and commits@ lists, the JIRA archive and the web; about 35 targeted GitHub searches (getByOutput, lookup-by-output, 'new FSTCompiler', 'FSTCompiler.Builder' example, FST package-info, package-summary, FST example compile, 'Util.Result' record, 'topN.get', 'INPUT_TYPE.BYTE1', shortestPaths example, new items since 2026-10-25, ...); a scan of the changed files of all 415 open PRs (none touches the page); the page's commit history on main, branch_11x, branch_10x and branch_10_6; lists.apache.org for the last 30 days; Stack Exchange. Read but not the same bug: open issue #10094 (LUCENE-9052, 2019) reports that this page's construction example did not compile on 8.3 because of BytesRef.copyChars, an earlier drift that main fixed in 2020 (59a8e83520e) before any of the three current errors existed (its only comment, 2023-11-17, calls it resolved); LUCENE-6112 (#7174, 2014, fixed) and the LUCENE-9089 follow-up (#10131 comment, 2020, committed as 59a8e83520e) are earlier, fixed drifts of the same page; #249, #12695 and #12715, and #13328 (the changes that broke it) and #12831 (which edited the same block) never mention the page's code; #9938 (LUCENE-8895) deprecated getByOutput without mentioning the page; LUCENE-8488 (#9534) and #15225 are generic javadoc proposals that name no example; #16821 / #16936 and #16904 are outside fixes of the same defect class in other files. Recheck: only issues #16939 and #16940 were updated since a recent cutoff, neither about util/fst, and no PR; searches for getByOutput, 'FSTCompiler.Builder' javadoc, 'fst package-info', 'Util.Result' and new FST example items find nothing new; the page is unchanged on every branch. Tracking issue #16937 does not mention FST.
- Lucene commit tested
- main
645d4fe14a20(2026-10-28): the minimal test fails with assertions on and off (standalone, and gradle as an ordinary core test); the page's own blocks, extracted mechanically frompackage-info.java, fail with the same 6 errors and, with the fix applied, compile and print the documented values; the fix was checked with gradle in a scratch worktree of645d4fe14a20(the 9util.fstsuites with assertions on and off,renderJavadoc, format, lint and forbidden-APIs checks of core). Releases: the version-history runs ran each release's own page against its jars (9.0.0, 9.8.0, 9.9.0, 9.12.3, 10.0.0, 10.5.2), the finder's test ran on 10.5.2, 9.12.3, jars built from4ae946e5a9b(then 10.6.0 RC1, now the 10.6.0 tag) and branch_10x jars, and a javac scan covered every release jar 9.0.0-10.5.2. This doc's fact check ran the minimal test against the published 10.5.2, 10.6.0 and 9.12.3 jars (SHA-1 checked against Maven Central) and compiled 10.6.0's own page against the released 10.6.0 core jar: 6, 6 and 2 errors. Upstream mainf815e679bf6c(2026-11-01) was read, not run: the page's blob is unchanged.
- Finding record
a Lucene main checkout @ 645d4fe14a20: lucene/core/src/java/org/apache/lucene/util/fst/package-info.java:35-96, FSTCompiler.java:161 (private constructor), Util.java:429 (public record Result)
- The finding in 30 seconds
a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/util/fst/package-info.java:35-96 (blocks; :45, :62-68, :92-95 stale)a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/util/fst/FSTCompiler.java:68 (@lucene.experimental), :161-168 (private constructor), :242, :260, :351 (Builder)a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/util/fst/Util.java:41 (@lucene.experimental), :429 (record Result), :442 (TopResults.topN)a Lucene main checkout (645d4fe14a20) lucene/CHANGES.txt:3138 (9.9.0, GITHUB-12695), :4660 (9.0.0, LUCENE-8638); lucene/MIGRATE.md:1021-1026a Lucene main checkout (645d4fe14a20) lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/OrdsSegmentTermsEnum.java:1164 (private getByOutput, the only other one on main)
- Who is affected
a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/util/fst/FSTCompiler.java:68; a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/util/fst/Util.java:41; a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/util/fst/FST.java:62 (@lucene.experimental)
- Why it looks unintended
a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/util/fst/package-info.java:35-96a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/util/BytesRefBuilder.java:22, IntsRefBuilder.java:22 (@lucene.internal)
- History
a Lucene clone (git tag --contains 666c7a25907 -> 9.0.0, 6cd78318eab -> 9.9.0, 942065cc3e7 -> 10.0.0)
- TestFstPackageExamples.java (one test, Java-public Lucene classes + javax.tools):
repro/LFV-1027/TestFstPackageExamples.java(89 lines)
Made in parallel with this doc from the mechanism in the brief; the PNG is the summary frame.
assets/LFV-1027/bug.png(423 KB)
