decolua/9router · error

Edge TTS voices fetch failed: ${res.status}

Error message

Edge TTS voices fetch failed: ${res.status}

What it means

fetchEdgeTtsVoices() retrieves the Edge TTS voice catalog from speech.platform.bing.com using a hardcoded trustedclienttoken, caching results for VOICES_TTL. A non-2xx response throws 'Edge TTS voices fetch failed: <status>'. This is a catalog-only call (voice listing); synthesis uses getToken() instead, but voice listing features will fail with this error.

Source

Thrown at open-sse/handlers/ttsProviders/edgeTts.js:59

    headers: {
      "Content-Type": "application/x-www-form-urlencoded",
      "Accept": "*/*",
      "Origin": "https://www.bing.com",
      "Referer": "https://www.bing.com/translator",
      "User-Agent": UA,
      ...(token.cookie ? { "Cookie": token.cookie } : {}),
    },
  });
}

export async function fetchEdgeTtsVoices() {
  const now = Date.now();
  if (_voicesCache && now - _voicesCacheTime < VOICES_TTL) return _voicesCache;
  const res = await fetch(
    "https://speech.platform.bing.com/consumer/speech/synthesize/readaloud/voices/list?trustedclienttoken=6A5AA1D4EAFF4E9FB37E23D68491D6F4",
    { headers: { "User-Agent": UA } }
  );
  if (!res.ok) throw new Error(`Edge TTS voices fetch failed: ${res.status}`);
  const voices = await res.json();
  _voicesCache = voices;
  _voicesCacheTime = now;
  return voices;
}

export default {
  noAuth: true,
  async synthesize(text, model) {
    const voiceId = model || "vi-VN-HoaiMyNeural";
    let token = await getToken();
    let res = await ttsRequest(text, voiceId, token);

    // 429/403: invalidate cache and retry once
    if (res.status === 429 || res.status === 403) {
      cache.token = null;
      cache.tokenTime = 0;
      token = await getToken();

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. If 401, check the edge-tts community for the new trustedclienttoken and update the hardcoded value in open-sse/handlers/ttsProviders/edgeTts.js
  2. If 429, wait for the cache TTL or reset window; the function already caches voices for VOICES_TTL so avoid busting it
  3. Verify connectivity: curl the voices/list URL from the host to see the actual status/body
  4. Retry with backoff for 5xx/transient failures
  5. Fall back to a static/cached voice list so the UI works offline

Example fix

// before
const voices = await fetchEdgeTtsVoices();
// after
let voices;
try {
  voices = await fetchEdgeTtsVoices();
} catch (e) {
  voices = DEFAULT_EDGE_VOICES; // static fallback list
  console.warn("Edge TTS voices fetch failed, using cached list:", e.message);
}
Defensive patterns

Strategy: fallback

Validate before calling

const probe = await fetch(VOICES_URL).catch(() => null);
if (!probe || !probe.ok) console.warn("Edge TTS voice catalog unreachable — status " + (probe?.status ?? "network-error"));

Type guard

function isVoicesFetchError(e) { return e instanceof Error && e.message.startsWith("Edge TTS voices fetch failed"); }

Try / catch

try {
  const voices = await fetchEdgeTtsVoices();
} catch (e) {
  const voices = CACHED_VOICES ?? []; // serve stale/static list
  console.warn("Voice catalog unavailable:", e.message);
}

Prevention

When it happens

Trigger: The voices/list endpoint returns 401 (trusted client token revoked/rotated by Microsoft), 403 (IP/UA blocked), 429 (rate limited from repeated listing), or 5xx (Microsoft service issue).

Common situations: Microsoft rotated the trustedclienttoken (historically happens, breaking all edge-tts clients); datacenter IP blocked by the speech endpoint; dashboard voice-picker called too frequently and rate limited; regional outage.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/be265a1ce932d537. Report an issue: GitHub.