{"record":{"id":"bc024ae7389cb253","repo":"unslothai/unsloth","slug":"no-active-model-bc024a","errorCode":null,"errorMessage":"No active model","messagePattern":"No active model","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"studio/backend/core/inference/orchestrator.py","lineNumber":2113,"sourceCode":"        self,\n        text: str,\n        temperature: float = 0.6,\n        top_p: float = 0.95,\n        top_k: int = 50,\n        min_p: float = 0.0,\n        max_new_tokens: int = 2048,\n        repetition_penalty: float = 1.0,\n        use_adapter: Optional[Union[bool, str]] = None,\n        cancel_event = None,\n    ) -> Tuple[bytes, int]:\n        \"\"\"Generate TTS audio. Returns (wav_bytes, sample_rate).\n\n        Blocking — sends command and waits for the full audio response.\n        \"\"\"\n        if not self._ensure_subprocess_alive():\n            raise RuntimeError(\"Inference subprocess is not running\")\n        if not self.active_model_name:\n            raise RuntimeError(\"No active model\")\n        expected_model = self.active_model_name\n\n        # Serialize under _gen_lock and reserve dispatcher admission before waiting for\n        # compare work to drain. A bare idle wait is racy: a compare request can register\n        # between the wait and this command, leaving TTS queued without safe ownership of\n        # the worker's single shared cancel event.\n        with self._gen_lock:\n            with self._dispatcher_lifecycle_lock:\n                self._exclusive_tts_pending = True\n            try:\n                dispatcher_idle = self._wait_dispatcher_idle(cancel_event = cancel_event)\n                if cancel_event is not None and cancel_event.is_set():\n                    raise AudioGenerationCancelledError(\"Audio generation cancelled\")\n                if not dispatcher_idle:\n                    raise RuntimeError(\n                        \"Cannot start audio generation while compare requests are active\"\n                    )\n","sourceCodeStart":2095,"sourceCodeEnd":2131,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/inference/orchestrator.py#L2095-L2131","documentation":"Guard in generate_audio: the worker may be alive but active_model_name is empty — no model is published as active. This happens after an unload, a failed load, or a teardown that cleared model state (several paths set active_model_name = None).","triggerScenarios":"Calling TTS generation right after /unload, after a load failure, or after a cancel path that cleared active_model_name and models while the worker object still exists.","commonSituations":"Race between UI unloading a model and a queued TTS request; retrying audio after a cancelled load; stale frontend state showing a model as loaded when the backend already dropped it.","solutions":["Load a model and wait for the loaded response before calling generate_audio.","Refresh frontend model state after unload/cancel so audio requests are not sent.","Check orchestrator.active_model_name before issuing audio work."],"exampleFix":"// before\nwav, sr = orchestrator.generate_audio(text)\n// after\nif not orchestrator.active_model_name:\n    raise RuntimeError(\"load a model before requesting audio\")\nwav, sr = orchestrator.generate_audio(text)","handlingStrategy":"validation","validationCode":"if not orchestrator.active_model_name:\n    raise ValueError(\"load a model before requesting audio\")","typeGuard":"def has_active_model(orch) -> bool:\n    return orch.active_model_name is not None","tryCatchPattern":null,"preventionTips":["Refresh model state after unload/cancel events before enabling audio actions.","Subscribe to backend load/unload events instead of caching active-model locally."],"tags":["inference","tts","state","precondition"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}