All findings · Lucene finding · LFV-723 · taxonomy-rollup-ignores-default-dim-config

Taxonomy facets never roll up a hierarchical dimension that gets its config from getDefaultDimConfig

If a FacetsConfig subclass makes unconfigured dimensions hierarchical through getDefaultDimConfig(), taxonomy facets never add the leaf counts up to the parents: for 3 documents under 2010 (2) and 2012 (1), getTopChildren(10, "Publish Date") returns null and every parent count reads 0. Every release since 4.8.0 (2014) is affected.

Summary

Priority
Medium, rank 178Facet dimension and parent counts come out silently as 0 or null, but only with an opt-in hierarchical getDefaultDimConfig override and with an easy-to-see symptom.
Impact
silent wrong results
Since
4.8.0 (2014): LUCENE-5479 made the default overridable; the roll-up loop dates from 4.7.0introduced 2014-01-04 · over 12 years
Affected
every release from 4.8.0 through 10.6.0, and main (from 4.7.0 through a getDimConfig override)
Status
documented
Found by
bounded-exhaustive check of the FacetsConfig option matrix (semi-formal)

AI-assisted page: this finding was first signalled by a semi-formal check (an exact check of the real jar, or a modelling hypothesis that a tool then witnessed) 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

Taxonomy facets add leaf counts up to the parents at search time, but only for the dimensions they believe are hierarchical. Indexing asks the config of each dimension, default included; the roll-up looks only at the explicitly configured ones.

Background in three steps

  1. A taxonomy facet dimension such as Publish Date holds paths like 2010/10/15. FacetsConfig says, per dimension, whether it is hierarchical and whether a document may have several values (multiValued).
  2. For a hierarchical, single-valued dimension, indexing stores only the number (ordinal) of each document's leaf category. After counting, FastTaxonomyFacetCounts adds the leaf counts up the tree, the roll-up, so 2010 gets 2 and the dimension 3.
  3. A dimension you never configure gets the default config. Since 4.8.0 a FacetsConfig subclass can change that default by overriding the protected getDefaultDimConfig().
A light card with four boxes in a row, 1 Indexing (each document stores only its leaf category such as Publish Date/2010/10/15), 2 Counting (each stored leaf gets 1 per matching document, parents stay 0), 3 Roll-up outlined in red with a cross (adds each count into its parents), and 4 Facet counts (Publish Date: 3, 2010 (2), 2012 (1)), a red note under the roll-up saying it only walks the dimensions configured by name, so a dimension made hierarchical by the default getDefaultDimConfig() is never rolled up, and two small category trees at the bottom: an orange expected tree with counts 3, 2, 2, 1, 1, 1, 1, 1 and a blue actual tree in which every parent is 0 and getTopChildren returns null.
Hierarchical taxonomy facets count each document at its leaf category and add the counts up the tree at search time, but that roll-up skips a dimension whose hierarchical setting comes from the overridable default config. Generated with AI, checked against the code.
Diagram of the bug: three documents under Publish Date (2010/10/15, 2010/10/20, 2012/1/1) are indexed with a FacetsConfig whose getDefaultDimConfig makes every unconfigured dimension hierarchical. Indexing stores only the leaf categories. TaxonomyFacets.rollup() walks getDimConfigs(), which is empty, so the counts of 2010, 2012 and the dimension stay 0 and getTopChildren(10, "Publish Date") returns null, while an explicit setHierarchical gives value 3 with 2010 (2) and 2012 (1).
The repro's Publish Date tree: leaf counts 1, 1 and 1; the roll-up should give 2010 (2), 2012 (1) and 3 for the dimension, but with the hierarchical default the parents stay 0. Select the still to open it at full size. Generated with AI, checked against the code.

The finding, step by step

  1. Subclass FacetsConfig so that getDefaultDimConfig() returns a hierarchical DimConfig, as Lucene's own TestFacetsConfig#testCustomDefault does. Index 3 documents under Publish Date: 2010/10/15, 2010/10/20 and 2012/1/1.
  2. Indexing follows that default: each document stores only its leaf category, and the counts of the parents (2010, 2012 and the dimension) are left to be added up at search time.
  3. You expect FastTaxonomyFacetCounts to give what an explicit setHierarchical("Publish Date", true) gives: value 3, with 2010 (2) and 2012 (1).
  4. Instead getTopChildren(10, "Publish Date") returns null and getSpecificValue("Publish Date", "2010") returns 0. The roll-up only visits the dimensions listed in getDimConfigs(), the explicit entries, and Publish Date has none.
  5. No error, and a DrillDownQuery on Publish Date/2010 still matches 2 documents. If some documents have a depth-1 label, only those show: toys (1) instead of electronics (3), books (1), toys (1).

Who is affected

Applications whose FacetsConfig subclass overrides getDefaultDimConfig() (or getDimConfig) so that unconfigured dimensions are hierarchical and single-valued, and that count such a dimension with taxonomy faceting. Opt-in and rare: the three real overrides found in the recorded GitHub code search use multiValued = true, which is unaffected. Deterministic, 3 documents suffice; a fix needs no reindex.

Mechanism, terms and numbers657 words

FacetsConfig#getDefaultDimConfig() is a protected hook (LUCENE-5479, 4.8.0) that sets the config of every dimension without an explicit entry; Lucene's only test of it makes those dimensions hierarchical. Indexing follows the default: for a hierarchical, single-valued dimension it stores only each document's leaf category and leaves the parent counts to a search-time roll-up. But TaxonomyFacets.rollup() picks the dimensions to roll up from config.getDimConfigs(), which holds only the explicit entries, so such a dimension is never rolled up: its dimension count and every non-leaf count stay 0, getTopChildren(dim) returns null (or only the depth-1 leaves), and nothing throws, while a DrillDownQuery on the same labels still matches the documents. It affects FastTaxonomyFacetCounts (both constructors) and the value-source aggregation of TaxonomyFacetFloatAssociations, in every release from 4.8.0 through 10.6.0 and on main. The index itself is correct, so a fix in the roll-up needs no reindex.

The mechanism (main 5adff78bb168)

  1. The hook. FacetsConfig.getDefaultDimConfig() (FacetsConfig.java:142-151, protected) supplies the config of every dimension without an explicit entry: getDimConfig(dim) returns the map entry if there is one, else getDefaultDimConfig() (:153-160).
  2. Indexing honours it. processFacetFields reads getDimConfig(facetField.dim) (:370); a 3-component path is accepted only because the default says hierarchical (:371-378). It stores the leaf ordinal (:383-384) and adds the ancestor ordinals only when the dimension is multiValued (:386-398). So each document stores one ordinal: 2010/10/15, 2010/10/20 or 2012/1/1.
  3. Counting. FastTaxonomyFacetCounts counts each stored ordinal once (FastTaxonomyFacetCounts.java:93, :138), then calls rollup() (:117 for hits, :174 for count-all). The value-source path of TaxonomyFacetFloatAssociations calls the same rollup() (TaxonomyFacetFloatAssociations.java:164-165); its indexed-association constructors, and those of TaxonomyFacetIntAssociations, never call rollup() for any config and are not affected (code reading). DrillSideways builds its taxonomy facets with FastTaxonomyFacetCounts (DrillSideways.java:159, :165).
  4. The roll-up skips the dimension. TaxonomyFacets.rollup() ("Rolls up any single-valued hierarchical dimensions", TaxonomyFacets.java:261-285) loops over config.getDimConfigs().entrySet() (:269). getDimConfigs() returns the private map of explicit entries (FacetsConfig.java:228-231). Publish Date has no entry, so the leaf counts (1 each) are never added up: 2010/10, 2010, 2012/1, 2012 and the dimension stay 0.
  5. What the caller sees. getTopChildren(10, "Publish Date") collects the dimension's children with a count above 0 (TaxonomyFacets.java:478-503), finds none, and returns null for 0 children (:308-310). getSpecificValue("Publish Date") is accepted with the comment "ok: rolled up at search time" (:540-541) and returns the raw count, 0 (:553). getAllDims drops a dimension whose getTopChildren is null (:571-575). getTopDims sums a single-valued dimension's direct children (:639-650), which were never rolled up, and leaves out a dimension whose sum is 0 (:652): it returns [] where the explicit config gives value=3 2010 (2) 2012 (1) (executed on 5adff78bb168; correct with the fix).
  6. Everything else asks getDimConfig. verifyDim (:221-235), getAllDims (:570) and FacetsConfig.build see the default. Besides rollup(), only OrdinalMappingLeafReader.java:136 (LFV-722) enumerates getDimConfigs() in core facets; the sandbox cutter has the same loop (TaxonomyFacetsCutter.java:119) and its builder refuses unconfigured dimensions instead (TaxonomyFacetBuilder.java:48-59).

The numbers (3 documents, FastTaxonomyFacetCounts)

callexplicit setHierarchicalhierarchical default via getDefaultDimConfig
getTopChildren(10, "Publish Date")value=3, 2010 (2), 2012 (1)null
getTopChildren(10, "Publish Date", "2010")value=2, 10 (2)null
getSpecificValue("Publish Date", "2010")20
getSpecificValue("Publish Date")30
DrillDownQuery on Publish Date/20102 hits2 hits

With some depth-1 labels the result is partial: 5 documents under category/electronics/phones, /electronics/laptops, /electronics/phones, /books/fiction and /toys give value=1 childCount=1 toys (1) instead of value=5 childCount=3 electronics (3) books (1) toys (1). The value-source aggregation (TaxonomyFacetFloatAssociations, DoubleValuesSource.fromLongField("price"), MAX, prices 5, 7, 3) gives null instead of value=7.0 2010 (7.0) 2012 (3.0). Counts under the deepest parent, DrillDownQuery, SortedSetDocValues faceting with the same default, a hierarchical multiValued default and explicitly configured dimensions are correct.

Exposure and likelihood232 words
  • Who is hit. Applications that subclass FacetsConfig and override getDefaultDimConfig() (the documented hook, 4.8.0 and later) or the public getDimConfig (the workaround the LUCENE-5479 reporter had used, 4.7.0 and later) so that dimensions without an explicit entry are hierarchical and single-valued, and that count such a dimension with taxonomy faceting: FastTaxonomyFacetCounts (both constructors), TaxonomyFacetFloatAssociations with a DoubleValuesSource, and DrillSideways' default taxonomy facets (code reading).
  • What goes wrong. Dimension and parent counts read 0, getTopChildren(dim) returns null or only the depth-1 leaves, and getAllDims and getTopDims leave the dimension out. Nothing throws, and DrillDownQuery on the same labels still matches, so the facet panel and the result list disagree.
  • Opt-in, no scale needed. Deterministic with ordinary data (3 documents suffice), with assertions on and off.
  • Likelihood: rare. All three real overrides found in the recorded GitHub code search (in 2 projects, seecr/meresco-lucene and voyanttools/trombone) use multiValued = true, which is unaffected, and the symptom is easy to see, so a user would likely fall back to explicit setHierarchical calls.
  • Not affected. The stock FacetsConfig, explicitly configured dimensions, a hierarchical multiValued default, SortedSetDocValues faceting, drill-down and counts under the deepest parent.
  • After a fix. The index is written as designed (an index built with the default config and counted with an explicitly configured copy gives the right counts), so a fix in the roll-up corrects existing indexes at search time.

Minimal repro

One JUnit test, one method: a FacetsConfig whose default is hierarchical, three documents, FastTaxonomyFacetCounts. It fails on main and on the 10.6.0, 10.5.2, 9.12.3 and 9.1.0 jars, with assertions on and off, and in 20 of 20 iterations; the same test with an explicit setHierarchical passes.

TestHierarchicalDefaultDimConfig.java (one test method)70 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.facet.taxonomy;

import org.apache.lucene.document.Document;
import org.apache.lucene.facet.FacetField;
import org.apache.lucene.facet.Facets;
import org.apache.lucene.facet.FacetsConfig;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.tests.util.LuceneTestCase;
import org.apache.lucene.util.IOUtils;

public class TestHierarchicalDefaultDimConfig extends LuceneTestCase {

  public void testUnconfiguredHierarchicalDimIsRolledUp() throws Exception {
    // Every dimension without an explicit entry is hierarchical (as in
    // TestFacetsConfig#testCustomDefault); "Publish Date" has no explicit entry.
    FacetsConfig config =
        new FacetsConfig() {
          @Override
          protected DimConfig getDefaultDimConfig() {
            DimConfig dimConfig = new DimConfig();
            dimConfig.hierarchical = true;
            return dimConfig;
          }
        };

    Directory dir = newDirectory();
    Directory taxoDir = newDirectory();
    IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig());
    DirectoryTaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(taxoDir);
    String[][] dates = {{"2010", "10", "15"}, {"2010", "10", "20"}, {"2012", "1", "1"}};
    for (String[] date : dates) {
      Document doc = new Document();
      doc.add(new FacetField("Publish Date", date));
      writer.addDocument(config.build(taxoWriter, doc));
    }
    DirectoryReader reader = DirectoryReader.open(writer);
    TaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoWriter);

    Facets facets =
        new FastTaxonomyFacetCounts(
            FacetsConfig.DEFAULT_INDEX_FIELD_NAME, reader, taxoReader, config);

    // What config.setHierarchical("Publish Date", true) gives for the same documents:
    assertEquals(
        "dim=Publish Date path=[] value=3 childCount=2\n  2010 (2)\n  2012 (1)\n",
        String.valueOf(facets.getTopChildren(10, "Publish Date")));

    IOUtils.close(reader, taxoReader, writer, taxoWriter, dir, taxoDir);
  }
}
Command
cd $LUCENE
cp $REPRO/TestHierarchicalDefaultDimConfig.java lucene/facet/src/test/org/apache/lucene/facet/taxonomy/
./gradlew :lucene:facet:test --tests org.apache.lucene.facet.taxonomy.TestHierarchicalDefaultDimConfig -Ptests.seed=DEADBEEF -Ptests.asserts=true
# assertions off fails the same way: -Ptests.asserts=false
Expected
getTopChildren(10, "Publish Date") gives value=3 childCount=2, 2010 (2), 2012 (1), as with an explicit setHierarchical.
Observed
It returns null: expected:<[dim=Publish Date path=[] value=3 childCount=2 ...]> but was:<[null]>.

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

More files, environment, full output231 words

The test sits in org.apache.lucene.facet.taxonomy next to the module's taxonomy tests and uses only public and protected API. Three documents, one dimension, single thread, deterministic. It uses the count-all constructor to stay short; the hits constructor new FastTaxonomyFacetCounts(taxoReader, config, fc) fails the same way. It compiles from 9.1.0 on (org.apache.lucene.tests). For a release, compile and run the same file against that release's lucene-core, lucene-facet and lucene-test-framework jars.

Pass -Ptests.asserts explicitly: on current main its default is drawn from the seed ("Run with assertions for ~75% of all seeds").

The expected string is what the same documents give with config.setHierarchical("Publish Date", true) (the test with that one change passes on stock main). The same test is the suggested regression test; it passes with the recommended fix.

Environment

lucenemain 5adff78bb168 (12.0.0-SNAPSHOT), 10.6.0, 10.5.2, 9.12.3, 9.1.0: fail
jdkOpenJDK 25.0.3 (build 25.0.3+9-LTS)
osLinux, aarch64

Observed output

# gradle, main 5adff78bb168, seed DEADBEEF, -Ptests.asserts=true
TestHierarchicalDefaultDimConfig > testUnconfiguredHierarchicalDimIsRolledUp FAILED
    org.junit.ComparisonFailure: expected:<[dim=Publish Date path=[] value=3 childCount=2
      2010 (2)
      2012 (1)
    ]> but was:<[null]>
        at __randomizedtesting.SeedInfo.seed([DEADBEEF:C525DFB2C6A10945]:0)
        ...
        at app//org.apache.lucene.facet.taxonomy.TestHierarchicalDefaultDimConfig.testUnconfiguredHierarchicalDimIsRolledUp(TestHierarchicalDefaultDimConfig.java:64)

# the same failure: gradle with -Ptests.asserts=false; the JUnit runner on main (-ea and -da), 10.6.0 (-ea and -da), 10.5.2, 9.12.3 and 9.1.0
# main, 20 iterations (seed 5EED0723): 20 of 20 fail
# control, the same test with explicit setHierarchical, stock main: passes
# main with the recommended fix: passes (assertions on and off)

Why it looks unintended

  • The hook's javadoc: "The default configuration to be used for dimensions that are not yet set"; Lucene's only test of it sets hierarchical = true.
  • Indexing honours the default and leaves the parents to a roll-up; getSpecificValue says "rolled up at search time".
  • The same getDimConfigs() blind spot in another class was fixed as a bug (LUCENE-5801).
The full argument252 words
  • The hook is documented for exactly this. getDefaultDimConfig javadoc: "Get the default configuration for new dimensions. Useful when the dimension is not known beforehand and may need different global default settings"; "@return The default configuration to be used for dimensions that are not yet set in the FacetsConfig" (FacetsConfig.java:142-148). CHANGES 4.8.0: "LUCENE-5479: FacetsConfig subclass can now customize the default per-dim facets configuration".
  • Lucene's only test of the hook sets hierarchical = true (TestFacetsConfig#testCustomDefault, TestFacetsConfig.java:104-117). It checks only getDimConfig("foobar").hierarchical, never a count; no test combines a custom default with taxonomy counts.
  • The rest of the module honours the default. Indexing accepts a 3-component path only because the default is hierarchical (with the stock default build throws "is not hierarchical yet has 3 components", FacetsConfig.java:371-378) and leaves the parents to the roll-up; getSpecificValue(dim) says "ok: rolled up at search time" (TaxonomyFacets.java:541); rollup() says it rolls up "any single-valued hierarchical dimensions"; SortedSetDocValues faceting with the same default counts correctly.
  • History: an assumption the hook outdated. The loop dates from LUCENE-5339 (2013), when the only default was the static, flat DEFAULT_DIM_CONFIG, so a hierarchical dimension had to be configured explicitly. LUCENE-5479 (2014) made the default overridable and changed only FacetsConfig and its test. Its discussion (#6542) was about a multiValued = true default, where build stores the ancestors itself and the gap does not show.
  • Precedent. LUCENE-5801 (#6863, 2014): OrdinalMappingAtomicReader collected facet fields only from getDimConfigs(); it was reported as "wrong facet data" and fixed.
The devil's-advocate check249 words

The strongest case for "intended": FacetsConfig is @lucene.experimental; its class javadoc says "use the setters in this class to change these settings for each dim" (FacetsConfig.java:49-51); the hook's javadoc example is multivalue = true; isDimConfigured's javadoc says an unconfigured dimension uses DEFAULT_DIM_CONFIG (:162-165); enumerating getDimConfigs() keeps the taxonomy's children and siblings arrays lazy, which two tests assert; and the sandbox TaxonomyFacetBuilder (#14237) requires explicit configuration for the same reason.

Why it fails: nothing in core documents or enforces that a hierarchical dimension must be configured explicitly. Indexing silently accepts the paths and relies on a roll-up that never comes, and the result is 0 for a label DrillDownQuery finds in 2 documents. The isDimConfigured javadoc is not older than the hook: it was added in 9.0.0 (LUCENE-9971, #149, 2021) and repeats the pre-2014 assumption. Laziness can be kept: the recommended fix walks the taxonomy only when the default needs a roll-up, and both laziness tests pass with it (it does not cover name-dependent getDimConfig overrides, which only the always-walk alternative does). The sandbox comment shows a contributor who knew the loop's limit and chose to fail loudly rather than miscount; "configure hierarchical dimensions explicitly" is a contract upstream could plausibly choose, but then core should enforce it the same way (option D) instead of returning wrong counts. Verdict: not intended, a defect; every reviewer rated the "intended" case weak (the devil's advocate rated only how upstream may frame it as medium).

Suggested fix

Recommended A. Also roll up taxonomy dimensions that use the default config, only when that default needs it (validated for the documented hook)

After the getDimConfigs() loop in TaxonomyFacets.rollup(), if the default config is hierarchical and single-valued, roll up the taxonomy's dimensions without an explicit entry (+34 lines, one file). With it the repro passes (assertions on and off), and so do the facet module's 307 tests (assertions on: 0 failures, 7 skipped; laziness tests included) and its static checks.

All options and trade-offs4 options ยท 763 words

Four options. A was validated with gradle on main 5adff78bb168; C was run and breaks two existing tests; B and D were not run. In any case, fix the isDimConfigured javadoc (FacetsConfig.java:162-165): an unconfigured dimension uses getDefaultDimConfig(), not necessarily DEFAULT_DIM_CONFIG.

A. Also roll up taxonomy dimensions that use the default config, only when that default needs it (validated for the documented hook) (recommended)

After the existing loop, read the default through getDimConfig of a name without an explicit entry (a small helper unconfiguredDim() returns "", which a FacetField never has as its dimension, padded with '\u0000' while that name is configured). getDefaultDimConfig() takes no name, so this is exactly the default. If it is hierarchical and single-valued, walk the dimension roots (the children of the root ordinal, the same walk getAllDims does, TaxonomyFacets.java:564-578) and roll up each one without an explicit entry whose getDimConfig(dim) is hierarchical and single-valued. Explicit entries are skipped, so nothing is rolled up twice. The full diff is in the Sources block.

    // Dimensions without an explicit entry are not in getDimConfigs(): they use the default
    // DimConfig, which a FacetsConfig subclass may change (getDefaultDimConfig). Walk the
    // taxonomy's dimensions for them only when that default needs a roll-up, so the
    // children/siblings arrays stay lazy otherwise:
    DimConfig defaultConfig = config.getDimConfig(unconfiguredDim());
    if (defaultConfig.hierarchical && defaultConfig.multiValued == false) {
      if (children == null) {
        children = getChildren();
      }
      ParallelTaxonomyArrays.IntArray siblings = getSiblings();
      for (int dimOrd = children.get(TaxonomyReader.ROOT_ORDINAL);
          dimOrd != TaxonomyReader.INVALID_ORDINAL;
          dimOrd = siblings.get(dimOrd)) {
        String dim = taxoReader.getPath(dimOrd).components[0];
        if (config.isDimConfigured(dim) == false) {
          DimConfig dimConfig = config.getDimConfig(dim);
          if (dimConfig.hierarchical && dimConfig.multiValued == false) {
            updateValueFromRollup(dimOrd, children.get(dimOrd));
          }
        }
      }
    }

Trade-offs

  • The probe name works around getDefaultDimConfig being protected in another package; a getDimConfig override that answers flat for "" but hierarchical for some other names would escape the gate. So A is validated for getDefaultDimConfig overrides and for getDimConfig overrides that return the effective default for the probe name, and is incomplete for name-dependent overrides (C covers those).
  • When the gate opens, the children and siblings arrays are loaded once per reader, as for any explicitly configured hierarchical dimension today.
  • Like the existing loop, it does not compare indexFieldName (rolling up a dimension stored in another field adds zeros).
  • No index change and no reindex.

What the checks validated

  • Gradle in a scratch worktree of 5adff78bb168, OpenJDK 25.0.3, seed DEADBEEF: stock, the repro fails with assertions on and off; with the fix it passes with assertions on and off.
  • The whole facet module with the fix, :lucene:facet:test with assertions on: 40 classes, 307 tests, 0 failures, 7 skipped, including TestTaxonomyFacetCounts (19), TestTaxonomyFacetCounts2 (4), TestTaxonomyFacetValueSource (10), TestTaxonomyFacetAssociations (12), TestFacetsConfig (4) and the new test.
  • :lucene:facet:check -x test (google-java-format, ecj lint, forbidden APIs) passes with the fix and the test.
  • With the fix applied on 5adff78bb168, the earlier independent tests pass (2 of 2, 3 of 3 including the depth-1 case, 5 of 5 including a getDimConfig override), and the value-source probe gives value=7.0 2010 (7.0) 2012 (3.0) like the explicit config.
  • The getTopDims and getAllDims probe gives the explicit config's value=3 2010 (2) 2012 (1) with the fix (stock: []).

B. Expose the default and gate on it (cleaner API; not run)

Add a public accessor to FacetsConfig that returns getDefaultDimConfig(), and use it in A instead of the probe name.

Trade-offs

Same behaviour for the documented hook, no probe name; an API addition to an @lucene.experimental class.

C. Always walk the taxonomy's dimensions and ask getDimConfig(dim) (exact, but breaks two tests) (validated by the checks)

Replace the getDimConfigs() loop with the getAllDims-style walk (diff in the Sources block). It covers every override, including name-dependent getDimConfig overrides, and the repro passes.

Trade-offs

It loads the children and siblings arrays for every count, even with only flat dimensions, and two existing laziness assertions fail: TestTaxonomyFacetCounts#testLabelWithDelimiter (:451, assertFalse(siblingsLoaded())) and TestTaxonomyFacetValueSource#testChildrenAndSiblingsLoaded (:520, expected:<false> but was:<true>); 29 tests, 2 failed.

What the checks validated

  • Gradle on 5adff78bb168: the repro passes; TestTaxonomyFacetCounts and TestTaxonomyFacetValueSource: 2 of 29 fail as above.

D. Document and enforce explicit configuration, as the sandbox does (not run)

Throw an IllegalArgumentException when build or TaxonomyFacets meets an unconfigured dimension whose config is hierarchical and single-valued, and say so in the getDefaultDimConfig javadoc, like the sandbox TaxonomyFacetBuilder (TaxonomyFacetBuilder.java:48-59).

Trade-offs

Fails loudly instead of miscounting, but breaks indexing for applications that use the hook today, and makes the hook unusable for hierarchical taxonomy dimensions, the very case its only test shows.

Downstream note

Products built on Lucene that let users add facet dimensions without per-dimension configuration through a hierarchical default would show the same zero or missing parent counts; the downstream overrides found (seecr/meresco-lucene, voyanttools/trombone) use multiValued = true and are unaffected.

How it was found

Semi-formal: a bounded-exhaustive check compared taxonomy and SortedSetDocValues facet results with a javadoc-based reference over every FacetsConfig option combination and up to 3 small documents. Reading rollup() while building it raised the suspicion; this defect's mismatches then appeared in exactly the 20 taxonomy configs with a hierarchical, single-valued default (other mismatches: another finding, and an artifact of the check fixed before the second run).

The method in full178 words

Method: semi-formal, bounded-exhaustive translation validation of the FacetsConfig option matrix.

  • The matrix: drill-down terms indexing (5 options) x hierarchical x multiValued x requireDimCount x index field layout x config style (explicit setters, or a getDefaultDimConfig override) x faceting (taxonomy, SortedSetDocValues): 400 configs. Each was checked on every multiset of up to 2 (and, in a second run, 3) small documents, in 1 or 2 segments, with and without deletes, against a reference written from the javadoc.
  • While building the matrix, reading TaxonomyFacets.rollup() showed that it iterates getDimConfigs(). In the run on the stock jars, this defect's mismatches then appeared in exactly the 20 taxonomy configs with hierarchical = true, multiValued = false and the default-override style, and in none of the explicit-setter configs (the run's other mismatches belong to a different finding and to an artifact of the check itself, fixed before the second run): 408,567,314 checks at up to 2 documents, 685,912,348 at up to 3, assertions off.
  • The finding was reduced to a public-API JUnit test on the real jars, with an explicit-config control.

Prior reports, history and checks

Prior reports

New: the searches found no Lucene issue, PR, JIRA entry, list thread or commit, and nothing outside Lucene, that describes this defect (re-checked 2026-11-03 and 2026-11-04). Related items concern other things: the sandbox TaxonomyFacetBuilder check (#14237), the same blind spot in another class (#6863, fixed 2014), and a review remark on an unmerged draft (#11780).

Searches3 searches

No report of this defect was found (re-checked 2026-11-03 in two independent passes, and again on 2026-11-04). Related prior items, none of them this defect:

  • #14237 (epotyom, merged 2025-03-03, sandbox facets): the sandbox TaxonomyFacetBuilder throws unless the dimension is configured explicitly, with the comment that the sandbox "TaxonomyFacetsCutter uses FacetConfig#getDimConfigs to find dimensions that need to be rolled up, hence it needs the dimension to be configured explicitly" (TaxonomyFacetBuilder.java:48-59). It is about the sandbox cutter, a different class and fix site, motivated by dimension totals for the stock flat default; it says nothing about core TaxonomyFacets, getDefaultDimConfig or wrong counts, and the PR discussion does not mention it. The closest related item.
  • #6863 (LUCENE-5801, 2014, fixed): OrdinalMappingAtomicReader collected facet fields only from getDimConfigs(), reported as "wrong facet data". A different class (today's OrdinalMappingLeafReader, LFV-722); the precedent that this blind spot is a bug.
  • #11780 (open draft): in a 2023 review gsmiller noted that a config.getDimConfigs() enumeration "won't know about" fields that use the default dim config, in a proposed SortedSetDocValues helper that was never merged. Different code.
  • #6542 (LUCENE-5479, 2014): added the hook. The reporter wanted a multiValued = true default and had used a getDimConfig override; the committed test sets hierarchical = true; roll-up is never discussed.
  • #149 (LUCENE-9971, 2021): made unseen dimensions behave the same in SortedSetDocValues and taxonomy facets and added isDimConfigured, whose javadoc names DEFAULT_DIM_CONFIG. A different defect.
  • java-user, 2014-06-22: a null result for a hierarchical Publish Date dimension, caused by a different FacetsConfig at search time (no setHierarchical), which the javadoc forbids. Same symptom, different cause.

LFV-722 is a different bug with the same assumption in OrdinalMappingLeafReader.

What was searched, when, and what turned up
WhereWhenHowFound
GitHub apache/lucene issues, PRs and commits (incl. the migrated JIRA archive); downstream repositories; dev@, java-user@, issues@, commits@; JIRA2026-10-27the scripted prior-report search, 3 runs (72 GitHub issue and PR, 9 commit, 6 downstream, 72 mailing-list and 18 JIRA queries) plus two earlier runs of 51 and 43 queriesonly the related items above
GitHub by hand: apache/lucene, apache/lucene-solr, apache/solr, Lucene.NET, Elasticsearch, OpenSearch; JIRA; lists.apache.org; GitHub code search; Stack Overflow2026-10-2741 read-only GitHub searches; the changed files of all 409 open apache/lucene PRs; 9 JQL enumerations with 13 issues grepped; 9 list terms with 37 messages read; a code search for getDefaultDimConfig; 13 Stack Overflow searchesnothing about this defect; the real downstream overrides use multiValued = true
Re-check for this doc: GitHub issues, PRs and commits, downstream trackers, the four lists, JIRA, open PRs, web2026-11-04the scripted prior-report search, 51 queries of which 45 ran (16 GitHub, 3 commit, 2 downstream, 20 mailing-list, 4 JIRA; 97 hits, all the items above or unrelated) and 6 web queries were left to a manual pass; 4 GitHub API searches; open PRs touching TaxonomyFacets or FacetsConfig; 3 manual web searches (2 answered, 1 throttled)nothing new; getDefaultDimConfig has 0 hits on GitHub issues and PRs, commits, downstream repositories, JIRA and the dev@, java-user@ and issues@ lists

History

The roll-up loop dates from LUCENE-5339 (7477fde1cb0, 2014, first released in 4.7.0); LUCENE-5479 (1ea87054f0d, 2014-03-01, 4.8.0) made the default overridable without touching it. Two version-portable probes fail on all 116 releases from 4.8.0 to 10.5.2; the minimal test, run on 9.1.0, 9.12.3, 10.5.2, 10.6.0 and main, fails on each. Not fixed upstream.

Versions tested8 rows

The loop. LUCENE-5339 ("Simplify the facet module APIs", #6403) wrote rollup() as a loop over config.getDimConfigs(): first 5458dbf2484 (2013-11-14, a development branch), into the 4.x line by 7477fde1cb0 (branch_4x, 2014-01-04; trunk 9d0b60388da; svn era, no PR). The trigger. LUCENE-5479 (#6542) added the protected getDefaultDimConfig(): 074923dda7e (trunk) and 1ea87054f0d (branch_4x), 2014-03-01, changing only FacetsConfig and its test. Later moves kept the loop: 458786d0f41 (2013), LUCENE-7994 77e6e291bf3 (2017), #12966 9ba4af7b883 (2024, into TaxonomyFacets) and its 9.x backport #13358. Not a regression.

Two version-portable main() probes index the same 3 documents and count them with an explicit-config control. Not fixed upstream: the loop is unchanged at TaxonomyFacets.java:269 on main f72004515ec (2026-11-03), branch_10_6 facfa0d52c9 (2026-11-01) and the 10.6.0 tag; no open PR changes it.

Versions and branches executed, with results
Version or commitVerdictResult
4.6.1 and older no APIno FacetsConfig (the probes do not compile)
4.7.0, 4.7.1, 4.7.2 getDimConfig override onlyno getDefaultDimConfig yet; a getDimConfig override that makes unconfigured dimensions hierarchical fails
4.8.0 first releaseprobe: top=null, value(2010)=0, value(dim)=0, drill-down 2 hits; control correct
4.8.1 to 10.5.2 (115 releases, incl. 8.11.4) affectedboth probes: the same wrong output on every release; the control correct in every run that compiled
9.1.0, 9.12.3, 10.5.2 affectedminimal test fails
10.6.0 affectedminimal test fails, assertions on and off
main 5adff78bb168 affectedminimal test fails (gradle and JUnit runner, assertions on and off; 20 of 20 iterations)
main + recommended fix not affectedminimal test passes; facet module 307 tests, 0 failures

Independent checks

Before this doc: the finder's cross-model review (OpenAI GPT-5.6, refute lens), an independent reproducer, a second cross-model review (intended lens), an intended-behaviour devil's advocate and an adjudication all rated it real (the cross-model reviews, the devil's advocate and the adjudication with high confidence). This doc re-ran it on 5adff78bb168 and 10.6.0 and validated the fix with gradle.

Checks and verdicts281 words

The reviews and verifiers ran on main a9779ef3c193 (the cross-model reviews on ea57360912ed, whose facet sources are identical); a re-verification on e1faeba08bde (2026-11-02) and this doc's runs on 5adff78bb168 reproduced it.

Each independent check and its verdict
CheckVerdictWhat it found
finder foundBounded-exhaustive check, then a 2-test JUnit: the default-config test fails with assertions on and off, also on 10.5.2 and 9.12.3; its explicit-config control passes.
cross-model review (OpenAI GPT-5.6, refute lens, executed) real (high)Own test fails on main (4 seeds, assertions on and off), 10.5.2 and 9.12.3. It rejected the first fix sketch, which walked the taxonomy eagerly and broke a laziness test; the fix was rewritten to stay lazy.
independent reproducer realOwn 3-test JUnit (both constructors, the depth-1 toys case) fails on main, 10.5.2 and 9.12.3; an isolation test shows the index is right and only the roll-up differs.
cross-model review (OpenAI GPT-5.6, intended lens, executed) real (high)Rated the intended-behaviour case weak; its own test fails only the default-override taxonomy case and passes with the fix.
intended-behaviour devil's advocate real (high); framing mediumA getDimConfig override fails the same way; SortedSetDocValues and multiValued controls pass; found the sandbox comment (#14237) as the strongest counterpoint and LUCENE-5801 as precedent.
adjudication confirmed (high)Re-ran the independent test with new seeds (fails with assertions on and off, passes with the fix) and re-read the root cause.
this doc reproduced; fix validatedOne-method test fails on main 5adff78bb168 and on 10.6.0, 10.5.2, 9.12.3 and 9.1.0; the value-source path, earlier covered by code reading only, was executed and fails the same way; the recommended fix passes the facet module's 307 tests.

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,451 words

Finding record

LFV-723, snapshot of 2026-11-06

Registry 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
Area
facet / taxonomy facets (TaxonomyFacets#rollup dimension enumeration vs the overridable FacetsConfig default dimension config; FastTaxonomyFacetCounts, TaxonomyFacetFloatAssociations)
Priority
Medium, rank 178: Facet dimension and parent counts come out silently as 0 or null, but only with an opt-in hierarchical getDefaultDimConfig override and with an easy-to-see symptom.
Impact class
silent wrong results
Impact note
Hits applications that subclass FacetsConfig and override the protected getDefaultDimConfig (or the public getDimConfig) to return a hierarchical, single-valued DimConfig, as Lucene's own TestFacetsConfig#testCustomDefault (LUCENE-5479) does, and then count such a dimension that has no explicit entry with taxonomy faceting (FastTaxonomyFacetCounts, both constructors, and the value-source aggregation of TaxonomyFacetFloatAssociations, which calls the same rollup(), all executed): the dimension count and every non-leaf label count read 0 and getTopChildren(dim) returns null or only the depth-1 leaves, with no error, while leaf counts, drill-down, SortedSetDocValues faceting and explicitly configured dimensions stay correct; opt-in, no scale needed, deterministic with -ea and -da, every release since 4.7.0 (4.8.0 through the documented extension point).
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.
Introduced
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: git log -S'getDimConfigs().entrySet()', git blame -w -C -C -M and git tag --contains in the history clone]. Not a regression: a latent assumption from when the only default was the static, flat DEFAULT_DIM_CONFIG (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: the probes do not compile and the jars contain no FacetsConfig.class]
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, getDimConfig-override probe]; 4.8.0 to 10.5.2 (116 releases) also with the getDefaultDimConfig override [exec]; main a9779ef3c193 [exec, -ea and -da]. 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]; the released 10.6.0 is affected too [exec, 2026-11-04: the minimal test fails on its jars with -ea and -da, and on main 5adff78bb168], and no open PR changes rollup() or getDimConfigs(). All runs on JDK 25, 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
semi-formal: exhaustive check, code reading
Upstream and prior reports
related items only, no report of this defect (searched 2026-10-27, read-only, re-checked 2026-11-03; 301 queries: three scripted prior-report searches over apache/lucene issues, PRs and commits, downstream repositories, the dev@, java-user@, issues@ and commits@ lists, the JIRA archive and the web, plus the finder's 51-query run and the intended-behaviour check's 43-query run; 41 manual GitHub issue searches over apache/lucene, lucene-solr, solr, lucenenet, Elasticsearch and OpenSearch; the changed files of all 409 open apache/lucene PRs; 9 JQL enumerations with 13 issues grepped; 9 list terms with 37 messages read; a GitHub code search for getDefaultDimConfig; Stack Overflow). No issue, PR, commit, JIRA entry, mailing-list thread, Q&A post or web page reports the core miscount. The closest related item: merged sandbox PR #14237 (epotyom, 2025-03-03; in 10.2.0 to 10.5.2), whose TaxonomyFacetBuilder constructor (lucene/sandbox, TaxonomyFacetBuilder.java:47-58 on a9779ef3c193) throws unless the dimension is configured explicitly, with the comment that the sandbox TaxonomyFacetsCutter 'uses FacetConfig#getDimConfigs to find dimensions that need to be rolled up, hence it needs the dimension to be configured explicitly'; it concerns the sandbox cutter (a different, out-of-scope fix site, with the flat default as its trigger), says nothing about core TaxonomyFacets, getDefaultDimConfig or wrong counts, and the PR discussion does not mention it. Related, not this bug: #6863 (LUCENE-5801, 2014, fixed: OrdinalMappingAtomicReader collected facet fields only from getDimConfigs(), reported as 'wrong facet data'; precedent, and the fix site of another finding, LFV-722), #11780 (open draft; a 2023 review comment by gsmiller that a getDimConfigs() enumeration does not know fields that use the default dim config, in an unmerged SortedSetDocValues helper), #6542 (LUCENE-5479, added getDefaultDimConfig; discussion only about multiValued = true), #6403 (LUCENE-5339), #12966 and #13358 (moved the loop), #6599 (LUCENE-5536, unrelated), and a 2014 java-user thread with the same symptom caused by different FacetsConfig instances at index and search time. Not fixed: no open PR changes rollup() or getDimConfigs(); upstream main (2 commits past a9779ef3c193, neither in facet), branch_10x and branch_10_6 are unchanged. Downstream: the getDefaultDimConfig overrides found (seecr/meresco-lucene, voyanttools/trombone) all use multiValued = true, which is unaffected. Gaps: general web search was only partly available (the 18 planned web queries were not run), GitHub search reads the first 100 results per query, solr-user@ was not read
Lucene commit tested
main 5adff78bb168 (gradle in a scratch worktree and the JUnit runner, assertions on and off) and the released 10.6.0, 10.5.2, 9.12.3 and 9.1.0 jars, 2026-11-04. Earlier runs: main a9779ef3c193 and ea57360912ed (identical facet sources) and e1faeba08bde; two version-portable probes on every lucene-facet release from 4.7.0 to 10.5.2.

Lucene and upstream sources

Finding record
  • lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyFacets.java:261-285 (at a9779ef3c193) (rollup(), javadoc 'Rolls up any single-valued hierarchical dimensions', loop over config.getDimConfigs().entrySet() at :269) and :537-541 (getSpecificValue: 'ok: rolled up at search time'); lucene/facet/src/java/org/apache/lucene/facet/FacetsConfig.java:141-151 (protected getDefaultDimConfig and its javadoc), :153-160 (getDimConfig falls back to it), :162-168 (isDimConfigured javadoc still names DEFAULT_DIM_CONFIG), :228-231 (getDimConfigs returns only the explicit map), :370-398 (processFacetFields uses getDimConfig; ancestors added only when multiValued, :386-398); taxonomy/FastTaxonomyFacetCounts.java:117 and :174 and taxonomy/TaxonomyFacetFloatAssociations.java:165 (callers of rollup()); lucene/facet/src/test/org/apache/lucene/facet/TestFacetsConfig.java:104-115 (testCustomDefault, LUCENE-5479, hierarchical = true); lucene/sandbox/src/java/org/apache/lucene/sandbox/facet/utils/TaxonomyFacetBuilder.java:47-58 (#14237 comment and check)
The finding in 30 seconds
  • lucene/facet/src/java/org/apache/lucene/facet/FacetsConfig.java:142-160 (at 5adff78bb168) (getDefaultDimConfig, getDimConfig), :228-231 (getDimConfigs), :370-398 (processFacetFields)
  • lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyFacets.java:261-285 (at 5adff78bb168) (rollup, loop at :269), :308-310, :478-503, :540-541, :553, :564-578
  • lucene/facet/src/java/org/apache/lucene/facet/taxonomy/FastTaxonomyFacetCounts.java:93, (at 5adff78bb168) :117, :138, :174; TaxonomyFacetFloatAssociations.java:164-165; lucene/facet/src/java/org/apache/lucene/facet/DrillSideways.java:159, :165
  • lucene/facet/src/java/org/apache/lucene/facet/taxonomy/OrdinalMappingLeafReader.java:136; (at 5adff78bb168) lucene/sandbox/src/java/org/apache/lucene/sandbox/facet/cutters/TaxonomyFacetsCutter.java:119; lucene/sandbox/src/java/org/apache/lucene/sandbox/facet/utils/TaxonomyFacetBuilder.java:48-59
  • lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyFacets.java:595-660 (at 5adff78bb168) (getTopDims); TaxonomyFacetFloatAssociations.java:54-61, :84-93, :169 and TaxonomyFacetIntAssociations.java:41-62 (indexed-association constructors and aggregation, no rollup() call; the only rollup() call in the class is the value-source path, :165)
Minimal repro
  • Lucene main 5adff78bb168 build-tools/build-infra/src/main/java/org/apache/lucene/gradle/plugins/java/TestsAndRandomizationPlugin.java:240-248 (tests.asserts default drawn from the seed)
Why it looks unintended
  • lucene/facet/src/java/org/apache/lucene/facet/FacetsConfig.java:49-51 (at 5adff78bb168) (class javadoc), :142-151 (getDefaultDimConfig javadoc), :162-168 (isDimConfigured javadoc), :371-378
  • lucene/CHANGES.txt:12462-12463 (at 5adff78bb168) (LUCENE-5479, 4.8.0)
  • lucene/facet/src/test/org/apache/lucene/facet/TestFacetsConfig.java:104-117 (at 5adff78bb168) (testCustomDefault)
  • lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyFacets.java:261 (at 5adff78bb168) (rollup javadoc), :541
Suggested fix
  • lucene/facet/src/test/org/apache/lucene/facet/taxonomy/TestTaxonomyFacetCounts.java:451-452; (at 5adff78bb168) TestTaxonomyFacetValueSource.java:520-521 (laziness assertions)
  • lucene/facet/src/java/org/apache/lucene/facet/FacetField.java:69-73 (at 5adff78bb168) (empty dimension rejected)
Diagrams
  • lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyFacets.java:261-285; (at 5adff78bb168) lucene/facet/src/java/org/apache/lucene/facet/FacetsConfig.java:228-231, :370-398

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

Repro files

About the diagrams

A walk-through of the minimal repro's input, made from the code at 5adff78bb168 and the executed runs; the PNG is the summary still.

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.