apache/iceberg · error · IllegalArgumentException

Invalid time unit

Error message

Invalid time unit: %s

What it means

TimerResultParser.toTimeUnit converts the 'timeUnit' JSON field of a timer result into java.util.concurrent.TimeUnit using TimeUnit.valueOf on the upper-cased string. If the string is not a valid TimeUnit constant name, IllegalArgumentException('Invalid time unit: ...') is thrown, indicating malformed metrics JSON.

Solutions

  1. Use standard TimeUnit constant names in the JSON: NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS
  2. Fix the producer of the metrics JSON to emit TimeUnit.valueOf-compatible names
  3. Validate/sanitize the timeUnit string before parsing, mapping abbreviations ('ns' -> 'NANOSECONDS') yourself
  4. Catch IllegalArgumentException when parsing untrusted metrics files and skip or remap the offending timer

Example fix

// before
String unit = "ns"; // fails
// after
String unit = switch (raw) {
  case "ns" -> "NANOSECONDS";
  case "ms" -> "MILLISECONDS";
  default -> raw.toUpperCase(Locale.ROOT);
};
Defensive patterns

Strategy: validation

Validate before calling

boolean validTimeUnit(String s) {
  try { TimeUnit.valueOf(s.toUpperCase(Locale.ROOT)); return true; }
  catch (IllegalArgumentException | NullPointerException e) { return false; }
}

Try / catch

try {
  TimerResultParser.fromJson(json);
} catch (IllegalArgumentException e) {
  LOG.warn("Skipping malformed timer: {}", e.getMessage());
}

Prevention

When it happens

Trigger: Parsing a TimerResult JSON (from a metrics report) whose timeUnit field is misspelled, in an unexpected format (e.g. 'nanos', 'ns', 'milli-seconds'), or produced by a different/writer version using non-standard unit names.

Common situations: Hand-edited or third-party-generated metrics JSON; reading metrics files produced by another framework; unit strings like 'NANOSECOND' (singular) or lowercase abbreviations.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/1d967a878e7ccb8f. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/org/apache/iceberg/metrics/TimerResultParser.java:117

    long duration = JsonUtil.getLong(TOTAL_DURATION, timer);
    return TimerResult.of(unit, toDuration(duration, unit), count);
  }

  @VisibleForTesting
  static long fromDuration(Duration duration, TimeUnit unit) {
    return unit.convert(duration.toNanos(), TimeUnit.NANOSECONDS);
  }

  @VisibleForTesting
  static Duration toDuration(long val, TimeUnit unit) {
    return Duration.of(val, toChronoUnit(unit));
  }

  private static TimeUnit toTimeUnit(String timeUnit) {
    try {
      return TimeUnit.valueOf(timeUnit.toUpperCase(Locale.ROOT));
    } catch (IllegalArgumentException e) {
      throw new IllegalArgumentException(String.format("Invalid time unit: %s", timeUnit), e);
    }
  }

  private static ChronoUnit toChronoUnit(TimeUnit unit) {
    switch (unit) {
      case NANOSECONDS:
        return ChronoUnit.NANOS;
      case MICROSECONDS:
        return ChronoUnit.MICROS;
      case MILLISECONDS:
        return ChronoUnit.MILLIS;
      case SECONDS:
        return ChronoUnit.SECONDS;
      case MINUTES:
        return ChronoUnit.MINUTES;
      case HOURS:
        return ChronoUnit.HOURS;
      case DAYS:

View on GitHub (pinned to 86d9c8fc54)