apache/beam · error · IllegalArgumentException

Local timestamp (millis) can only be used with an…

Error message

Local timestamp (millis) can only be used with an underlying long type

What it means

The LocalTimestampMillis Avro logical type is only defined over Avro 'long' underlying types. Its validate() checks the schema type and throws IllegalArgumentException if the underlying type is anything other than LONG.

Solutions

  1. Change the field's underlying Avro type to long in the schema
  2. Use the int-compatible logical type (time-millis/local timestamp micros only if long) that matches your base type
  3. Regenerate the schema from the source of truth so the logical type matches long

Example fix

// before
{"name": "ts", "type": "int", "logicalType": "local-timestamp-millis"}
// after
{"name": "ts", "type": {"type": "long", "logicalType": "local-timestamp-millis"}}
Defensive patterns

Strategy: validation

Validate before calling

for (Schema.Field f : schema.getFields()) {
  Object lt = f.schema().getLogicalType();
  if (lt instanceof LogicalTypes.LocalTimestampMillis && f.schema().getType() != Schema.Type.LONG)
    throw new IllegalArgumentException("local-timestamp-millis requires long: " + f.name());
}

Type guard

static boolean isValidLocalTimestampMillis(Schema s) {
  return !(s.getLogicalType() instanceof LogicalTypes.LocalTimestampMillis)
      || s.getType() == Schema.Type.LONG;
}

Try / catch

try { conversion.validate(schema); } catch (IllegalArgumentException e) { /* fix underlying type to long */ }

Prevention

When it happens

Trigger: Attaching the local-timestamp-millis logical type to a schema field whose base type is int, string, etc., then validating/reading the schema through AvroJavaTimeConversions.

Common situations: Hand-written Avro schemas that declare timestamp-millis fields as int or string; schema registries with mistyped logical-type fields; schema evolution changing the underlying type.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

 *
 * <p>This code is copied from avro 1.10.2 TimeConversions.
 */
public class AvroJavaTimeConversions {

  // Not defined in avro 1.8.2
  private static final String LOCAL_TIMESTAMP_MILLIS = "local-timestamp-millis";
  private static final String LOCAL_TIMESTAMP_MICROS = "local-timestamp-micros";

  public static class LocalTimestampMillis extends LogicalType {
    private LocalTimestampMillis() {
      super(LOCAL_TIMESTAMP_MILLIS);
    }

    @Override
    public void validate(Schema schema) {
      super.validate(schema);
      if (schema.getType() != Schema.Type.LONG) {
        throw new IllegalArgumentException(
            "Local timestamp (millis) can only be used with an underlying long type");
      }
    }
  }

  public static class LocalTimestampMicros extends LogicalType {
    private LocalTimestampMicros() {
      super(LOCAL_TIMESTAMP_MICROS);
    }

    @Override
    public void validate(Schema schema) {
      super.validate(schema);
      if (schema.getType() != Schema.Type.LONG) {
        throw new IllegalArgumentException(
            "Local timestamp (micros) can only be used with an underlying long type");
      }
    }

View on GitHub (pinned to 12126d8942)