Netflix/Hystrix · error · IllegalStateException
Hystrix does not support delayed scheduling
Error message
Hystrix does not support delayed scheduling
What it means
ThreadPoolScheduler - the RxJava Scheduler Hystrix uses for thread-isolated commands - only supports immediate scheduling onto the Hystrix thread pool. Its schedule(action, delayTime, unit) overload deliberately throws IllegalStateException because delayed tasks have no defined thread-pool semantics in Hystrix.
Source
Thrown at hystrix-core/src/main/java/com/netflix/hystrix/strategy/concurrency/HystrixContextScheduler.java:180
return Subscriptions.unsubscribed();
}
// This is internal RxJava API but it is too useful.
ScheduledAction sa = new ScheduledAction(action);
subscription.add(sa);
sa.addParent(subscription);
ThreadPoolExecutor executor = (ThreadPoolExecutor) threadPool.getExecutor();
FutureTask<?> f = (FutureTask<?>) executor.submit(sa);
sa.add(new FutureCompleterWithConfigurableInterrupt(f, shouldInterruptThread, executor));
return sa;
}
@Override
public Subscription schedule(Action0 action, long delayTime, TimeUnit unit) {
throw new IllegalStateException("Hystrix does not support delayed scheduling");
}
}
/**
* Very similar to rx.internal.schedulers.ScheduledAction.FutureCompleter, but with configurable interrupt behavior
*/
private static class FutureCompleterWithConfigurableInterrupt implements Subscription {
private final FutureTask<?> f;
private final Func0<Boolean> shouldInterruptThread;
private final ThreadPoolExecutor executor;
private FutureCompleterWithConfigurableInterrupt(FutureTask<?> f, Func0<Boolean> shouldInterruptThread, ThreadPoolExecutor executor) {
this.f = f;
this.shouldInterruptThread = shouldInterruptThread;
this.executor = executor;
}
@OverrideView on GitHub (pinned to 5ce3bc58c3)
Solutions
- Apply delayed operators on a standard Rx scheduler (Schedulers.computation()/io()) instead of the Hystrix thread-pool scheduler.
- Reorder the chain: schedule only the command execution itself on Hystrix; do retry/delay/backpressure orchestration downstream on another scheduler.
- If you need delayed retries, use Hystrix's own retry mechanisms or an outer observable with retryWhen on a default scheduler.
Example fix
// before
command.toObservable()
.delay(1, TimeUnit.SECONDS) // forces delayed schedule
.subscribeOn(hystrixScheduler) // -> IllegalStateException
// after
command.toObservable()
.delay(1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.computation()); Defensive patterns
Strategy: validation
Try / catch
try {
observable.delay(1, TimeUnit.SECONDS).subscribeOn(hystrixScheduler);
} catch (IllegalStateException e) {
if ("Hystrix does not support delayed scheduling".equals(e.getMessage())) {
// restructure: use Schedulers.computation() for delayed operators
}
} Prevention
- Never schedule delayed Rx operators on Hystrix thread-pool schedulers.
- Reserve the Hystrix scheduler for the command execution itself.
When it happens
Trigger: Using RxJava operators that introduce delays on a Hystrix-scheduled observable, e.g. observable.delay(...), timer(...), or interval(...) while subscribed on a HystrixContextScheduler/ThreadPoolScheduler.
Common situations: Chaining .delay() or .timer() onto a HystrixCommand's toObservable() and then calling subscribeOn with the Hystrix scheduler; custom Rx pipelines built on HystrixPlugins concurrency strategy schedulers.
Related errors
- unsupported rx type: {}
- fallback cannot return Observable if command isn't observabl
- fallback cannot return 'void' if command return type is " +
- Response has already terminated so response can not be set :
- Failed executing wrapped Action0
AI-assisted analysis of Netflix/Hystrix@5ce3bc58c3 (2026-08-14).
Data as JSON: /api/errors/b5d79b93b98a4696.
Report an issue: GitHub.