NVIDIA / NVIDIA/cuvs

[BUG] CPU fallback for the quantized accelerated-HNSW Lucene codecs throws instead of falling back

Open
#2,639 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug Lucene
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.