apache/flink · error · VariantTypeException

Expecting a primitive variant but got %s

Error message

Expecting a primitive variant but got %s

What it means

BinaryVariant.get() switches on the variant's type tag and materializes the primitive value; the default branch throws VariantTypeException because the stored type is not one of the handled primitive kinds (it is likely an OBJECT or ARRAY, i.e. a compound value).

Source

Thrown at flink-core/src/main/java/org/apache/flink/types/variant/BinaryVariant.java:232

                return getLong();
            case FLOAT:
                return getFloat();
            case DOUBLE:
                return getDouble();
            case DECIMAL:
                return getDecimal();
            case STRING:
                return getString();
            case DATE:
                return getDate();
            case TIMESTAMP:
                return getDateTime();
            case TIMESTAMP_LTZ:
                return getInstant();
            case BYTES:
                return getBytes();
            default:
                throw new VariantTypeException(
                        String.format("Expecting a primitive variant but got %s", getType()));
        }
    }

    @Override
    public <T> T getAs() throws VariantTypeException {
        return (T) get();
    }

    @Override
    public Variant getElement(int index) throws VariantTypeException {
        return getElementAtIndex(index);
    }

    @Override
    public int getArraySize() throws VariantTypeException {
        return handleArray(value, pos, (size, offsetSize, offsetStart, dataStart) -> size);
    }

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Branch on getType() first: use getObject(...)/getArray(...) for OBJECT/ARRAY and get() for primitives
  2. If the value should be a scalar, fix the producer that wrote a nested object/array into this variant
  3. Use the typed accessors (getString, getLong, ...) which give clearer errors, after a type check

Example fix

// before
Object v = variant.get(); // throws if variant holds an object

// after
Object v;
switch (variant.getType()) {
    case OBJECT: v = variant.getObject(); break;
    case ARRAY:  v = variant.getArray();  break;
    default:     v = variant.get();       break;
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (variant.getType() == VariantType.OBJECT || variant.getType() == VariantType.ARRAY) {
    /* use getObject()/getArray() instead of get() */
}

Type guard

static boolean isPrimitiveVariant(Variant v) {
    VariantType t = v.getType();
    return t != VariantType.OBJECT && t != VariantType.ARRAY;
}

Try / catch

catch (VariantTypeException e) { /* fall back to per-type handling based on getType() */ }

Prevention

When it happens

Trigger: Calling get()/getAs() on a Variant whose getType() is OBJECT or ARRAY (or an unknown future type tag). get() is intended for primitives only; getObject/getArray must be used for compound types.

Common situations: Schema-on-read pipelines where a column is Variant and some rows hold objects/arrays while code assumes scalars; upstream producer changed a field from a scalar to a nested object; generic code doing variant.getAs() without first checking type.

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/f70cc5b3b39169b2. Report an issue: GitHub.