Summary
TextDecoder.decodeText contains force-unwraps that crash the app during repeated rapid transcription calls (e.g., live transcription preview that re-transcribes every ~200ms).
Crash Stack
EXC_BREAKPOINT / SIGTRAP
_assertionFailure → TextDecoder.decodeText(from:using:sampler:options:callback:)
→ TranscribeTask.run → WhisperKit.transcribe → WhisperKit.transcribe(audioPath:)
Root Cause
Two force-unwraps in TextDecoder.decodeText (TextDecoder.swift):
- Line 747:
decoderInputs.initialPrompt.last! — crashes if initialPrompt is empty
- Line 829:
decoderOutput.logits! — crashes if logits is nil
These are fine for single-shot transcription but become problematic during sustained rapid calls where internal state can degrade.
Reproduction
- Create two WhisperKit instances (main + live)
- Call
transcribe(audioPath:) on the live instance in a tight loop (~5-10 calls/sec) during recording
- After extended use (minutes to hours), the decoder state accumulates corruption and one of the force-unwraps hits nil
Environment
- WhisperKit v0.15.0
- macOS 26.2, Apple Silicon
- Model: openai_whisper-small
- Using separate WhisperKit instances for main and live transcription
Suggested Fix
Replace the force-unwraps with guard statements that throw errors instead of crashing:
// Line 747
guard let firstToken = decoderInputs.initialPrompt.last else {
throw WhisperError.decodingFailed("initialPrompt is empty")
}
var nextToken: Int = firstToken
// Line 829
guard let logits = decoderOutput.logits else {
throw WhisperError.decodingLogitsFailed("Logits output is nil")
}
This would allow callers to handle the error gracefully instead of crashing the entire app.
Related
I noticed #413 and #412 are addressing thread safety — this may be related to the same class of issues.
Summary
TextDecoder.decodeTextcontains force-unwraps that crash the app during repeated rapid transcription calls (e.g., live transcription preview that re-transcribes every ~200ms).Crash Stack
Root Cause
Two force-unwraps in
TextDecoder.decodeText(TextDecoder.swift):decoderInputs.initialPrompt.last!— crashes ifinitialPromptis emptydecoderOutput.logits!— crashes if logits is nilThese are fine for single-shot transcription but become problematic during sustained rapid calls where internal state can degrade.
Reproduction
transcribe(audioPath:)on the live instance in a tight loop (~5-10 calls/sec) during recordingEnvironment
Suggested Fix
Replace the force-unwraps with guard statements that throw errors instead of crashing:
This would allow callers to handle the error gracefully instead of crashing the entire app.
Related
I noticed #413 and #412 are addressing thread safety — this may be related to the same class of issues.