{"record":{"id":"981460d46c7104ea","repo":"jamiepine/voicebox","slug":"unknown-model-model-name","errorCode":null,"errorMessage":"Unknown model: {model_name}","messagePattern":"Unknown model: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"backend/routes/models.py","lineNumber":82,"sourceCode":"async def unload_model():\n    \"\"\"Unload the default Qwen TTS model to free memory.\"\"\"\n    from ..services import tts\n\n    try:\n        tts.unload_tts_model()\n        return {\"message\": \"Model unloaded successfully\"}\n    except Exception as e:\n        raise HTTPException(status_code=500, detail=str(e))\n\n\n@router.post(\"/models/{model_name}/unload\")\nasync def unload_model_by_name(model_name: str):\n    \"\"\"Unload a specific model from memory without deleting it from disk.\"\"\"\n    from ..backends import get_model_config, unload_model_by_config\n\n    config = get_model_config(model_name)\n    if not config:\n        raise HTTPException(status_code=400, detail=f\"Unknown model: {model_name}\")\n\n    try:\n        was_loaded = unload_model_by_config(config)\n        if not was_loaded:\n            return {\"message\": f\"Model {model_name} is not loaded\"}\n        return {\"message\": f\"Model {model_name} unloaded successfully\"}\n    except Exception as e:\n        raise HTTPException(status_code=500, detail=str(e)) from e\n\n\n@router.get(\"/models/progress/{model_name}\")\nasync def get_model_progress(model_name: str):\n    \"\"\"Get model download progress via Server-Sent Events.\"\"\"\n    progress_manager = get_progress_manager()\n\n    async def event_generator():\n        async for event in progress_manager.subscribe(model_name):\n            yield event","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/routes/models.py#L64-L100","documentation":"400 from POST /models/{model_name}/unload. get_model_config(model_name) walks the full registry (Qwen TTS + custom voice + non-Qwen TTS + Whisper + Qwen LLM) and returns None when no config.model_name matches. The route then raises HTTPException(400, f'Unknown model: {model_name}'). model_name comes from the path, so typos and case mismatches are the usual cause.","triggerScenarios":"POST /models/qwen3/unload (no such model_name); /models/Qwen3-1.7B/unload (wrong case — registry ids are lowercase like 'qwen3-1.7b'); /models/kokoro/unload when kokoro is registered under a different id; trailing slash or whitespace in the path segment.","commonSituations":"User typed a display name ('Qwen3 1.7B') instead of the id; client built the URL from a display_name field; registry was extended but client uses an outdated id; confusion between TTS model_name and LLM model_name.","solutions":["Use the exact lowercase registry id, e.g. qwen3-1.7b, qwen3-0.6b, qwen3-4b, or the Whisper/TTS ids.","GET /models/status to list valid model_name values; copy the id verbatim into the path.","Trim whitespace and avoid URL-encoding the hyphen.","If maintaining the client, derive the id from the same registry source the server uses, not from display_name."],"exampleFix":"# before\ncurl -X POST http://localhost:8000/models/Qwen3-1.7B/unload\n# after\ncurl -X POST http://localhost:8000/models/qwen3-1.7b/unload","handlingStrategy":"validation","validationCode":"async function validModelName(name: string) {\n  const status = await (await fetch('/models/status')).json();\n  return status.models.some(m => m.model_name === name);\n}\nif (!(await validModelName(modelName))) {\n  throw new Error(`Unknown model: ${modelName}. Check /models/status for valid ids.`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await fetch(`/models/${encodeURIComponent(modelName)}/unload`, {method:'POST'});\n} catch (e) {\n  if (e.response?.status === 400 && /Unknown model/.test(e.response.detail)) {\n    // refresh model list, fix the id, retry\n  } else throw e;\n}","preventionTips":["Always copy model_name verbatim from GET /models/status (lowercase ids, hyphen-separated).","Never build the URL from display_name or repo_id.","Keep the client's model list sourced from the live registry."],"tags":["models","unload","registry","validation","http-400"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}