apache/hadoop · error · MetricsException

Unrecognized flush interval: ${rollInterval}. Must be a numb

Error message

Unrecognized flush interval: ${rollInterval}. Must be a number followed by an optional unit. The unit must be one of: minute, hour, day

What it means

The roll-interval property is matched against ^\s*(\d+)\s*([A-Za-z]*)\s*$ and the digit group is parsed with Integer.parseInt. Because the regex already guarantees the first group is all digits, the NumberFormatException branch fires only when the number exceeds Integer.MAX_VALUE (2147483647). The misleading 'Unrecognized flush interval' message then blames the whole value even though the number was simply too large for a 32-bit int.

Source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/sink/RollingFileSystemSink.java:356

   *
   * @return the roll interval in millis
   */
  @VisibleForTesting
  protected long getRollInterval() {
    String rollInterval =
        properties.getString(ROLL_INTERVAL_KEY, DEFAULT_ROLL_INTERVAL);
    Pattern pattern = Pattern.compile("^\\s*(\\d+)\\s*([A-Za-z]*)\\s*$");
    Matcher match = pattern.matcher(rollInterval);
    long millis;

    if (match.matches()) {
      String flushUnit = match.group(2);
      int rollIntervalInt;

      try {
        rollIntervalInt = Integer.parseInt(match.group(1));
      } catch (NumberFormatException ex) {
        throw new MetricsException("Unrecognized flush interval: "
            + rollInterval + ". Must be a number followed by an optional "
            + "unit. The unit must be one of: minute, hour, day", ex);
      }

      if ("".equals(flushUnit)) {
        millis = TimeUnit.HOURS.toMillis(rollIntervalInt);
      } else {
        switch (flushUnit.toLowerCase()) {
        case "m":
        case "min":
        case "minute":
        case "minutes":
          millis = TimeUnit.MINUTES.toMillis(rollIntervalInt);
          break;
        case "h":
        case "hr":
        case "hour":
        case "hours":

View on GitHub (pinned to 2add963021)

Solutions

  1. Use a small number plus an explicit unit: roll-interval=30days or roll-interval=720h
  2. Remember a bare number means HOURS and must fit in a 32-bit int (max ~245,000 years — never a real constraint)
  3. Never express this property in milliseconds; the minimum unit is minutes

Example fix

# before
*.sink.rolling.roll-interval=2592000000  # 30 days in millis -> parseInt overflow

# after
*.sink.rolling.roll-interval=30days
Defensive patterns

Strategy: validation

Validate before calling

Matcher m = Pattern.compile("^\\s*(\\d+)\\s*([A-Za-z]*)\\s*$").matcher(rollInterval);
if (!m.matches() || Long.parseLong(m.group(1)) > Integer.MAX_VALUE) {
  throw new IllegalArgumentException("roll-interval number exceeds int range: "
      + rollInterval + " — use a small number plus minute/hour/day unit");
}

Try / catch

try {
  sink.init(subsetConf);
} catch (MetricsException e) {
  // 'Unrecognized flush interval' wrapping NumberFormatException => numeric part > Integer.MAX_VALUE
  LOG.error("Invalid roll-interval '{}': number must fit in a 32-bit int", rollInterval, e);
}

Prevention

When it happens

Trigger: roll-interval with a numeric part above 2147483647, e.g. roll-interval=2592000000 (someone computing 30 days in milliseconds) or roll-interval=99999999999hours.

Common situations: Copy-pasting millisecond durations from other tools' configs (where roll intervals are expressed in millis); scripts that generate the interval arithmetically and overflow int range.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/f8f98bc5fa683e05. Report an issue: GitHub.