prestodb/presto · error · IllegalArgumentException
Index out of bound: %s (size: %s)
Error message
Index out of bound: %s (size: %s)
What it means
This is thrown by the Variant metadata/dictionary accessor in VariantUtil: the metadata header's first two bits give the offset-size, the next bytes give the dictionary size (dictSize), and `id` must be a valid index into that dictionary. This IllegalArgumentException is raised when the requested variant dictionary id is >= dictSize, i.e. the caller asked for a string key that does not exist in the variant's metadata dictionary — normally a sign of malformed variant bytes or a misread offset.
Source
Thrown at presto-parquet/src/main/java/com/facebook/presto/parquet/spark/VariantUtil.java:497
// Extracts b1b0 to determine the integer size of the offset list.
int offsetSize = (typeInfo & 0x3) + 1;
int offsetStart = position + 1 + sizeBytes;
int dataStart = offsetStart + (size + 1) * offsetSize;
return handler.apply(size, offsetSize, offsetStart, dataStart);
}
// Get a key at `id` in the variant metadata.
// Throw `MALFORMED_VARIANT` if the variant is malformed. An out-of-bound `id` is also considered
// a malformed variant because it is read from the corresponding variant value.
public static String getMetadataKey(byte[] metadata, int id)
{
checkIndex(0, metadata.length);
// Extracts the highest 2 bits in the metadata header to determine the integer size of the
// offset list.
int offsetSize = ((metadata[0] >> 6) & 0x3) + 1;
int dictSize = readUnsigned(metadata, 1, offsetSize);
if (id >= dictSize) {
throw new IllegalArgumentException(String.format("Index out of bound: %s (size: %s)", id, dictSize));
}
// There are a header byte, a `dictSize` with `offsetSize` bytes, and `(dictSize + 1)` offsets
// before the string data.
int stringStart = 1 + (dictSize + 2) * offsetSize;
int offset = readUnsigned(metadata, 1 + (id + 1) * offsetSize, offsetSize);
int nextOffset = readUnsigned(metadata, 1 + (id + 2) * offsetSize, offsetSize);
if (offset > nextOffset) {
throw new IllegalArgumentException(String.format("Invalid offset: %s > %s", offset, nextOffset));
}
checkIndex(stringStart + nextOffset - 1, metadata.length);
return new String(metadata, stringStart + offset, nextOffset - offset, UTF_8);
}
}
View on GitHub (pinned to 55bb57d202)
Solutions
- Ensure the value[] and metadata[] byte arrays passed together come from the same variant cell
- Validate the metadata header (offsetSize, dictSize) before indexing and reject inconsistent pairs
- Re-read/regenerate the source Parquet data to rule out corruption
- Catch IllegalArgumentException and treat the variant object as malformed
Example fix
// before
String key = VariantUtil.getMetadataString(metadata, fieldId);
// after
try {
String key = VariantUtil.getMetadataString(metadata, fieldId);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Field id out of variant dictionary bounds: " + fieldId, e);
} Defensive patterns
Strategy: validation
Validate before calling
// Java
static boolean isIdInDictionary(byte[] metadata, int id) {
if (metadata == null || metadata.length == 0) return false;
int offsetSize = ((metadata[0] >> 6) & 0x3) + 1;
int dictSize = VariantUtil.readUnsigned(metadata, 1, offsetSize);
return id >= 0 && id < dictSize;
} Try / catch
// Java
try {
String key = VariantUtil.getMetadataString(metadata, id);
} catch (IllegalArgumentException e) {
// value/metadata mismatch or corrupt metadata: skip the row
} Prevention
- Always pass the value[] and metadata[] arrays from the same variant cell
- Check that offsetSize/dictSize parsed from the header are consistent with metadata.length
- Detect producer/consumer version mismatches in the Variant spec
- Handle per-row corrupt variants gracefully rather than aborting the query
When it happens
Trigger: Resolving an object field or array element in a Variant whose field-id `id` (read from the value's object header) is greater than or equal to the dictSize parsed from the metadata header — happens when value and metadata arrays do not belong together, or the metadata bytes are corrupt.
Common situations: Pairing a variant value[] from one row with a metadata[] from another; corrupted Parquet variant columns; writers that violate the Variant metadata layout so dictSize is parsed wrong.
Related errors
- Unexpected type:
- Invalid offset: %s > %s
- Decimal out of bound:
- Invalid position %s and length %s in page with %s positions
- Invalid channel %d in page with %s channels
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/ca4434d18fb07299.
Report an issue: GitHub.