[BUG] CPU fallback for the quantized accelerated-HNSW Lucene codecs throws instead of falling back
Nobody has claimed this yet.
- Dominant language
- Cuda
- Stars
- 854
- Forks
- 236
- Avg merge
- 3d 3h
- Merged PRs (30d)
- 62
Description
Describe the bug
The CPU fallback path in LuceneAcceleratedHNSWScalarQuantizedVectorsFormat and LuceneAcceleratedHNSWBinaryQuantizedVectorsFormat is broken. When cuVS resources cannot be created, both log GPU based indexing not supported, falling back to using the ... and then throw instead of falling back.
Steps to reproduce
Try loading the codecs
package com.nvidia.cuvs.repro;
import static com.nvidia.cuvs.lucene.ThreadLocalCuVSResourcesProvider.setCuVSResourcesInstance;
import static org.apache.lucene.index.VectorSimilarityFunction.EUCLIDEAN;
import com.nvidia.cuvs.lucene.AcceleratedHNSWParams;
import com.nvidia.cuvs.lucene.Lucene101AcceleratedHNSWCodec;
import com.nvidia.cuvs.lucene.LuceneAcceleratedHNSWBinaryQuantizedCodec;
import com.nvidia.cuvs.lucene.LuceneAcceleratedHNSWScalarQuantizedCodec;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Random;
import org.apache.lucene.codecs.Codec;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.KnnFloatVectorField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
/**
* Indexes a few vectors with each accelerated HNSW codec while cuVS resources are unavailable.
*
* <p>All three codecs are documented to fall back to CPU index construction in this state.
* Only {@code Lucene101AcceleratedHNSWCodec} does; the two quantized variants throw.
*/
public class FallbackRepro {
private static final int NUM_DOCS = 16;
private static final int DIMENSION = 8;
public static void main(String[] args) throws Exception {
// Force the !isSupported() branch on this thread, the same way
// TestCagraToHnswSerializationAndSearchWithFallbackWriter does.
setCuVSResourcesInstance(null);
AcceleratedHNSWParams params = new AcceleratedHNSWParams.Builder().build();
index("Lucene101AcceleratedHNSWCodec", new Lucene101AcceleratedHNSWCodec(params));
index("LuceneAcceleratedHNSWScalarQuantizedCodec", new LuceneAcceleratedHNSWScalarQuantizedCodec(params));
index("LuceneAcceleratedHNSWBinaryQuantizedCodec", new LuceneAcceleratedHNSWBinaryQuantizedCodec(params));
}
private static void index(String label, Codec codec) {
Random random = new Random(222);
IndexWriterConfig config = new IndexWriterConfig().setCodec(codec);
try {
Path indexPath = Files.createTempDirectory("cuvs-fallback-repro");
try (Directory directory = FSDirectory.open(indexPath);
IndexWriter writer = new IndexWriter(directory, config)) {
for (int i = 0; i < NUM_DOCS; i++) {
float[] vector = new float[DIMENSION];
for (int j = 0; j < DIMENSION; j++) {
vector[j] = random.nextFloat() * 100;
}
Document document = new Document();
document.add(new KnnFloatVectorField("vector_field", vector, EUCLIDEAN));
writer.addDocument(document);
}
}
System.out.printf("%-45s OK%n", label);
} catch (Throwable t) {
System.out.printf("%-45s %s%n", label, t);
}
}
}
output:
WARNING: Java vector incubator module is not readable. For optimal vector performance, pass '--add-modules jdk.incubator.vector' to enable Vector API.
Sep 16, 2026 5:38:43 PM com.nvidia.cuvs.lucene.Lucene99AcceleratedHNSWVectorsFormat fieldsWriter
WARNING: GPU based indexing not supported, falling back to using the Lucene99HnswVectorsWriter
Lucene101AcceleratedHNSWCodec OK
Sep 16, 2026 5:38:44 PM com.nvidia.cuvs.lucene.LuceneAcceleratedHNSWScalarQuantizedVectorsFormat fieldsWriter
WARNING: GPU based indexing not supported, falling back to using the Lucene99HnswScalarQuantizedVectorsFormat
Sep 16, 2026 5:38:44 PM com.nvidia.cuvs.lucene.LuceneProvider getLuceneHnswScalarQuantizedVectorsFormatInstance
SEVERE: Unable to initialize LuceneHnswScalarQuantizedVectorsFormat: class org.apache.lucene.codecs.lucene99.Lucene99HnswScalarQuantizedVectorsFormat cannot be cast to class org.apache.lucene.codecs.hnsw.FlatVectorsFormat (org.apache.lucene.codecs.lucene99.Lucene99HnswScalarQuantizedVectorsFormat and org.apache.lucene.codecs.hnsw.FlatVectorsFormat are in unnamed module of loader org.codehaus.mojo.exec.URLClassLoaderBuilder$ExecJavaClassLoader @5f7989fa)
LuceneAcceleratedHNSWScalarQuantizedCodec java.lang.ClassCastException: class org.apache.lucene.codecs.lucene99.Lucene99HnswScalarQuantizedVectorsFormat cannot be cast to class org.apache.lucene.codecs.hnsw.FlatVectorsFormat (org.apache.lucene.codecs.lucene99.Lucene99HnswScalarQuantizedVectorsFormat and org.apache.lucene.codecs.hnsw.FlatVectorsFormat are in unnamed module of loader org.codehaus.mojo.exec.URLClassLoaderBuilder$ExecJavaClassLoader @5f7989fa)
Sep 16, 2026 5:38:44 PM com.nvidia.cuvs.lucene.LuceneAcceleratedHNSWBinaryQuantizedVectorsFormat fieldsWriter
WARNING: GPU based indexing not supported, falling back to using the Lucene102HnswBinaryQuantizedVectorsFormat
Sep 16, 2026 5:38:44 PM com.nvidia.cuvs.lucene.LuceneProvider getLuceneHnswBinaryQuantizedVectorsFormatInstance
SEVERE: Unable to initialize LuceneBinaryQuantizedVectorsFormat: Cannot invoke "java.lang.Class.getConstructor(java.lang.Class[])" because "this.hnswBinaryQuantizedVectorsFormat" is null
LuceneAcceleratedHNSWBinaryQuantizedCodec java.lang.NullPointerException: Cannot invoke "java.lang.Class.getConstructor(java.lang.Class[])" because "this.hnswBinaryQuantizedVectorsFormat" is null
Additional context covers three things:
The NullPointerException is already tracked in #2615 as part of another set of issues.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with fieldsWriter in LuceneAcceleratedHNSWScalarQuantizedVectorsFormat and LuceneAcceleratedHNSWBinaryQuantizedVectorsFormat, then inspect the corresponding fallback methods in LuceneProvider. Reproduce the issue with setCuVSResourcesInstance(null) and the provided codec-loading example. Done means both quantized codecs index successfully through their CPU fallback without throwing.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- search
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100