apache/beam · error · AssertionError

micros_instant logical type encountered a Java Instant with

Error message

micros_instant logical type encountered a Java Instant with greater than microsecond precision.

What it means

The micros_instant logical type represents instants with only microsecond precision. toBaseType throws an AssertionError if the java.time.Instant has sub-microsecond nanos (nano % 1000 != 0), since precision would be lost.

Source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/schemas/logicaltypes/MicrosInstant.java:56

 * NanosInstant}.
 */
public class MicrosInstant implements Schema.LogicalType<Instant, Row> {
  public static final String IDENTIFIER =
      SchemaApi.LogicalTypes.Enum.MICROS_INSTANT
          .getValueDescriptor()
          .getOptions()
          .getExtension(RunnerApi.beamUrn);
  // TODO(https://github.com/apache/beam/issues/20540): This should be a constant
  private final Schema schema;

  public MicrosInstant() {
    this.schema = Schema.builder().addInt64Field("seconds").addInt32Field("micros").build();
  }

  @Override
  public Row toBaseType(Instant input) {
    if (input.getNano() % 1000 != 0) {
      throw new AssertionError(
          "micros_instant logical type encountered a Java "
              + "Instant with greater than microsecond precision.");
    }
    return Row.withSchema(schema).addValues(input.getEpochSecond(), input.getNano() / 1000).build();
  }

  @Override
  public Instant toInputType(Row row) {
    return Instant.ofEpochSecond(
        checkArgumentNotNull(
            row.getInt64(0), "While trying to convert to Instant: Row missing seconds field"),
        checkArgumentNotNull(
                row.getInt32(1), "While trying to convert to Instant: Row missing micros field")
            * 1000);
  }

  @Override
  public String getIdentifier() {

View on GitHub (pinned to 12126d8942)

Solutions

  1. Truncate the Instant to microseconds before conversion: input.truncatedTo(ChronoUnit.MICROS).
  2. Normalize at the source (round/truncate timestamps when produced).
  3. If nanosecond precision is required, use a logical type that supports nanos instead of micros_instant.

Example fix

// before
Row r = Row.withSchema(schema).addValues(Instant.now(), ...).build();

// after
Instant t = Instant.now().truncatedTo(ChronoUnit.MICROS);
Row r = Row.withSchema(schema).addValues(t, ...).build();
Defensive patterns

Strategy: validation

Validate before calling

// Java: truncate instants to microsecond precision before use
Instant safe = input.truncatedTo(ChronoUnit.MICROS);

Type guard

// Java
public static boolean isMicrosPrecise(Instant t) { return t.getNano() % 1000 == 0; }

Prevention

When it happens

Trigger: Converting an Instant created with nanosecond precision (e.g. Instant.now() on JVMs reporting finer clocks, or truncatedFrom with NANOS) through a schema using MicrosInstant.

Common situations: Passing Instant.now() values directly into rows on JDK 9+ where the clock can have nanosecond resolution.

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/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/67746827bb5dc3d4. Report an issue: GitHub.