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 FutureObserver.get(long, TimeUnit) when the backing source does not signal within the given timeout. The message is produced by ExceptionHelper.timeoutMessage: 'The source did not signal an event for {timeout} {unit} and has been terminated.' FutureObserver implements Future<T> over an Observable/Streamer-style single source; 'has been terminated' refers to the get() call giving up after await() returns false, not necessarily a source-side failure.
Source
Thrown at src/main/java/io/reactivex/rxjava4/internal/observers/FutureObserver.java:98
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
- Raise the timeout to cover realistic worst-case latency.
- Apply a timeout() operator on the source so it terminates deterministically instead of leaving the Future hanging.
- Catch TimeoutException and supply a fallback or trigger a retry.
- Confirm the calling thread is allowed to block (BlockingHelper may reject it).
Example fix
// before
T v = observable.toFuture().get(1, TimeUnit.SECONDS); // TimeoutException
// after
T v;
try {
v = observable.timeout(Duration.ofSeconds(1))
.toFuture().get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
v = fallback();
} Defensive patterns
Strategy: try-catch
Validate before calling
// bound the source and choose a realistic timeout: Observable<T> bounded = source.timeout(Duration.ofSeconds(5)); // get(long, TimeUnit) declares TimeoutException — handle it.
Try / catch
try {
T v = observable.toFuture().get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
v = fallback();
} catch (InterruptedException | ExecutionException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
} Prevention
- Apply timeout() on the source so the Future cannot hang indefinitely.
- Match the get(timeout) to real worst-case latency.
- Verify the calling thread may block (BlockingHelper check).
When it happens
Trigger: Calling futureObserver.get(3, TimeUnit.SECONDS) where the upstream emits nothing and does not complete/error within 3 seconds. Typical with sources blocked on a condition, hot sources that have not produced yet, or cold sources stalled on I/O.
Common situations: Blocking on a source that legitimately never completes; undersized timeouts relative to real latency; producer-thread starvation/deadlock; calling from a context where BlockingHelper.verifyNonBlocking() disallows blocking.
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/ea176ed0ce735334.
Report an issue: GitHub.