apache/iceberg · error · IllegalArgumentException

Avro does not support TIME type with precision

Error message

Avro does not support TIME type with precision: %s, it only supports precision less than 3.

What it means

Thrown when converting a Flink TIME (without time zone) type to an Avro schema whose precision exceeds 3. Avro represents time as timeMillis (an int with millisecond precision), so TIME(4)-TIME(9) cannot be represented. The message is slightly misleading: precision must be 3 or less (not strictly less than 3).

Solutions

  1. Cast the column to TIME(3) (or TIME(0)) before writing.
  2. Define the column as TIME(3) in the table DDL to match Avro's timeMillis.
  3. If sub-millisecond precision is required, use a different format (Parquet) or store as an integer/bigint.
  4. Round or truncate time values at the source pipeline stage.

Example fix

// before
// `t` TIME(6)
// after
// Flink DDL: `t` TIME(3)  -- maps to avro timeMillis
Defensive patterns

Strategy: validation

Validate before calling

if (logicalType instanceof TimeType && ((TimeType) logicalType).getPrecision() > 3) { throw new IllegalArgumentException("Cast TIME(p) to TIME(3) before Avro serialization"); }

Prevention

When it happens

Trigger: Calling AvroSchemaConverter.convertToSchema with a TimeType of precision > 3.

Common situations: Flink tables with TIME(6) or TIME(9) columns (e.g. microsecond time from upstream systems) serialized to Avro files or Avro-encoded Kafka records.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/7127b43ea63ca908. Report an issue: GitHub.

Appendix: source

Thrown at flink/v2.3/flink/src/main/java/org/apache/iceberg/flink/formats/avro/typeutils/AvroSchemaConverter.java:538

            avroLogicalType = LogicalTypes.timestampMicros();
          } else {
            throw new IllegalArgumentException(
                "Avro does not support TIMESTAMP type "
                    + "with precision: "
                    + precision
                    + ", it only supports precision less than 6.");
          }
          timestamp = avroLogicalType.addToSchema(SchemaBuilder.builder().longType());
          return nullable ? nullableSchema(timestamp) : timestamp;
        }
      case DATE:
        // use int to represents Date
        Schema date = LogicalTypes.date().addToSchema(SchemaBuilder.builder().intType());
        return nullable ? nullableSchema(date) : date;
      case TIME_WITHOUT_TIME_ZONE:
        precision = ((TimeType) logicalType).getPrecision();
        if (precision > 3) {
          throw new IllegalArgumentException(
              "Avro does not support TIME type with precision: "
                  + precision
                  + ", it only supports precision less than 3.");
        }
        // use int to represents Time, we only support millisecond when deserialization
        Schema time = LogicalTypes.timeMillis().addToSchema(SchemaBuilder.builder().intType());
        return nullable ? nullableSchema(time) : time;
      case DECIMAL:
        DecimalType decimalType = (DecimalType) logicalType;
        // store BigDecimal as byte[]
        Schema decimal =
            LogicalTypes.decimal(decimalType.getPrecision(), decimalType.getScale())
                .addToSchema(SchemaBuilder.builder().bytesType());
        return nullable ? nullableSchema(decimal) : decimal;
      case ROW:
        RowType rowType = (RowType) logicalType;
        List<String> fieldNames = rowType.getFieldNames();
        // we have to make sure the record name is different in a Schema

View on GitHub (pinned to 86d9c8fc54)