From 95d4e34c28632e15facfaacd1158ac41c1f28a7a Mon Sep 17 00:00:00 2001 From: niksedk Date: Sat, 23 May 2026 08:02:07 +0200 Subject: [PATCH 1/2] Suppress cancel-error dialog in auto-translate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the user presses Cancel during translation, the HttpClient call throws OperationCanceledException (or TaskCanceledException) which the generic catch in DoTranslate surfaced as a translation-error dialog with a stack trace. Cancel should be silent — the finally block already sets StatusText to "Translation cancelled". Add a guarded catch for user-initiated cancellation; genuine cancellation-shaped errors still fall through to the existing handler. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/ui/Features/Translate/AutoTranslateViewModel.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ui/Features/Translate/AutoTranslateViewModel.cs b/src/ui/Features/Translate/AutoTranslateViewModel.cs index 1dcf51e478..148583eaf4 100644 --- a/src/ui/Features/Translate/AutoTranslateViewModel.cs +++ b/src/ui/Features/Translate/AutoTranslateViewModel.cs @@ -1249,6 +1249,10 @@ private async Task DoTranslate(TranslationPair sourceLanguage, TranslationPair t } } + catch (OperationCanceledException) when (_abort) + { + // User pressed Cancel — let the finally block report it; do not surface as an error. + } catch (Exception ex) { _ = Dispatcher.UIThread.Invoke(async () => From 9ba5e52a84ae75c0f9f1e798b94b3628da4079b7 Mon Sep 17 00:00:00 2001 From: niksedk Date: Sat, 23 May 2026 08:26:21 +0200 Subject: [PATCH 2/2] Race-proof the auto-translate cancel guard Cancel() called _cancellationTokenSource.Cancel() before setting _abort = true, so the worker thread could observe cancellation and throw OperationCanceledException before _abort was set (and even when ordering is right, the non-volatile bool write isn't guaranteed visible across threads). - Set _abort before cancelling the token, so intent is recorded first. - Widen the catch guard to also check the CTS's IsCancellationRequested, which is internally synchronized and race-free. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/ui/Features/Translate/AutoTranslateViewModel.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ui/Features/Translate/AutoTranslateViewModel.cs b/src/ui/Features/Translate/AutoTranslateViewModel.cs index 148583eaf4..2c0c518302 100644 --- a/src/ui/Features/Translate/AutoTranslateViewModel.cs +++ b/src/ui/Features/Translate/AutoTranslateViewModel.cs @@ -627,8 +627,8 @@ private void Ok() private void Cancel() { var wasTranslating = !IsTranslateEnabled; - _cancellationTokenSource.Cancel(); _abort = true; + _cancellationTokenSource.Cancel(); IsProgressEnabled = false; if (IsTranslateEnabled) @@ -1249,9 +1249,11 @@ private async Task DoTranslate(TranslationPair sourceLanguage, TranslationPair t } } - catch (OperationCanceledException) when (_abort) + catch (OperationCanceledException) when (_abort || _cancellationTokenSource.IsCancellationRequested) { // User pressed Cancel — let the finally block report it; do not surface as an error. + // Check both _abort and the token: Cancel() sets _abort then fires the token, but the + // worker thread can observe cancellation before _abort is visible across threads. } catch (Exception ex) {