ReactiveX/RxJava · error · TimeoutException
The source did not signal an event for {timeout} {unit} and
Error message
The source did not signal an event for {timeout} {unit} and has been terminated. What it means
Thrown as a TimeoutException by FutureMultiObserver.get(long, TimeUnit) when the backing source does not signal (onNext/onError/onComplete) within the given timeout. The message is built by ExceptionHelper.timeoutMessage and reads 'The source did not signal an event for {timeout} {unit} and has been terminated.' — note 'has been terminated' here means the get() call gave up, not necessarily that the source itself errored. FutureMultiObserver implements Future<T> over a Multi source.
Source
Thrown at src/main/java/io/reactivex/rxjava4/internal/observers/FutureMultiObserver.java:97
await();
}
if (isCancelled()) {
throw new CancellationException();
}
Throwable ex = error;
if (ex != null) {
throw new ExecutionException(ex);
}
return value;
}
@Override
public T get(long timeout, @NonNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
if (getCount() != 0) {
BlockingHelper.verifyNonBlocking();
if (!await(timeout, unit)) {
throw new TimeoutException(timeoutMessage(timeout, unit));
}
}
if (isCancelled()) {
throw new CancellationException();
}
Throwable ex = error;
if (ex != null) {
throw new ExecutionException(ex);
}
return value;
}
@Override
public void onSubscribe(Disposable d) {
DisposableHelper.setOnce(this.upstream, d);
}View on GitHub (pinned to a8ab535614)
Solutions
- Increase the timeout to match realistic worst-case latency.
- Ensure the upstream Multi actually terminates — apply a timeout() operator on the source so it errors/completes deterministically instead of hanging the Future.
- Catch TimeoutException explicitly and handle it (retry, fallback, or report).
- Verify you are calling get(timeout,unit) from a thread permitted to block (BlockingHelper rejects blocking on certain schedulers).
Example fix
// before
Multi<T> m = source; // may never complete
T v = m.toFuture().get(2, TimeUnit.SECONDS); // TimeoutException
// after
Multi<T> m = source.timeout(Duration.ofSeconds(2));
T v;
try {
v = m.toFuture().get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
v = fallback();
} Defensive patterns
Strategy: try-catch
Validate before calling
// choose a timeout that covers realistic latency, then also bound the source: Multi<T> bounded = source.timeout(Duration.ofSeconds(5)); // FutureMultiObserver.get declares TimeoutException, so you must handle it anyway.
Try / catch
try {
T v = multi.toFuture().get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
v = fallback();
} catch (InterruptedException | ExecutionException e) {
Thread.currentThread().interrupt(); // for InterruptedException
throw new RuntimeException(e);
} Prevention
- Always apply a timeout() operator on sources feeding a Future so they terminate deterministically.
- Size get(timeout) to worst-case latency, not average.
- Confirm the calling thread is allowed to block (BlockingHelper may reject it).
When it happens
Trigger: Calling futureMulti.get(5, TimeUnit.SECONDS) where the upstream Multi neither emits, errors, nor completes within 5 seconds. Common with cold sources that never complete (e.g. infinite intervals), sources blocked on I/O, or sources awaiting a signal that never arrives.
Common situations: Blocking on a Multi that wraps a never-completing stream; network/datasource stalls; deadlocks where the producer thread is starved; timeouts set too low for the workload; forgetting that BlockingHelper.verifyNonBlocking() also runs and may throw if called from a non-blocking context.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- The source did not signal an event for {timeout} {unit} and
- remove
- Read-only iterator.
- Read only iterator
- No more elements
AI-assisted analysis of ReactiveX/RxJava@a8ab535614 (2026-08-13).
Data as JSON: /api/errors/3661be282e82fe39.
Report an issue: GitHub.