apache/iceberg · error · IllegalStateException

Unknown type for long field. Type name:

Error message

Unknown type for long field. Type name: 

What it means

StructInternalRow.getLong converts the underlying value of a long/timestamp field to a Java long, accepting Long, OffsetDateTime (timestamptz), and LocalDate (date-as-days). Any other runtime type throws this IllegalStateException with the actual class name.

Source

Thrown at spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/source/StructInternalRow.java:156

      return (int) ((LocalDate) integer).toEpochDay();
    } else {
      throw new IllegalStateException(
          "Unknown type for int field. Type name: " + integer.getClass().getName());
    }
  }

  @Override
  public long getLong(int ordinal) {
    Object longVal = struct.get(ordinal, Object.class);

    if (longVal instanceof Long) {
      return (long) longVal;
    } else if (longVal instanceof OffsetDateTime) {
      return Duration.between(Instant.EPOCH, (OffsetDateTime) longVal).toNanos() / 1000;
    } else if (longVal instanceof LocalDate) {
      return ((LocalDate) longVal).toEpochDay();
    } else {
      throw new IllegalStateException(
          "Unknown type for long field. Type name: " + longVal.getClass().getName());
    }
  }

  @Override
  public float getFloat(int ordinal) {
    return struct.get(ordinal, Float.class);
  }

  @Override
  public double getDouble(int ordinal) {
    return struct.get(ordinal, Double.class);
  }

  @Override
  public Decimal getDecimal(int ordinal, int precision, int scale) {
    return isNullAt(ordinal) ? null : getDecimalInternal(ordinal);
  }

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Ensure the accessor matches the declared Iceberg type (getLong only for long/timestamptz/date semantics)
  2. Reconcile schema drift: refresh the table schema and Spark conversion so field types match the data
  3. Inspect the type name in the message and fix the producer writing that wrong type

Example fix

// before
row.getLong(timeFieldOrdinal); // throws: value is LocalTime
// after
// time fields must be routed to getTime or converted upstream
long nanos = ((LocalTime) value).toNanoOfDay();
Defensive patterns

Strategy: validation

Validate before calling

// Java
Object v = struct.getField(ordinal);
if (!(v instanceof Long) && !(v instanceof OffsetDateTime) && !(v instanceof LocalDate)) {
  throw new IllegalStateException("Expected Long/OffsetDateTime/LocalDate, got " + v.getClass());
}

Type guard

boolean isValidLongFieldValue(Object v) {
  return v instanceof Long || v instanceof OffsetDateTime || v instanceof LocalDate;
}

Try / catch

try {
  long l = row.getLong(ordinal);
} catch (IllegalStateException e) {
  if (e.getMessage().startsWith("Unknown type for long field")) {
    // use the correct accessor for the field's declared type
  }
  throw e;
}

Prevention

When it happens

Trigger: Reading a long/Timestamp/Timestamptz field whose stored value is none of Long, OffsetDateTime, or LocalDate — e.g. LocalTime for a time field read through the wrong accessor or a String/BigDecimal in the row.

Common situations: Schema drift between the Iceberg schema and the Spark read schema, custom StructLike values with unexpected boxed types, or microsecond/nanosecond conversion code invoked on fields of the wrong declared type.

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/89b2d8cabc046842. Report an issue: GitHub.