google/guava · error · UnsupportedOperationException

scheduleWithFixedDelay is not supported.

Error message

scheduleWithFixedDelay is not supported.

What it means

SameThreadScheduledExecutorService is a deliberately minimal synchronous test double that runs submitted tasks on the caller thread. It implements one-shot scheduling but intentionally does not support periodic scheduling; scheduleWithFixedDelay throws UnsupportedOperationException by design.

Source

Thrown at android/guava-testlib/src/com/google/common/util/concurrent/testing/SameThreadScheduledExecutorService.java:186

    }

    @Override
    public int compareTo(Delayed other) {
      Preconditions.checkNotNull(other, "other must not be null!");
      return 0;
    }
  }

  @Override
  public ListenableScheduledFuture<?> scheduleAtFixedRate(
      Runnable command, long initialDelay, long period, TimeUnit unit) {
    throw new UnsupportedOperationException("scheduleAtFixedRate is not supported.");
  }

  @Override
  public ListenableScheduledFuture<?> scheduleWithFixedDelay(
      Runnable command, long initialDelay, long delay, TimeUnit unit) {
    throw new UnsupportedOperationException("scheduleWithFixedDelay is not supported.");
  }
}

View on GitHub (pinned to 94f39958ba)

Solutions

  1. Switch the test to a real ScheduledThreadPoolExecutor (or a more complete fake) for code paths that use scheduleWithFixedDelay.
  2. Refactor the code under test to depend on a Scheduler abstraction so the periodic path can be stubbed without this executor.
  3. Split the test so periodic scheduling is exercised against a real executor while synchronous parts use the fake.
  4. Replace fixed-delay scheduling with chained one-shot schedule(...) calls the fake does support.

Example fix

// before
SameThreadScheduledExecutorService ex = new SameThreadScheduledExecutorService();
ex.scheduleWithFixedDelay(task, 0, 1, SECONDS); // UnsupportedOperationException

// after
ScheduledExecutorService ex = Executors.newScheduledThreadPool(1);
ex.scheduleWithFixedDelay(task, 0, 1, SECONDS);
Defensive patterns

Strategy: validation

Validate before calling

boolean usesFixedDelay = schedulingType == SchedulingType.WITH_FIXED_DELAY;
ScheduledExecutorService ex = usesFixedDelay
    ? Executors.newScheduledThreadPool(1)
    : new SameThreadScheduledExecutorService();

Type guard

boolean supportsFixedDelay(ScheduledExecutorService ex) {
  return !(ex instanceof SameThreadScheduledExecutorService);
}

Try / catch

// UnsupportedOperationException signals wrong test double; switch executors,
// do not swallow it.

Prevention

When it happens

Trigger: Code under test calls executor.scheduleWithFixedDelay(command, initialDelay, delay, unit) on an instance of SameThreadScheduledExecutorService provided by a test.

Common situations: Injecting this fake executor into code that performs periodic scheduling with a fixed delay between completions (e.g. backoff retries, heartbeat loops); tests migrated from a real ScheduledExecutorService without noticing the fake omits fixed-delay scheduling.

Related errors


AI-assisted analysis of google/guava@94f39958ba (2026-08-13). Data as JSON: /api/errors/5c0718c2653658f3. Report an issue: GitHub.