unslothai/unsloth · error · SttEngineUnavailableError

The local transcription runtime did not start in time.

Error message

The local transcription runtime did not start in time.

What it means

SttEngineUnavailableError raised in _wait_for_server when the deadline (time.monotonic() + _SERVER_START_TIMEOUT_SECONDS) expires: whisper-server stayed alive for the whole window but never answered two consecutive whisper-identifying HTTP probes on the reserved 127.0.0.1 port. The process is up but not ready — usually a huge model loading into RAM/VRAM or a port bind problem.

Source

Thrown at studio/backend/core/inference/stt_ggml_sidecar.py:1058

            if cancel_event is not None and cancel_event.is_set():
                raise SttLoadCancelledError(
                    "GGUF STT model loading was cancelled so training could start."
                )
            if process.poll() is not None:
                raise SttEngineUnavailableError(
                    "The local transcription runtime exited before becoming "
                    "ready; the model file may be corrupt or unsupported."
                )
            # Require a whisper-server-specific response twice, with the managed
            # child alive around each probe. An arbitrary local process that won
            # the bind race would otherwise be mistaken for the sidecar and
            # receive the user's microphone audio.
            if GgmlSttSidecar._probe_is_whisper_server(process, port) and (
                GgmlSttSidecar._probe_is_whisper_server(process, port)
            ):
                return
            time.sleep(0.2)
        raise SttEngineUnavailableError("The local transcription runtime did not start in time.")

    @staticmethod
    def _probe_is_whisper_server(process: subprocess.Popen, port: int) -> bool:
        """One readiness probe: our child is alive and the responder looks like
        whisper.cpp's server (its index page and errors identify whisper)."""
        if process.poll() is not None:
            return False
        try:
            req = urllib.request.Request(f"http://127.0.0.1:{port}/", method = "GET")
            with urllib.request.urlopen(req, timeout = 2) as response:
                body = response.read(65536)
        except Exception:
            return False
        if process.poll() is not None:
            return False
        return b"whisper" in body.lower()

    # -- transcription ------------------------------------------------------

View on GitHub (pinned to 203007d190)

Solutions

  1. Retry the load once — first load after boot is often slow due to cold page cache.
  2. Use a smaller curated model if the machine is near the RAM/VRAM limit.
  3. Check GPU drivers and free memory; a child alive-but-unresponsive often indicates VRAM exhaustion.
  4. Verify nothing else on the host squats 127.0.0.1 or blocks the child's bind.
Defensive patterns

Strategy: retry

Validate before calling

import shutil
if psutil.virtual_memory().available < model_ram_estimate(model_id):
    pick_smaller_model()

Try / catch

try:
    sidecar.load(model_id)
except SttEngineUnavailableError as exc:
    if "did not start in time" in str(exc):
        if not retry_once():
            pick_smaller_curated_model()

Prevention

When it happens

Trigger: load() spawns the child, the readiness loop polls every 0.2s until the timeout, and _probe_is_whisper_server never returns True twice — process alive, but / on the port never looks like whisper.cpp's server.

Common situations: Very large GGUF on a slow disk or low-RAM machine exceeding the start timeout; child stuck on GPU init (broken driver); another process interferes with the reserved port; heavy swap thrash during model mmap.

Related errors


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