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

  1. Ensure pitch >= length. For a tightly-packed i7u dataset (no per-row padding), set pitch = length.
  2. If the dataset has per-row alignment padding, set pitch to the actual byte stride including padding.
  3. Verify the offsets array is computed as row_start_byte / pitch (each offsets[i] indexes into the matrix by row unit).
  4. 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

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


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/adfc41d963e8b56a. Report an issue: GitHub.