unslothai/unsloth · warning · SttModelBusyError
A transcription is still running on the current dictation mo
Error message
A transcription is still running on the current dictation model. Try again in a moment.
What it means
SttModelBusyError raised in _load_locked when a model switch is requested while self._active_requests > 0 and the current server process is alive. Switching would tear down a server that is mid-transcription, so the switch is refused instead — and it is refused before _release_locked(), so the user keeps the working server.
Source
Thrown at studio/backend/core/inference/stt_mtmd_sidecar.py:853
# so a training start would otherwise see False and wait out the startup in
# unload() instead of cancelling this load.
cancel_event = (
request_cancel_event if request_cancel_event is not None else threading.Event()
)
self._load_cancel_event = cancel_event
self._load_owner_cancel_event = request_cancel_event
self._loading = True
released = False
try:
if cancel_event.is_set():
raise SttLoadCancelledError("Dictation model loading was cancelled.")
# Before the release: a 409 for a model that is not downloaded
# must not cost the user the server they were already using.
model_path, mmproj_path = self._ensure_model_downloaded(model_id)
# Only when there is a live server to protect: a request against
# a server that already died must not block recovery.
if self._active_requests and self._process_alive():
raise SttModelBusyError(
"A transcription is still running on the current dictation model. "
"Try again in a moment."
)
self._release_locked()
released = True
finally:
# Nothing started, so take the announcement back; past here the startup owns it.
if not released:
self._loading = False
self._load_cancel_event = None
self._load_owner_cancel_event = None
# Re-read last: _release_locked() reaps the old server, which can
# take seconds, and training admission that already passed its own
# check cannot come back to cancel this load. Publishing _loading
# first covers the other order, so between them every training start
# either cancels this load or is seen by it.
training = _training_active()
try:View on GitHub (pinned to 203007d190)
Solutions
- Retry the model switch after the in-flight transcription finishes (usually seconds).
- Serialize model switches behind a queue so only one switch is attempted at a time.
- Keep a single model choice per session to avoid switch storms between clients.
Defensive patterns
Strategy: retry
Try / catch
```python
for attempt in range(3):
try:
sidecar.load(new_model_id)
break
except SttModelBusyError:
time.sleep(1.0) # in-flight transcription on the old model
else:
return "model busy", 409
``` Prevention
- Serialize model switches and transcriptions through one coordinator/queue.
- Settle on a single dictation model per session.
- Return 409 with Retry-After semantics so clients back off politely.
When it happens
Trigger: Client A is transcribing on model X (active request in flight) while client B calls load(model Y) on the same sidecar instance.
Common situations: Two studio windows/tabs dictating with different models; a long recording still uploading while the user changes the voice model in settings; a preload racing a live transcription.
Related errors
- The dictation model changed while this recording was being p
- Another GGUF dictation model ('{self._model_id}') is still d
- Another dictation model ('{self._model_id}') is still downlo
- Another dictation model ('{self._model_id}') is still downlo
- The previous dictation worker did not exit and still holds i
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/598973fb2ab2d7e2.
Report an issue: GitHub.