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
- Retry the transcription — the retry loads/validates the current model again.
- Use a single shared model selection across clients so switches cannot interleave.
- 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
- Use one shared model selection across all clients to eliminate switch races.
- Return 409 so the client knows a plain retry is safe.
- Do not cache the model choice across a long audio preparation step.
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
- A transcription is still running on the current dictation mo
- The diffusion engine changed while this load was starting. R
- The stable-diffusion.cpp server binary was replaced by an in
- The stable-diffusion.cpp binary was replaced by an install f
- Another GGUF dictation model ('{self._model_id}') is still d
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/a79529e3134e18b6.
Report an issue: GitHub.