apache/beam · error · IllegalArgumentException

Encountered unrecognized Timezone

Error message

Encountered unrecognized Timezone: ${type.getTimezone()}

What it means

When converting Arrow timestamp columns, the library parses the timezone string via Joda's DateTimeZone.forID; an unrecognized/invalid timezone ID makes it throw IllegalArgumentException. Arrow timestamps carry a timezone string that must be a valid IANA identifier for the converter to build a correct instant.

Solutions

  1. Normalize the Arrow timestamp timezone to a valid IANA ID (e.g. 'America/New_York', 'UTC') in the producer
  2. Use Arrow timestamp without timezone (null) if wall-clock semantics are intended and the schema path supports it
  3. Pre-parse/validate the timezone with DateTimeZone.forID before conversion and repair invalid IDs
  4. Convert timestamps to epoch longs upstream and skip the tz-aware branch

Example fix

// before
new ArrowType.Timestamp(ArrowType.TimeUnit.MILLISECOND, "UTC+2") // throws
// after
new ArrowType.Timestamp(ArrowType.TimeUnit.MILLISECOND, "UTC")
Defensive patterns

Strategy: validation

Validate before calling

import org.joda.time.DateTimeZone;
String tzId = timestampField.getType().getTimezone();
try {
  DateTimeZone.forID(tzId);
} catch (Exception e) {
  throw new IllegalArgumentException("Arrow timestamp timezone not a valid IANA ID: " + tzId);
}

Type guard

boolean isValidIANATimezone(String id) {
  try { org.joda.time.DateTimeZone.forID(id); return true; } catch (Exception e) { return false; }
}

Try / catch

try {
  rows = ArrowConversion.rowsFromRecordBatch(schema, batches);
} catch (IllegalArgumentException e) {
  if (e.getMessage().startsWith("Encountered unrecognized Timezone")) {
    throw new ConfigException("Fix the Arrow timestamp timezone ID", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Arrow schema declares a Timestamp field whose getTimezone() is null for a tz-aware conversion path, a non-IANA string (e.g. 'UTC+2', 'GMT-05:00', or a typo like 'Amercia/New_York'), so DateTimeZone.forID fails.

Common situations: Data written by tools that store offset-style or custom timezone labels; null timezone on naive timestamps where the converter expects an ID; cross-version schema drift where the writer emitted an abbreviation like 'EST'.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/9e4280f08d387406. Report an issue: GitHub.

Appendix: source

Thrown at sdks/java/extensions/arrow/src/main/java/org/apache/beam/sdk/extensions/arrow/ArrowConversion.java:522

      public Optional<Function<Object, Object>> visit(ArrowType.Date type) {
        throw new IllegalArgumentException("Type \'" + type.toString() + "\' not supported.");
      }

      @Override
      public Optional<Function<Object, Object>> visit(ArrowType.Time type) {
        throw new IllegalArgumentException("Type \'" + type.toString() + "\' not supported.");
      }

      @Override
      public Optional<Function<Object, Object>> visit(ArrowType.Timestamp type) {
        // Arrow timestamp semantics:
        // - With timezone: epoch is always UTC, timezone is display metadata
        // - Without timezone: epoch is in an unknown timezone ("naive" wall-clock time)
        DateTimeZone tz;
        try {
          tz = DateTimeZone.forID(type.getTimezone());
        } catch (Exception e) {
          throw new IllegalArgumentException(
              "Encountered unrecognized Timezone: " + type.getTimezone());
        }

        return Optional.of(
            epoch -> {
              switch (type.getUnit()) {
                case MILLISECOND:
                  return new DateTime((long) epoch, tz);
                case MICROSECOND:
                  return new DateTime(Math.floorDiv((long) epoch, 1000L), tz);
                case NANOSECOND:
                  long seconds = Math.floorDiv((long) epoch, 1_000_000_000L);
                  long nanoAdjustment = Math.floorMod((long) epoch, 1_000_000_000L);
                  return java.time.Instant.ofEpochSecond(seconds, nanoAdjustment);
                default:
                  throw new AssertionError("Encountered unrecognized TimeUnit: " + type.getUnit());
              }
            });

View on GitHub (pinned to 12126d8942)