unslothai/unsloth · warning · SttModelBusyError

The dictation model changed while this recording was being p

Error message

The dictation model changed while this recording was being prepared. Try again.

What it means

SttModelBusyError raised when, under _lock, self._model_id != model_id: another client switched the dictation model between this request's load() returning and the port being read. Transcribing would silently use the wrong model's server, so the request is refused instead.

Source

Thrown at studio/backend/core/inference/stt_mtmd_sidecar.py:1002

        # on CPU exactly as whisper.cpp and Transformers do. Refusing after a
        # preload that succeeded only discarded the user's recording.
        # Reject a missing model before decoding, matching the other sidecars.
        self._ensure_model_downloaded(model_id)
        decoded_audio = _decode_audio_bounded(audio, cancel_event)
        if cancel_event is not None and cancel_event.is_set():
            raise SttTranscriptionCancelledError("Transcription cancelled.")
        wav_bytes = _pcm_to_wav_bytes(decoded_audio)
        audio_seconds = (len(decoded_audio) / _TARGET_SAMPLE_RATE) if len(decoded_audio) else None
        self.load(model_id, request_cancel_event = cancel_event)
        with self._lock:
            port = self._port
            if port is None or not self._process_alive():
                raise SttUnavailableError("The dictation server is not running.")
            # Another client can switch models in the gap between that load
            # returning and this lock, and the port read here would then be its
            # server. Refuse rather than transcribe on the wrong model.
            if self._model_id != model_id:
                raise SttModelBusyError(
                    "The dictation model changed while this recording was being "
                    "prepared. Try again."
                )
            # Long audio can outlast the keep-alive, and _post_transcribe runs
            # outside the lock, so disarm the timer rather than let it kill
            # llama-server mid-request and throw the dictation away.
            self._active_requests += 1
            self._cancel_idle_unload_locked()
        try:
            # Outside the lock: a held lock would block unload, including the
            # one a training run performs, for the whole request timeout.
            text = self._post_transcribe(
                port, model_id, wav_bytes, audio_seconds, cancel_event = cancel_event
            )
            if cancel_event is not None and cancel_event.is_set():
                raise SttTranscriptionCancelledError("Transcription cancelled.")
        except Exception:
            if cancel_event is not None and cancel_event.is_set():

View on GitHub (pinned to 203007d190)

Solutions

  1. Retry the transcription — the retry loads/validates the current model again.
  2. Use a single shared model selection across clients so switches cannot interleave.
  3. Catch SttModelBusyError at the route and return 409 so the client knows to resubmit.
Defensive patterns

Strategy: retry

Try / catch

```python
try:
    return sidecar.transcribe_bytes(audio, model=model_id, cancel_event=ev)
except SttModelBusyError:
    return "model changed, resubmit", 409  # client retries with current model
```

Prevention

When it happens

Trigger: Client B calls load(other_model) and it completes while client A is between its load(model) and its locked port read in transcribe_bytes().

Common situations: Two clients dictating with different model selections; a settings change (model switch) landing during another window's in-flight recording.

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/a79529e3134e18b6. Report an issue: GitHub.