{"record":{"id":"5b516ff9c998a4dc","repo":"Mintplex-Labs/anything-llm","slug":"failed-to-load-or-play-tts-message-response","errorCode":null,"errorMessage":"Failed to load or play TTS message response.","messagePattern":"Failed to load or play TTS message response\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/TTSButton/asyncTts.jsx","lineNumber":26,"sourceCode":"  const playerRef = useRef(null);\n  const [speaking, setSpeaking] = useState(false);\n  const [loading, setLoading] = useState(false);\n  const [audioSrc, setAudioSrc] = useState(null);\n  const { t } = useTranslation();\n\n  function speakMessage() {\n    if (speaking) {\n      playerRef?.current?.pause();\n      return;\n    }\n\n    try {\n      if (!audioSrc) {\n        setLoading(true);\n        Workspace.ttsMessage(slug, chatId)\n          .then((audioBlob) => {\n            if (!audioBlob)\n              throw new Error(\"Failed to load or play TTS message response.\");\n            setAudioSrc(audioBlob);\n          })\n          .catch((e) => showToast(e.message, \"error\", { clear: true }))\n          .finally(() => setLoading(false));\n      } else {\n        playerRef.current.play();\n      }\n    } catch (e) {\n      console.error(e);\n      setLoading(false);\n      setSpeaking(false);\n    }\n  }\n\n  useEffect(() => {\n    function setupPlayer() {\n      if (!playerRef?.current) return;\n      playerRef.current.addEventListener(\"play\", () => {","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/3aec848f2885144aa8f1e53b9731a04310d5d558/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/TTSButton/asyncTts.jsx#L8-L44","documentation":"Per-message TTS playback. Workspace.ttsMessage(slug, chatId) requests synthesized audio and the .then handler expects a truthy Blob; when the promise resolves with a falsy value (empty body or an error response that produced no blob) this error is thrown inside the promise chain and routed to .catch, which toasts e.message.","triggerScenarios":"TTS provider not configured or disabled server-side so the endpoint returns JSON/error instead of audio; TTS API key invalid or quota exhausted; chatId/slug no longer valid so no message is found; response body empty due to a proxy stripping it.","commonSituations":"Clicking the speaker icon before configuring a TTS provider in admin settings; expired free-tier TTS quota; message deleted or workspace slug changed; CORS/proxy interfering with the audio response.","solutions":["Configure and test a TTS provider under Admin settings (voice/speech section)","Inspect the network tab — the ttsMessage response is likely JSON containing the real error, not audio","Verify the chat message still exists and the workspace slug in the URL is current","Check quota/validity of the TTS provider's API key and retry"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"const settings = await SystemSettings.fetch();\nif (!settings?.tts_model_provider) return disableTtsButton(\"Configure a TTS provider first\");","typeGuard":"function isAudioBlob(value) {\n  return value instanceof Blob && value.size > 0 && value.type.startsWith(\"audio/\");\n}","tryCatchPattern":".then((audioBlob) => {\n  if (!isAudioBlob(audioBlob))\n    throw new Error(\"Failed to load or play TTS message response.\");\n  setAudioSrc(audioBlob);\n})\n.catch((e) => showToast(e.message, \"error\", { clear: true }))","preventionTips":["Hide or disable the speak button when no TTS provider is configured","Type-check the response is a non-empty audio Blob before playing","Distinguish provider-not-configured from synthesis failure in the toast so users know where to look"],"tags":["tts","speech","audio","frontend","workspace-chat"],"backgroundTag":"tts-synthesis-failed","analyzedSha":"3aec848f2885144aa8f1e53b9731a04310d5d558","analyzedAt":"2026-08-18T10:02:21.017Z","contentChangedAt":"2026-08-18T10:02:21.017Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}