elastic/elasticsearch · error · IllegalArgumentException
Pitch needs to be at least {}
Error message
Pitch needs to be at least {} What it means
Thrown by dotProductI7uBulkWithOffsets() in SimdVecLibrary before dispatching to the native vec_doti7u_bulk_with_offsets kernel. The pitch parameter is the byte stride between consecutive rows in the dataset MemorySegment (row-major layout). For 7-bit unsigned integer vectors, each element is 1 byte, so a row of 'length' elements occupies 'length' bytes. Pitch must be >= length so rows do not overlap. This is a hard pre-check (IllegalArgumentException), while the subsequent assert validateBulkOffsets is a secondary bounds check enabled only with -ea.
Source
Thrown at libs/native/src/main/java/org/elasticsearch/nativeaccess/SimdVecLibrary.java:193
@VectorSegment(countParam = "length", elementBits = Byte.SIZE) MemorySegment query,
int length,
int pitch,
@VectorSegment(countParam = "count", elementBits = Integer.SIZE, aligned = true) MemorySegment offsets,
int count,
@VectorSegment(countParam = "count", elementBits = Float.SIZE, aligned = true) MemorySegment scores
);
public void dotProductI7uBulkWithOffsets(
MemorySegment dataset,
MemorySegment query,
int length,
int pitch,
MemorySegment offsets,
int count,
MemorySegment scores
) {
if (pitch < length) {
throw new IllegalArgumentException("Pitch needs to be at least " + length);
}
assert validateBulkOffsets(dataset, offsets, count, pitch, length);
dotProductI7uBulkWithOffsets_raw(dataset, query, length, pitch, offsets, count, scores);
}
@Function("vec_doti7u_bulk_sparse")
@Critical(fallbackAdapter = Critical.UnsupportedFallback.class)
protected abstract void dotProductI7uBulkSparse_raw(
@VectorSegment(countParam = "count", elementBits = Long.SIZE, aligned = true) MemorySegment addresses,
@VectorSegment(countParam = "length", elementBits = Byte.SIZE) MemorySegment query,
int length,
int count,
@VectorSegment(countParam = "count", elementBits = Float.SIZE, aligned = true) MemorySegment scores
);
public void dotProductI7uBulkSparse(MemorySegment addresses, MemorySegment query, int length, int count, MemorySegment scores) {
assert validateBulkSparse(addresses, count);
dotProductI7uBulkSparse_raw(addresses, query, length, count, scores);View on GitHub (pinned to db6a809a66)
Solutions
- Ensure pitch >= length. For a tightly-packed i7u dataset (no per-row padding), set pitch = length.
- If the dataset has per-row alignment padding, set pitch to the actual byte stride including padding.
- Verify the offsets array is computed as row_start_byte / pitch (each offsets[i] indexes into the matrix by row unit).
- Double-check that 'length' is the number of vector elements (7-bit unsigned integers), not the byte count of the query.
Example fix
// before: pitch smaller than row width int length = 128; int pitch = 100; // BUG: must be >= 128 lib.dotProductI7uBulkWithOffsets(dataset, query, length, pitch, offsets, count, scores); // after: pitch equals row width for tightly-packed data int pitch = length; // 128 bytes = 128 elements * 1 byte/element lib.dotProductI7uBulkWithOffsets(dataset, query, length, pitch, offsets, count, scores);
Defensive patterns
Strategy: validation
Validate before calling
// Validate pitch before calling dotProductI7uBulkWithOffsets.
// For i7u vectors, each element is 1 byte, so row width = length bytes.
void safeDotProductI7uBulkWithOffsets(SimdVecLibrary lib, MemorySegment dataset, MemorySegment query,
int length, int pitch, MemorySegment offsets, int count, MemorySegment scores) {
if (pitch < length) {
throw new IllegalArgumentException(
"pitch (" + pitch + ") must be >= length (" + length + ") for i7u vectors");
}
lib.dotProductI7uBulkWithOffsets(dataset, query, length, pitch, offsets, count, scores);
} Prevention
- Always compute pitch from the element size: for byte-sized types (i7u, i8), pitch >= length in bytes.
- For tightly-packed datasets, set pitch = length (no padding).
- Verify offsets[i] * pitch + length does not exceed dataset.byteSize() before calling.
- Use a helper function that derives pitch from the data layout to avoid manual miscalculation.
When it happens
Trigger: Calling dotProductI7uBulkWithOffsets(dataset, query, length, pitch, offsets, count, scores) where pitch < length. The dataset is a row-major matrix indexed by offsets[i] * pitch. Pitch represents the byte distance from the start of one row to the next.
Common situations: Caller computed pitch in elements instead of bytes (though for byte-sized types these are the same); caller used a padded matrix but passed the unpadded length as pitch by mistake; caller confused the 'length' (number of vector elements per row) with 'pitch' (byte stride including padding).
Related errors
- vector dimensions incompatible: {}!= {}
- vector dimensions incompatible
- distances array must have length >= 4, but was: {}
- distancesOffset must be between 0 and distances.length - 4
- distances array must have length 4, but was: {}
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/adfc41d963e8b56a.
Report an issue: GitHub.