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
- Change the field's underlying Avro type to long in the schema
- Use the int-compatible logical type (time-millis/local timestamp micros only if long) that matches your base type
- 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
- Validate hand-written schemas against logical-type constraints before registering them
- Use Avro schema linting in CI
- Never hand-edit the underlying type of logical-typed fields
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
- Unknown logical type " + identifier
- An explicit schema is required to write non-schema'd…
- beam.RegisterSchemaProvider: schema type provider for
- Cannot find a matching Calcite SqlTypeName for Beam logical…
- Could not infer Beam schema for class
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)