elastic/elasticsearch · critical · IOException
Failed to merge GPU index:
Error message
Failed to merge GPU index:
What it means
Thrown by the lambda returned from ES92GpuHnswVectorsWriter.mergeOneField() when any Throwable occurs during the GPU-accelerated segment merge. This wraps all exceptions from the merge pipeline: opening the flat reader, reading float/byte vectors, acquiring GPU resources, building the CAGRA index, and writing the merged graph. The exception is always wrapped in an IOException regardless of the original type.
Solutions
- Inspect IOException.getCause() for the root exception.
- If GPU resource contention, reduce index.merge.scheduler.max_thread_count or the number of concurrent merges.
- If the cause is in the BYTE/quantized merge path, verify that QuantizedVectorsReader returns valid data (the assert at line 650 checks flatVectorsReader instanceof QuantizedVectorsReader).
- For MemorySegment mapping failures in the merge path, check that the merged segment's directory is an FSDirectory (see error 612).
- Consider disabling the GPU codec for problematic indices as a diagnostic step.
Defensive patterns
Strategy: try-catch
Try / catch
try {
IORunnable mergeTask = writer.mergeOneField(fieldInfo, mergeState);
mergeTask.run();
} catch (IOException e) {
Throwable cause = e.getCause();
logger.warn("GPU merge failed for field {}, falling back or investigating: {}", fieldInfo.name, cause);
throw e;
} Prevention
- Limit concurrent merges to avoid GPU resource contention.
- Ensure the merged segment directory is an FSDirectory for mmap fallback.
- Verify quantized vector readers return valid data for BYTE merge path.
- Monitor GPU memory during large segment merges.
When it happens
Trigger: Failure during Lucene segment merging when the GPU codec is active. This includes: flat reader open failures, vector iteration failures, GPU resource acquisition failures, CAGRA index build failures during merge, MemorySegment mapping failures for merged data, or quantized vector reading failures (for int8_hnsw fields).
Common situations: Large segment merges exceeding GPU memory; corrupted merged vector data; quantized vector reader returning unexpected data during BYTE merge path; concurrent merge threads competing for GPU resources; disk I/O failures during temp file creation for large merged segments.
Related errors
- Failed to flush GPU index:
- Failed to write GPU index:
- attempt to retrieve score correction for different ord
- beamWidth must be positive and less than or equal to 3200…
- Dataset dimensions must be positive: rows=
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/30769b6f53b5e3bd.
Report an issue: GitHub.
Appendix: source
Thrown at libs/gpu-codec/src/main/java/org/elasticsearch/gpu/codec/ES92GpuHnswVectorsWriter.java:659
// we just build a mock graph where every node is connected to every other node
generateMockGraphAndWriteMeta(fieldInfo, numVectors);
} else if (dataType == CuVSMatrix.DataType.FLOAT) {
mergeFloatVectorField(fieldInfo, mergeState, floatVectorValues, numVectors);
} else {
// During merging, we use quantized data, so we need to support byte[] too.
// That's how our current formats work: use floats during indexing, and quantized data to build a graph
// during merging.
assert dataType == CuVSMatrix.DataType.BYTE;
assert flatVectorsReader instanceof QuantizedVectorsReader;
BaseQuantizedByteVectorValues byteVectorValues = ((QuantizedVectorsReader) flatVectorsReader).getQuantizedVectorValues(
fieldInfo.name
);
mergeByteVectorField(fieldInfo, mergeState, byteVectorValues, numVectors);
}
var elapsed = System.nanoTime() - started;
logger.debug("Merged [{}] vectors in [{}ms]", numVectors, elapsed / 1_000_000.0);
} catch (Throwable t) {
throw new IOException("Failed to merge GPU index: ", t);
}
};
}
private void mergeByteVectorField(
FieldInfo fieldInfo,
MergeState mergeState,
BaseQuantizedByteVectorValues byteVectorValues,
int numVectors
) throws IOException, InterruptedException {
CagraIndexParams cagraIndexParams = createCagraIndexParams(
fieldInfo.getVectorSimilarityFunction(),
numVectors,
fieldInfo.getVectorDimension()
);
IndexInput slice = byteVectorValues.getSlice();
var input = slice == null ? null : FilterIndexInput.unwrap(slice);View on GitHub (pinned to db6a809a66)