apache/beam · error · IllegalArgumentException

Unexpected date type: {typeName}

Error message

Unexpected date type: {typeName}

What it means

When converting a literal for a DATE-typed field, FilterUtils accepts string literals or SQL DATE literals only. A literal of any other SQL type (e.g., INTEGER or TIMESTAMP) used in a date predicate throws this IllegalArgumentException (note the message says 'date type' even in the TIME branch's sibling case).

Source

Thrown at sdks/java/io/iceberg/src/main/java/org/apache/beam/sdk/io/iceberg/FilterUtils.java:362

      case LONG:
        return literal.getValueAs(Long.class);
      case FLOAT:
        return literal.getValueAs(Float.class);
      case DOUBLE:
        return literal.getValueAs(Double.class);
      case DECIMAL:
        return literal.getValueAs(BigDecimal.class);
      case STRING:
        return literal.getValueAs(String.class);
      case DATE:
        LocalDate date;
        if (SqlTypeName.STRING_TYPES.contains(typeName) || SqlTypeName.UNKNOWN.equals(typeName)) {
          date = LocalDate.parse(literal.getValueAs(String.class));
        } else if (SqlTypeName.DATE.equals(typeName)) {
          DateString dateValue = literal.getValueAs(DateString.class);
          date = LocalDate.parse(dateValue.toString());
        } else {
          throw new IllegalArgumentException("Unexpected date type: " + literal.getTypeName());
        }
        return DateTimeUtil.daysFromDate(date);
      case TIME:
        LocalTime time;
        if (SqlTypeName.STRING_TYPES.contains(typeName) || SqlTypeName.UNKNOWN.equals(typeName)) {
          time = LocalTime.parse(literal.getValueAs(String.class));
        } else if (SqlTypeName.TIME.equals(typeName)) {
          TimeString timeString = literal.getValueAs(TimeString.class);
          time = LocalTime.parse(timeString.toString());
        } else {
          throw new IllegalArgumentException("Unexpected date type: " + literal.getTypeName());
        }
        return DateTimeUtil.microsFromTime(time);
      case TIMESTAMP:
        LocalDateTime datetime;
        if (SqlTypeName.STRING_TYPES.contains(typeName) || SqlTypeName.UNKNOWN.equals(typeName)) {
          String value = literal.getValueAs(String.class);
          datetime = getLocalDateTime(value);

View on GitHub (pinned to 12126d8942)

Solutions

  1. Write the date as a quoted string or SQL DATE literal: "date_col = '2024-01-01'" or "date_col = DATE '2024-01-01'".
  2. Ensure the string is ISO-8601 (yyyy-MM-dd) so LocalDate.parse succeeds.
  3. Check the literal's inferred type by printing the parsed SqlNode before conversion.

Example fix

// before
Expression e = FilterUtils.convert("d = 20240101", schema);
// after
Expression e = FilterUtils.convert("d = DATE '2024-01-01'", schema);
Defensive patterns

Strategy: validation

Validate before calling

checkArgument(java.time.LocalDate.parse(dateStr) != null, "Date literal must be ISO yyyy-MM-dd string");
// build filter as: "d = DATE '" + dateStr + "'"

Try / catch

try { LocalDate.parse(userDate); } catch (DateTimeParseException e) { throw new IllegalArgumentException("Use ISO yyyy-MM-dd", e); }

Prevention

When it happens

Trigger: Calling FilterUtils.convert with a predicate like "date_col = 20240101" (integer literal) or otherwise providing a literal whose SqlTypeName is neither a string type, UNKNOWN, nor DATE against a DATE field.

Common situations: Writing dates as bare numbers instead of quoted strings; passing epoch ints to date comparisons; dialect quirks where the literal parses as a different type than expected.

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