{"record":{"id":"ff9ff6697e90e08c","repo":"decolua/9router","slug":"bing-tts-returned-empty-audio","errorCode":null,"errorMessage":"Bing TTS returned empty audio","messagePattern":"Bing TTS returned empty audio","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"open-sse/handlers/ttsProviders/edgeTts.js","lineNumber":86,"sourceCode":"  async synthesize(text, model) {\n    const voiceId = model || \"vi-VN-HoaiMyNeural\";\n    let token = await getToken();\n    let res = await ttsRequest(text, voiceId, token);\n\n    // 429/403: invalidate cache and retry once\n    if (res.status === 429 || res.status === 403) {\n      cache.token = null;\n      cache.tokenTime = 0;\n      token = await getToken();\n      res = await ttsRequest(text, voiceId, token);\n    }\n\n    if (!res.ok) {\n      const body = await res.text().catch(() => \"\");\n      throw new Error(`Bing TTS failed: ${res.status}${body ? \" - \" + body : \"\"}`);\n    }\n    const buf = await res.arrayBuffer();\n    if (buf.byteLength < 1024) throw new Error(\"Bing TTS returned empty audio\");\n    return { base64: Buffer.from(buf).toString(\"base64\"), format: \"mp3\" };\n  },\n};\n","sourceCodeStart":68,"sourceCodeEnd":90,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/open-sse/handlers/ttsProviders/edgeTts.js#L68-L90","documentation":"After Bing's tfettts endpoint responds 200, edgeTts.js reads the body and requires at least 1024 bytes before treating it as valid MP3 audio; a smaller payload throws \"Bing TTS returned empty audio\". This guards against responses that look successful but contain no usable audio (error pages, empty bodies, stub responses from the undocumented endpoint).","triggerScenarios":"The Bing TTS endpoint returns HTTP 200 but a tiny body — typically when Bing silently rejects the SSML/token (returns an empty or stub response), the requested voiceId is invalid/unsupported, the text is empty or only whitespace, or Bing returns an HTML error page smaller than 1KB with a 200 status.","commonSituations":"Passing a made-up or removed voice id (e.g. \"xx-YY-FooNeural\") that Bing accepts but cannot synthesize; sending empty text after client-side trimming; Bing A/B-testing a new response format that no longer returns MP3; intermittent Bing flakiness where the endpoint 200s with an empty body.","solutions":["Verify the voice id is real by fetching the voice list (fetchEdgeTtsVoices) and picking one of its `ShortName` values instead of a hand-typed id.","Check that the text argument is non-empty and non-whitespace before calling synthesize; log the text length when this fires.","Retry the request — this is often transient; the module refreshes its Bing token every ~5 minutes, so a later attempt may use a fresh token.","Inspect the actual response: temporarily log res body/headers on this path; if Bing consistently returns HTML instead of audio, its endpoint changed and this provider needs updating or replacing.","Fall back to another TTS provider for affected requests."],"exampleFix":"// before\ntext = userInput.trim();\nawait edgeTts.synthesize(text, \"my-custom-voice\");\n// after: validate inputs against the real voice list\nconst voices = await fetchEdgeTtsVoices();\nconst voice = \"my-custom-voice\";\nif (!text?.trim()) throw new Error(\"TTS text is empty\");\nif (!voices.some(v => v.ShortName === voice)) throw new Error(`Unknown voice: ${voice}`);\nawait edgeTts.synthesize(text.trim(), voice);","handlingStrategy":"validation","validationCode":"import { fetchEdgeTtsVoices } from \"open-sse/handlers/ttsProviders/edgeTts.js\";\nif (!text?.trim()) throw new Error(\"TTS text is empty\");\nconst voices = await fetchEdgeTtsVoices();\nif (!voices.some(v => v.ShortName === voiceId)) throw new Error(`Unknown Edge voice: ${voiceId}`);","typeGuard":"function isValidEdgeVoice(voice, voices) {\n  return typeof voice === \"string\" && voices.some(v => v.ShortName === voice);\n}","tryCatchPattern":"try {\n  const audio = await edgeTts.synthesize(text, voiceId);\n} catch (e) {\n  if (e.message === \"Bing TTS returned empty audio\") {\n    // usually invalid voice or empty text — retry once with a known-good default voice\n    return edgeTts.synthesize(text, \"en-US-AriaNeural\");\n  }\n  throw e;\n}","preventionTips":["Always pick voice ids from fetchEdgeTtsVoices() rather than hand-typing them.","Reject empty/whitespace text at the API boundary.","Retry once on this error before surfacing it — it is often transient.","If it becomes consistent, suspect a Bing endpoint/format change and check for library updates."],"tags":["tts","empty-response","validation","upstream-provider"],"backgroundTag":"empty-response-body","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}