{"record":{"id":"6061a32bbf9abda3","repo":"apache/iceberg","slug":"interrupted-while-running-parallel-task","errorCode":null,"errorMessage":"Interrupted while running parallel task","messagePattern":"Interrupted while running parallel task","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/util/ParallelIterable.java","lineNumber":167,"sourceCode":"      boolean hasRunningTask = false;\n\n      for (int i = 0; i < taskFutures.length; i += 1) {\n        if (taskFutures[i] == null || taskFutures[i].isDone()) {\n          if (taskFutures[i] != null) {\n            // check for task failure and re-throw any exception. Enqueue continuation if any.\n            try {\n              Optional<Task<T>> continuation = taskFutures[i].get();\n              continuation.ifPresent(yieldedTasks::addLast);\n              taskFutures[i] = null;\n            } catch (ExecutionException e) {\n              if (e.getCause() instanceof RuntimeException) {\n                // rethrow a runtime exception\n                throw (RuntimeException) e.getCause();\n              } else {\n                throw new RuntimeException(\"Failed while running parallel task\", e.getCause());\n              }\n            } catch (InterruptedException e) {\n              throw new RuntimeException(\"Interrupted while running parallel task\", e);\n            }\n          }\n\n          // submit a new task if there is space in the queue\n          if (queue.size() < maxQueueSize) {\n            taskFutures[i] = submitNextTask();\n          }\n        }\n\n        if (taskFutures[i] != null) {\n          hasRunningTask = true;\n        }\n      }\n\n      return !closed.get() && (tasks.hasNext() || hasRunningTask);\n    }\n\n    private CompletableFuture<Optional<Task<T>>> submitNextTask() {","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/util/ParallelIterable.java#L149-L185","documentation":"If the current thread is interrupted while waiting for parallel task futures to complete, ParallelIterable throws a RuntimeException with this message, preserving the InterruptedException as the cause. Interruption usually means the surrounding job is being cancelled or shut down.","triggerScenarios":"Cancelling a Spark job or shutting down the executor service while hasNext()/checkTasks() is blocked on Future.get of a ParallelIterable task.","commonSituations":"Job cancellation, query timeouts killing tasks, executor shutdown during parallel scan planning.","solutions":["Inspect e.getCause() (InterruptedException) and restore the interrupt flag if you catch it","Avoid long-lived ParallelIterable usage inside code that swallows interrupts","Shut down executors gracefully instead of forcing cancellation"],"exampleFix":"// before\niterable.forEach(x -> process(x)); // interrupted mid-iteration\n// after\ntry {\n  iterable.forEach(x -> process(x));\n} catch (RuntimeException e) {\n  if (e.getCause() instanceof InterruptedException) Thread.currentThread().interrupt();\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"if (Thread.currentThread().isInterrupted()) { throw new IllegalStateException(\"already interrupted; skip parallel iteration\"); }","typeGuard":null,"tryCatchPattern":"catch (RuntimeException e) { if (e.getCause() instanceof InterruptedException) { Thread.currentThread().interrupt(); } throw e; }","preventionTips":["Restore the interrupt flag after catching","Avoid cancelling executors while iterables are in use","Use cancellation-aware iterators in long jobs"],"tags":["parallel","interrupt","cancellation"],"backgroundTag":"request-timeout","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}