apache/iceberg · error · IllegalStateException

Unknown type for timestamp_ns:

Error message

Unknown type for timestamp_ns: 

What it means

Within StructRowData.getTimestamp, when the Iceberg field is timestamp_ns, the stored value must be LocalDateTime (micros branch), Instant, or Long (nanoseconds). Any other class raises this IllegalStateException. It signals a nanosecond-timestamp value stored in an unexpected Java representation.

Solutions

  1. Ensure timestamp_ns values are stored as Long nanos, Instant, or LocalDateTime.
  2. Convert java.sql.Timestamp values to LocalDateTime/Instant before writing.
  3. Verify the Flink LogicalType precision (TimestampType(9) for timestamp_ns) matches the Iceberg field.

Example fix

// before
row.setField(pos, sqlTimestamp);

// after
row.setField(pos, sqlTimestamp.toInstant());
Defensive patterns

Strategy: type-guard

Validate before calling

if (type.equals(Types.TimestampNanoType.get())) {
  Object v = struct.getField(pos);
  if (!(v instanceof LocalDateTime || v instanceof Instant || v instanceof Long)) {
    throw new IllegalArgumentException("Bad timestamp_ns representation: " + v.getClass());
  }
}

Type guard

boolean isNanoTimestampCompatible(Object v) {
  return v instanceof LocalDateTime || v instanceof Instant || v instanceof Long;
}

Try / catch

try {
  TimestampData ts = rowData.getTimestamp(pos, 9);
} catch (IllegalStateException e) {
  // convert the offending value (e.g. java.sql.Timestamp -> Instant) before retrying
}

Prevention

When it happens

Trigger: Calling getTimestamp(pos) on a timestamp_ns field whose value object is not LocalDateTime, Instant or Long, e.g. a java.sql.Timestamp or String.

Common situations: Reading data written by custom or third-party converters that materialize nanosecond timestamps as java.sql.Timestamp; schema evolved from timestamp (micros) to timestamp_ns while values kept old representations.

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/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/5b4e75b593f1c489. Report an issue: GitHub.

Appendix: source

Thrown at flink/v2.3/flink/src/main/java/org/apache/iceberg/flink/data/StructRowData.java:205

  @Override
  public TimestampData getTimestamp(int pos, int precision) {
    if (precision > 6) {
      Object timeVal = struct.get(pos, Object.class);
      if (timeVal instanceof OffsetDateTime) {
        OffsetDateTime odt = (OffsetDateTime) timeVal;
        return TimestampData.fromEpochMillis(
            odt.toInstant().toEpochMilli(), odt.getNano() % 1_000_000);
      } else if (timeVal instanceof LocalDateTime) {
        LocalDateTime ldt = (LocalDateTime) timeVal;
        return TimestampData.fromEpochMillis(
            ldt.toInstant(ZoneOffset.UTC).toEpochMilli(), ldt.getNano() % 1_000_000);
      } else if (timeVal instanceof Long) {
        long timeLong = (Long) timeVal;
        return TimestampData.fromEpochMillis(
            Math.floorDiv(timeLong, 1_000_000L), (int) Math.floorMod(timeLong, 1_000_000L));
      } else {
        throw new IllegalStateException("Unknown type for timestamp_ns: " + timeVal.getClass());
      }
    }
    long timeLong = getLong(pos);
    return TimestampData.fromEpochMillis(
        Math.floorDiv(timeLong, 1000L), (int) Math.floorMod(timeLong, 1000L) * 1000);
  }

  @Override
  public <T> RawValueData<T> getRawValue(int pos) {
    throw new UnsupportedOperationException("Not supported yet.");
  }

  @Override
  public byte[] getBinary(int pos) {
    return isNullAt(pos) ? null : getBinaryInternal(pos);
  }

  private byte[] getBinaryInternal(int pos) {

View on GitHub (pinned to 86d9c8fc54)