Skip to content

Commit 24f002c

Browse files
authored
Don't surface task cancellation as a transcription failure (#242)
When the pipeline's parent task is cancelled mid-transcription (a new recording is started, the engine is torn down, the user toggles again, or the 120s timeout task group cancels its sibling), the in-flight transcribe throws a raw Swift.CancellationError. The generic catch treated it as a real error and wrote a record reading: Transcription Failed: The operation couldn't be completed. (Swift.CancellationError error 1.) Cancellation is normal control flow, not a failure. Catch CancellationError (and the already-cancelled task case) explicitly: discard the empty pending record, release resources, and return quietly instead of persisting a scary failed entry. Also re-throw cancellation from the inner AI-enhancement catch so it is handled the same way rather than relabelled 'Enhancement failed'. Co-authored-by: thefourCraft <thefourCraft@users.noreply.github.com>
1 parent e76a2b9 commit 24f002c

1 file changed

Lines changed: 24 additions & 0 deletions

File tree

Zerm/Transcription/Engine/TranscriptionPipeline.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ class TranscriptionPipeline {
158158
transcription.aiRequestUserMessage = enhancementService.lastUserMessageSent
159159
finalPastedText = enhancedText
160160
} catch {
161+
// A cancelled enhancement is not a failure — let it propagate to
162+
// the outer cancellation handler instead of relabelling it.
163+
if error is CancellationError { throw error }
161164
let errorDescription = (error as? LocalizedError)?.errorDescription ?? error.localizedDescription
162165
transcription.enhancedText = "Enhancement failed: \(errorDescription)"
163166
let shortReason = String(errorDescription.prefix(80))
@@ -173,7 +176,28 @@ class TranscriptionPipeline {
173176

174177
transcription.transcriptionStatus = TranscriptionStatus.completed.rawValue
175178

179+
} catch is CancellationError {
180+
// The pipeline task was cancelled — e.g. a new recording started, the
181+
// engine was torn down, or the user toggled again mid-transcription.
182+
// This is normal control flow, NOT a failure: a raw CancellationError
183+
// surfaces as the confusing "The operation couldn't be completed.
184+
// (Swift.CancellationError error 1.)". Discard the empty pending record
185+
// and bail out quietly instead of writing a "Transcription Failed" entry.
186+
logger.notice("⏹️ Transcription cancelled — discarding pending record")
187+
modelContext.delete(transcription)
188+
try? modelContext.save()
189+
await onCleanup()
190+
return
176191
} catch {
192+
// A late/transitive cancellation can arrive wrapped or after the task is
193+
// already cancelled; treat that as a cancel too rather than a hard failure.
194+
if Task.isCancelled {
195+
logger.notice("⏹️ Transcription cancelled (task) — discarding pending record")
196+
modelContext.delete(transcription)
197+
try? modelContext.save()
198+
await onCleanup()
199+
return
200+
}
177201
let errorDescription = (error as? LocalizedError)?.errorDescription ?? error.localizedDescription
178202
let recoverySuggestion = (error as? LocalizedError)?.recoverySuggestion ?? ""
179203
let fullErrorText = recoverySuggestion.isEmpty ? errorDescription : "\(errorDescription) \(recoverySuggestion)"

0 commit comments

Comments
 (0)