apache/beam · error · IllegalArgumentException

Can't represent as

Error message

Can't represent ${fieldType} as ${avroType}

What it means

Thrown by AvroUtils.genericFromBeamField when a Beam DATETIME field (backed by ReadableInstant) is converted to an Avro schema whose underlying type is neither INT (days since epoch) nor LONG (millis since epoch). Only those two Avro primitive types have a defined datetime encoding; anything else is unrepresentable.

Solutions

  1. Change the Avro schema for that field to type INT (dates as days since epoch) or LONG (millis since epoch)
  2. Convert the datetime to a string (or another supported representation) in the Beam schema before conversion, then parse it back on the Avro side
  3. Regenerate the Avro schema via AvroUtils.toAvroSchema(beamSchema) so DATETIME maps to the supported Avro type automatically
  4. If using a logical type, ensure its Avro underlying type is INT or LONG

Example fix

// before
{"name": "eventTime", "type": "string"}
// after
{"name": "eventTime", "type": {"type": "long", "logicalType": "timestamp-millis"}}
Defensive patterns

Strategy: validation

Validate before calling

boolean datetimeSupported(org.apache.avro.Schema fieldSchema) {
  org.apache.avro.Schema s = fieldSchema.getType() == org.apache.avro.Schema.Type.UNION
      ? fieldSchema.getTypes().stream().filter(t -> t.getType() != org.apache.avro.Schema.Type.NULL).findFirst().get()
      : fieldSchema;
  return s.getType() == org.apache.avro.Schema.Type.INT || s.getType() == org.apache.avro.Schema.Type.LONG;
}

Try / catch

try {
  GenericRecord record = AvroUtils.toGenericRecord(row, avroSchema);
} catch (IllegalArgumentException e) {
  if (e.getMessage() != null && e.getMessage().startsWith("Can't represent")) {
    throw new IllegalStateException("DATETIME field must map to Avro int/long; fix schema", e);
  } else { throw e; }
}

Prevention

When it happens

Trigger: Converting a Beam Row containing a DATETIME field to a GenericRecord whose corresponding Avro schema type is, e.g., STRING, DOUBLE, or a logical type not backed by INT/LONG — typically because the Avro schema was hand-written or generated with a mismatched type for the timestamp/date column.

Common situations: Hand-edited .avsc files where a timestamp column was typed as string; schema inference from a different source (e.g. a DB schema mapping a TIMESTAMP to string); mixing Beam DATETIME with Avro logical types like local-timestamp-* that resolve to unexpected underlying types in older Avro versions.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/ba1a6654a7f5a81d. Report an issue: GitHub.

Appendix: source

Thrown at sdks/java/extensions/avro/src/main/java/org/apache/beam/sdk/extensions/avro/schemas/utils/AvroUtils.java:1328

      case STRING:
        return new Utf8((String) value);

      case DECIMAL:
        BigDecimal decimal = (BigDecimal) value;
        LogicalType logicalType = typeWithNullability.type.getLogicalType();
        @SuppressWarnings("nullness")
        ByteBuffer result = new Conversions.DecimalConversion().toBytes(decimal, null, logicalType);
        return result;

      case DATETIME:
        if (typeWithNullability.type.getType() == org.apache.avro.Schema.Type.INT) {
          ReadableInstant instant = (ReadableInstant) value;
          return (int) Days.daysBetween(Instant.EPOCH, instant).getDays();
        } else if (typeWithNullability.type.getType() == org.apache.avro.Schema.Type.LONG) {
          ReadableInstant instant = (ReadableInstant) value;
          return (long) instant.getMillis();
        } else {
          throw new IllegalArgumentException(
              "Can't represent " + fieldType + " as " + typeWithNullability.type.getType());
        }

      case BYTES:
        return ByteBuffer.wrap((byte[]) value);

      case LOGICAL_TYPE:
        String identifier = checkNotNull(fieldType.getLogicalType()).getIdentifier();
        if (FixedBytes.IDENTIFIER.equals(identifier)) {
          FixedBytesField fixedBytesField =
              checkNotNull(FixedBytesField.fromBeamFieldType(fieldType));
          byte[] byteArray = (byte[]) value;
          if (byteArray.length != fixedBytesField.getSize()) {
            throw new IllegalArgumentException("Incorrectly sized byte array.");
          }
          return NullnessCheckerWorkarounds.createFixed(
              null, (byte[]) value, typeWithNullability.type);
        } else if (VariableBytes.IDENTIFIER.equals(identifier)) {

View on GitHub (pinned to 12126d8942)