google/guava · error · RuntimeException
Unexpected interrupt while waiting for future
Error message
Unexpected interrupt while waiting for future
What it means
GcFinalization.await(Future) loops, calling System.gc() and future.get(1, SECONDS) until the future completes or the deadline expires. An InterruptedException is treated as unexpected and rethrown wrapped in a RuntimeException, because the helper assumes the awaiting thread should not be cancelled mid-wait.
Source
Thrown at android/guava-testlib/src/com/google/common/testing/GcFinalization.java:167
public static void awaitDone(Future<?> future) {
if (future.isDone()) {
return;
}
long timeoutSeconds = timeoutSeconds();
long deadline = System.nanoTime() + SECONDS.toNanos(timeoutSeconds);
do {
runFinalization();
if (future.isDone()) {
return;
}
System.gc();
try {
future.get(1L, SECONDS);
return;
} catch (CancellationException | ExecutionException ok) {
return;
} catch (InterruptedException ie) {
throw new RuntimeException("Unexpected interrupt while waiting for future", ie);
} catch (TimeoutException tryHarder) {
/* OK */
}
} while (System.nanoTime() - deadline < 0);
throw formatRuntimeException("Future not done within %d second timeout", timeoutSeconds);
}
/**
* Waits until the given predicate returns true, invoking the garbage collector as necessary to
* try to ensure that this will happen.
*
* @throws RuntimeException if timed out or interrupted while waiting
*/
public static void awaitDone(FinalizationPredicate predicate) {
if (predicate.isDone()) {
return;
}
long timeoutSeconds = timeoutSeconds();View on GitHub (pinned to 94f39958ba)
Solutions
- Ensure the thread running the GC finalization await is not interrupted — widen test timeouts or move the call off interruptible threads.
- Make the future complete promptly so the 1-second get() returns before any interrupt lands.
- If interruption is legitimate for your environment, do not use GcFinalization.await(future); poll the future yourself and handle InterruptedException by restoring interrupt status.
- Clear stray interrupt status (Thread.interrupted()) before calling await if prior code may have set it.
Example fix
// before Thread.interrupted(); // stray status from earlier test GcFinalization.await(future); // -> RuntimeException: Unexpected interrupt... // after Thread.interrupted(); // clear stray status GcFinalization.await(future);
Defensive patterns
Strategy: try-catch
Validate before calling
// Clear stray interrupt status and widen timeouts before awaiting. Thread.interrupted(); // clear any leaked status assert !Thread.currentThread().isInterrupted(); GcFinalization.await(future);
Try / catch
// The helper wraps InterruptedException in RuntimeException; catch only to
// surface harness problems, not to swallow them.
try {
GcFinalization.await(future);
} catch (RuntimeException e) {
if (!(e.getCause() instanceof InterruptedException)) throw e;
Thread.currentThread().interrupt(); // restore and fail loudly
throw e;
} Prevention
- Do not run GC finalization awaits on threads that may be interrupted (test timeout threads).
- Set test timeouts comfortably above the GcFinalization deadline.
- Clear stray interrupt status before calling await.
- Make the future complete quickly so the 1s get() returns before interrupts land.
When it happens
Trigger: Calling GcFinalization.awaitFullGc()/await(future) while the running thread is concurrently interrupted (Thread.interrupt()), e.g. by a test timeout, a shutdown hook, or framework-level cancellation.
Common situations: JUnit/other test timeouts interrupting the test thread; shared executors being shut down during GC-sensitive tests; harnesses that set interrupt status between test cases.
Related errors
- Unexpected interrupt while waiting for latch
- scheduleAtFixedRate is not supported.
- scheduleWithFixedDelay is not supported.
- %s returns null and cannot be used to test instance methods.
- at index %s
AI-assisted analysis of google/guava@94f39958ba (2026-08-13).
Data as JSON: /api/errors/b88e9a437cea99f3.
Report an issue: GitHub.