zh-TW sapi phoneme: docs show pinyin examples, but the API returns an empty HTTP 400

Mark C 0 Reputation points
2026-08-04T11:24:19.2633333+00:00

The zh-TW phonetic-set tables in SSML phonetic alphabets have a column headed sapi Example (Bopomofo, Pinyin), and every row shows both notations — for example 知 (ㄓ, zhi 1) and 八 (ㄅㄚ or ㄅㄚˉ, ba 1).

Reading that column as a list of valid ph values, I used the pinyin form for zh-TW. Every request fails. Only Bopomofo works.

Three requests, identical apart from the voice:

voice ph result
zh-CN-YunjianNeural hao 3 200, audio returned
zh-CN-YunjianNeural hao 3 200, audio returned
zh-TW-YunJheNeural hao 3 400, content-type: text/xml, 0-byte body
zh-TW-YunJheNeural ㄏㄠˇ 200, audio returned
<speak version='1.0' xmlns='http://www.w3.org/2001/10/synthesis' xml:lang='zh-TW'>
  <voice name='zh-TW-YunJheNeural'>
    <phoneme alphabet='sapi' ph='hao 3'>好</phoneme>
  </voice>
</speak>

Rows 1 and 2 differ only in the voice, so the locale is the only variable. Row 3 shows the same voice accepts a well-formed request.

Two questions:

  1. Is the pinyin shown in the zh-TW sapi Example column intended only as a reading aid? If so, could the section state that ph must be Bopomofo for zh-TW, since a column of sapi examples reads as valid input?
  2. The 400 declares content-type: text/xml but returns zero bytes — no error code, no message, no x-microsoft-error-* header. Is that expected? The service must identify the unrecognised phone in order to reject it, and without any detail these failures are indistinguishable from a character the voice simply can't speak, which made this hard to diagnose in bulk.
Azure Speech in Foundry Tools
0 comments No comments

1 answer

Sort by: Most helpful
  1. Jerald Felix 18,040 Reputation points Volunteer Moderator
    2026-08-06T04:07:41.9633333+00:00

    Hello Mark C,

    Greetings! Thanks for raising this question in the Q&A forum.

    Your read is correct on both counts, and your test matrix proves it cleanly since voice was the only variable between the working and failing rows.

    On question 1, the pinyin shown in the zh-TW table's "sapi Example (Bopomofo, Pinyin)" column is a reading aid for people who know pinyin but not Bopomofo, it is not a second valid input format. The article's own framing sentence states that the locales listed, which include zh-TW, support the Microsoft Speech API phonetic alphabet, and that you set sapi or ipa as the alphabet value for those locales, it does not say both notations shown in an example column are independently valid ph input. For zh-CN, the native SAPI phone set genuinely is pinyin-syllable-plus-tone-number, which is why hao 3 works for zh-CN-YunjianNeural. For zh-TW, the native SAPI phone set is Bopomofo, and the pinyin is included purely so pinyin-literate readers can cross-reference the same syllable, not because the engine accepts it. Your third and fourth rows demonstrate exactly this: the same zh-TW-YunJheNeural voice accepts the well-formed Bopomofo request and rejects the pinyin one. You're right that the column header reads ambiguously as a list of valid examples, and this is a legitimate documentation clarity gap, the table should state explicitly that ph must be Bopomofo for zh-TW rather than implying pinyin is a valid alternative encoding.

    On question 2, an empty-body 400 with content-type: text/xml and no x-microsoft-error-* header is not the expected diagnostic behavior for a phoneme validation failure, and you're right that this makes it indistinguishable from other failure classes like an unspeakable character. This looks like a genuine gap in the error surface for this specific validation path rather than intended behavior.

    Treat Bopomofo as the only valid ph value for zh-TW

    Continue using the Bopomofo notation with tone diacritics as you already confirmed works, for example ㄏㄠˇ. Do not send pinyin-with-numeral-tone for any zh-TW voice, only for zh-CN.

    Build a client-side validator instead of relying on the API's error detail

    Since the API won't tell you which character in a batch failed, validate ph values against the Bopomofo symbol set before sending, rather than discovering failures per-request. This also avoids conflating unrecognized-phone errors with a voice's genuine inability to speak a given character, which was the exact ambiguity you flagged.

    File documentation feedback on the phonetic-sets page

    Since this is a clarity issue in the table itself, use the Suggest a fix / feedback link at the bottom of the SSML phonetic alphabets page to request the zh-TW section state explicitly that ph must be Bopomofo, with the pinyin marked as a reading aid only. Content feedback through that link routes directly to the doc owner listed in the page metadata rather than general support.

    Report the empty 400 body as a service-side diagnostics gap

    This is a separate issue from the documentation one and belongs with the Speech service team, not docs. Open a support request:

    • Issue type: Technical
      • Service: Azure AI Speech
        • Problem type: Text to speech / SSML errors
        In the ticket, include your exact repro SSML, the voice name zh-TW-YunJheNeural, the observed content-type: text/xml with zero-byte body, and a comparison to the working Bopomofo request. Ask specifically for the phoneme validation path to return a body or header identifying the invalid phone, since that's the concrete gap and gives the product team a clear, actionable ask rather than a general complaint.

    If this answer helps you kindly accept the answer which will help others who have similar questions.

    Best Regards,

    Jerald Felix.

    Was this answer helpful?

    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.