prestodb/presto · error · IllegalArgumentException

Unexpected type:

Error message

Unexpected type: 

What it means

VariantUtil.getType decodes the Variant binary encoding: it reads the header byte at `position`, splits it into a basic type (low bits) and type-info (high bits), and maps the primitive type-info codes to a Type enum. This IllegalArgumentException is the MALFORMED_VARIANT guard thrown from the `default` branch when the type-info bits encode a value this library does not recognize — either the variant binary is corrupt/truncated or it was produced by a writer using a newer type code this reader does not know.

Source

Thrown at presto-parquet/src/main/java/com/facebook/presto/parquet/spark/VariantUtil.java:245

                        return Type.DOUBLE;
                    case DECIMAL4:
                    case DECIMAL8:
                    case DECIMAL16:
                        return Type.DECIMAL;
                    case DATE:
                        return Type.DATE;
                    case TIMESTAMP:
                        return Type.TIMESTAMP;
                    case TIMESTAMP_NTZ:
                        return Type.TIMESTAMP_NTZ;
                    case FLOAT:
                        return Type.FLOAT;
                    case BINARY:
                        return Type.BINARY;
                    case LONG_STR:
                        return Type.STRING;
                    default:
                        throw new IllegalArgumentException("Unexpected type: " + typeInfo);
                }
        }
    }

    private static IllegalStateException unexpectedType(Type type)
    {
        return new IllegalStateException("Expect type to be " + type);
    }

    // Get a boolean value from variant value `value[position...]`.
    // Throw `MALFORMED_VARIANT` if the variant is malformed.
    public static boolean getBoolean(byte[] value, int position)
    {
        checkIndex(position, value.length);
        int basicType = value[position] & BASIC_TYPE_MASK;
        int typeInfo = (value[position] >> BASIC_TYPE_BITS) & TYPE_INFO_MASK;
        if (basicType != PRIMITIVE || (typeInfo != TRUE && typeInfo != FALSE)) {
            throw unexpectedType(Type.BOOLEAN);

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Verify the producer and consumer use compatible Variant binary spec versions; upgrade the presto-parquet reader to match the writer
  2. Re-read the source Parquet file / regenerate the variant data to rule out corruption
  3. Validate the variant byte array (header byte, offsets, lengths) before calling getType
  4. Catch IllegalArgumentException from getType and treat the value as malformed rather than crashing the read

Example fix

// before
Type t = VariantUtil.getType(value, pos);
// after
Type t;
try {
    t = VariantUtil.getType(value, pos);
} catch (IllegalArgumentException e) {
    t = Type.NULL; // or surface a corrupt-row metric
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Java
static boolean looksLikeKnownVariantType(byte[] value, int position) {
    if (position < 0 || position >= value.length) return false;
    int basicType = value[position] & 0x3;
    if (basicType == 0x1 || basicType == 0x2 || basicType == 0x3) return true; // SHORT_STR/OBJECT/ARRAY
    int typeInfo = (value[position] >> 2) & 0x3f;
    return typeInfo <= 15; // all known primitive type codes are contiguous low values
}

Type guard

// Java
static boolean isReadableVariant(byte[] value, int position) {
    try { VariantUtil.getType(value, position); return true; }
    catch (RuntimeException e) { return false; }
}

Try / catch

// Java
try {
    Type t = VariantUtil.getType(value, pos);
    // use t
} catch (IllegalArgumentException e) {
    log.warn("Malformed variant type at pos " + pos, e);
    // skip row / mark corrupt
}

Prevention

When it happens

Trigger: Calling VariantUtil.getType(byte[] value, int position) on a variant value whose header byte has basicType == PRIMITIVE but a typeInfo code not in the known set (NULL, TRUE/FALSE, INT1/2/4/8, DOUBLE, DECIMAL4/8/16, DATE, TIMESTAMP, TIMESTAMP_NTZ, FLOAT, BINARY, LONG_STR), typically because the bytes are corrupted or written by a newer Spark Variant spec.

Common situations: Reading Parquet files with variant columns written by a newer Spark/other-engine version that added type codes; corrupted or hand-crafted variant byte arrays; passing the wrong byte[] or a non-variant blob to getType.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/be714c1cfe25741e. Report an issue: GitHub.