{"record":{"id":"b88e9a437cea99f3","repo":"google/guava","slug":"unexpected-interrupt-while-waiting-for-future","errorCode":null,"errorMessage":"Unexpected interrupt while waiting for future","messagePattern":"Unexpected interrupt while waiting for future","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"android/guava-testlib/src/com/google/common/testing/GcFinalization.java","lineNumber":167,"sourceCode":"  public static void awaitDone(Future<?> future) {\n    if (future.isDone()) {\n      return;\n    }\n    long timeoutSeconds = timeoutSeconds();\n    long deadline = System.nanoTime() + SECONDS.toNanos(timeoutSeconds);\n    do {\n      runFinalization();\n      if (future.isDone()) {\n        return;\n      }\n      System.gc();\n      try {\n        future.get(1L, SECONDS);\n        return;\n      } catch (CancellationException | ExecutionException ok) {\n        return;\n      } catch (InterruptedException ie) {\n        throw new RuntimeException(\"Unexpected interrupt while waiting for future\", ie);\n      } catch (TimeoutException tryHarder) {\n        /* OK */\n      }\n    } while (System.nanoTime() - deadline < 0);\n    throw formatRuntimeException(\"Future not done within %d second timeout\", timeoutSeconds);\n  }\n\n  /**\n   * Waits until the given predicate returns true, invoking the garbage collector as necessary to\n   * try to ensure that this will happen.\n   *\n   * @throws RuntimeException if timed out or interrupted while waiting\n   */\n  public static void awaitDone(FinalizationPredicate predicate) {\n    if (predicate.isDone()) {\n      return;\n    }\n    long timeoutSeconds = timeoutSeconds();","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/google/guava/blob/94f39958baf7ad51ddf9c70e406ed6b188194daa/android/guava-testlib/src/com/google/common/testing/GcFinalization.java#L149-L185","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nThread.interrupted(); // stray status from earlier test\nGcFinalization.await(future); // -> RuntimeException: Unexpected interrupt...\n\n// after\nThread.interrupted(); // clear stray status\nGcFinalization.await(future);","handlingStrategy":"try-catch","validationCode":"// Clear stray interrupt status and widen timeouts before awaiting.\nThread.interrupted(); // clear any leaked status\nassert !Thread.currentThread().isInterrupted();\nGcFinalization.await(future);","typeGuard":null,"tryCatchPattern":"// The helper wraps InterruptedException in RuntimeException; catch only to\n// surface harness problems, not to swallow them.\ntry {\n  GcFinalization.await(future);\n} catch (RuntimeException e) {\n  if (!(e.getCause() instanceof InterruptedException)) throw e;\n  Thread.currentThread().interrupt(); // restore and fail loudly\n  throw e;\n}","preventionTips":["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."],"tags":["guava","testing","concurrency","gc","interrupt","finalization"],"backgroundTag":null,"analyzedSha":"94f39958baf7ad51ddf9c70e406ed6b188194daa","analyzedAt":"2026-08-13T22:50:30.265Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}