grpc/grpc-java · error · IllegalArgumentException

Refresh interval must be greater than 0

Error message

Refresh interval must be greater than 0

What it means

FileWatcherAuthorizationServerInterceptor.scheduleRefreshes() schedules a file re-read with scheduleWithFixedDelay, which requires a positive period. A period <= 0 can never fire a sensible refresh loop, so the method throws IllegalArgumentException('Refresh interval must be greater than 0') before scheduling.

Source

Thrown at authz/src/main/java/io/grpc/authz/FileWatcherAuthorizationServerInterceptor.java:88

    internalAuthzServerInterceptor = AuthorizationServerInterceptor.create(policyContents);
  }

  /** 
   * Policy is reloaded periodically as per the provided refresh interval. Unlike the
   * constructor, exception thrown during reload will be caught and logged and the
   * previous AuthorizationServerInterceptor will be used to make authorization
   * decisions.
   * 
   * @param period the period between successive file load executions.
   * @param unit the time unit for period parameter
   * @param executor the execute service we use to read and update authorization policy
   * @return an object that caller should close when the file refreshes are not needed
   */
  public Closeable scheduleRefreshes(
      long period, TimeUnit unit, ScheduledExecutorService executor) throws IOException {
    checkNotNull(executor, "scheduledExecutorService");
    if (period <= 0) {
      throw new IllegalArgumentException("Refresh interval must be greater than 0");
    }
    final ScheduledFuture<?> future = 
        executor.scheduleWithFixedDelay(new Runnable() {
          @Override
          public void run() {
            try {
              updateInternalInterceptor();
            } catch (Exception e) {
              logger.log(Level.WARNING, "Authorization Policy file reload failed", e);
            }
          }
        }, period, period, unit);
    return new Closeable() {
      @Override public void close() {
        future.cancel(false);
      }
    };
  }

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Pass a positive period, e.g. scheduleRefreshes(5, TimeUnit.SECONDS, executor)
  2. Guard the call: only invoke scheduleRefreshes when the configured interval > 0; skip/disable polling otherwise
  3. Fix config parsing so a missing/zero interval maps to a sane default (e.g. 10s) rather than 0

Example fix

// before
watcher.scheduleRefreshes(refreshIntervalSeconds, TimeUnit.SECONDS, executor);
// after
if (refreshIntervalSeconds > 0) {
  watcher.scheduleRefreshes(refreshIntervalSeconds, TimeUnit.SECONDS, executor);
}
Defensive patterns

Strategy: validation

Validate before calling

if (periodMillis <= 0) {
  periodMillis = TimeUnit.SECONDS.toMillis(10); // or skip scheduling
}
watcher.scheduleRefreshes(periodMillis, TimeUnit.MILLISECONDS, executor);

Type guard

static boolean isValidRefreshInterval(long period) { return period > 0; }

Try / catch

try {
  closeable = watcher.scheduleRefreshes(period, unit, executor);
} catch (IllegalArgumentException e) {
  log.error("Invalid refresh interval: " + e.getMessage());
  closeable = null; // run without file watching
}

Prevention

When it happens

Trigger: Calling scheduleRefreshes(period, unit, executor) with period <= 0 — e.g. scheduleRefreshes(0, SECONDS, executor) or a negative value from misparsed config, or 0 as a 'poll immediately' attempt.

Common situations: Config value '0' meaning 'disable polling' being passed through instead of skipping the call; unit/time arithmetic bug producing 0 milliseconds; parsing an empty config string to 0.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/01a6f73dc01bad18. Report an issue: GitHub.