Skip to content

TextDecoder.decodeText force-unwraps cause crashes during repeated live transcription #414

@yw5aj

Description

@yw5aj

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):

  1. Line 747: decoderInputs.initialPrompt.last! — crashes if initialPrompt is empty
  2. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions