{"record":{"id":"2d4d3774d7d5e80c","repo":"open-webui/open-webui","slug":"mistral-api-key-is-required-for-mistral-tts","errorCode":null,"errorMessage":"Mistral API key is required for Mistral TTS","messagePattern":"Mistral API key is required for Mistral TTS","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"backend/open_webui/routers/audio.py","lineNumber":513,"sourceCode":"            },\n        )\n        sf.write(str(file_path), wav['audio'], samplerate=wav['sampling_rate'])\n\n    await asyncio.to_thread(_run_pipeline)\n\n    # Audio file already written by sf.write; just persist the request metadata.\n    async with aiofiles.open(file_body_path, 'w') as f:\n        await f.write(json.dumps(payload))\n    return FileResponse(file_path)\n\n\nasync def _tts_mistral(request, payload, file_path, file_body_path, user):\n    \"\"\"Generate speech via the Mistral TTS API.\"\"\"\n    api_key = await Config.get('audio.tts.mistral.api_key')\n    api_base_url = await Config.get('audio.tts.mistral.api_base_url') or 'https://api.mistral.ai/v1'\n\n    if not api_key:\n        raise HTTPException(status_code=400, detail='Mistral API key is required for Mistral TTS')\n\n    r = None\n    try:\n        session = await get_session()\n        r = await session.post(\n            url=f'{api_base_url}/audio/speech',\n            json={\n                'input': payload.get('input', ''),  # text to synthesize\n                'model': await Config.get('audio.tts.model') or 'voxtral-mini-tts-2603',\n                'voice_id': payload.get('voice', ''),\n                'response_format': 'mp3',\n            },\n            headers={\n                'Content-Type': 'application/json',\n                'Authorization': f'Bearer {api_key}',\n            },\n            ssl=AIOHTTP_CLIENT_SESSION_SSL,\n        )","sourceCodeStart":495,"sourceCodeEnd":531,"githubUrl":"https://github.com/open-webui/open-webui/blob/01f4282f1ffe0d6212f58d3afbeae21fffd0c4be/backend/open_webui/routers/audio.py#L495-L531","documentation":"HTTP 400 raised in _tts_mistral (backend/open_webui/routers/audio.py) when the audio.tts.mistral.api_key config is empty. The Mistral TTS handler requires a Bearer token for POST {api_base_url}/audio/speech and fails fast before making the request.","triggerScenarios":"Selecting 'mistral' as audio.tts.engine in Admin Settings without entering a Mistral API key, or having the key stored as an empty string.","commonSituations":"Admin switched the TTS engine to Mistral but skipped the key field; the key was cleared during a config migration or reset; env-var-based key not passed into the container.","solutions":["Set the Mistral API key under Admin Settings > Audio (audio.tts.mistral.api_key) and retry.","If configured via environment/config file, ensure the key value is non-empty and the backend is restarted.","Confirm the key is valid by calling the Mistral API directly (e.g. their models endpoint) to rule out an auth mix-up."],"exampleFix":"# before (env)\nAUDIO_TTS_ENGINE=mistral\n# no api key set\n\n# after\nAUDIO_TTS_ENGINE=mistral\nAUDIO_TTS_MISTRAL_API_KEY=<your-key>","handlingStrategy":"validation","validationCode":"api_key = await Config.get('audio.tts.mistral.api_key')\nif engine == 'mistral' and not api_key:\n    raise HTTPException(400, 'Configure audio.tts.mistral.api_key before using Mistral TTS')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate engine-specific credentials in Admin Settings before saving the engine choice.","Add a 'test connection' button that probes the provider when credentials are entered.","Include required keys per engine in deployment checklists."],"tags":["tts","mistral","configuration","api-key","audio"],"backgroundTag":null,"analyzedSha":"01f4282f1ffe0d6212f58d3afbeae21fffd0c4be","analyzedAt":"2026-08-14T18:25:22.715Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}