Silent failure when ProgressIndicator cancellation is caught and not rethrown
0 reputation · 21 Oct 2021, 02:03 UTC
0 reputation · 21 Oct 2021, 02:03 UTC
The IntelliJ Platform treats a task as completed successfully when a plugin or custom implementation catches ProcessCanceledException and does not rethrow it. This suppresses the cancellation UI, leaves no trace in the event log, and can leave intermediate caches or resources in an inconsistent state.
Developers often need to catch the exception to perform cleanup or finalization, but must ensure that the cancellation signal is still propagated to the platform so that progress indicators update correctly and dependent tasks observe the cancelled state.
What patterns allow safe cleanup while preserving the cancellation contract? How can plugin authors verify that swallowed exceptions do not hide cancellation from the UI or logging system? Are there platform‑provided helpers that automatically rethrow after a cleanup block?
35275 reputation · 21 Oct 2021, 11:55 UTC
Catch ProcessCanceledException, perform cleanup in a finally block (or after the catch), then rethrow the exception. This is the only pattern that guarantees the platform updates the UI, logs the cancellation, and notifies dependent tasks. Swallowing the exception—even in a generic catch (Exception e)—causes silent failure.
try {
// cancellable work
ProgressManager.checkCanceled(); // throws if cancelled
} finally {
cleanup(); // runs on both success and cancellation
ProgressManager.checkCanceled(); // rethrows if cancellation occurred
}The second checkCanceled() ensures the exception propagates after cleanup finishes.
try {
doWork();
} catch (ProcessCanceledException e) {
cleanup();
throw e; // must rethrow
}Use this when cleanup logic differs between success and cancellation paths.
static void runWithCleanup(Runnable work, Runnable cleanup) {
try {
work.run();
} finally {
cleanup.run();
ProgressManager.checkCanceled();
}
}Call as runWithCleanup(this::doWork, this::cleanup);.
Task.Backgroundable / Task.Modal — override run(@NotNull ProgressIndicator) and onCancel(). The framework calls onCancel() after the task thread is interrupted and before the exception propagates, so you get cleanup without manual rethrow.BackgroundableTaskQueue — enqueue Runnables; the queue handles cancellation and invokes your done() callback on both completion and cancellation.ProgressIndicator.runWithProgressSynchronously() — for modal tasks; it rethrows ProcessCanceledException automatically after the block exits.ProgressManager.getInstance().getProgressIndicator().isCanceled() == true when cancellation was requested.Exception or Throwable and not rethrowing ProcessCanceledException.Thread.interrupted() or the indicator, which delays UI updates.Are you implementing a Task.Backgroundable subclass, a plain Runnable passed to ProgressManager.getInstance().run(), or a custom ProgressIndicator consumer? The exact API changes which helper (onCancel() vs. manual rethrow) is most natural.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.