Closed general

say --rate=-4% returns HTTP 500, reported as "service flapping"

John Lauer · 1mo ago ·closed by John Lauer

adom-tts say --rate=-4% returns HTTP 500, and the CLI reports it as "service flapping"

A negative --rate makes every synthesis fail. The same text with no --rate succeeds immediately, so the request is being rejected rather than the service being unhealthy.

Reproduced on galliaApril against service-tts 0.0.1 / edge-tts 7.2.8:

T="The Adom Mesh gives your machines a way to reach each other over the network."
adom-tts say "$T" --out a.mp3                                  # OK
adom-tts say "$T" --voice en-US-AndrewNeural --out b.mp3       # OK
adom-tts say "$T" --rate=-4% --out c.mp3                       # HTTP 500 x4, no file

adom-tts health reports {"ok":true} throughout.

The reason this is worth fixing is the error text, not the failure. The CLI prints:

adom-tts: HTTP 500 (attempt 1/4) - service flapping, retrying
...
# hint: service-tts failing - retry later. Long text is already auto-chunked;
#       do NOT install a local TTS engine.

Every word of that points away from the actual cause. It names the service as unhealthy, tells the caller to wait, and pre-emptively rules out the two things a caller would otherwise suspect (their own text, their own setup). An AI caller following that advice does exactly what I did: retry with backoff for an hour, conclude the service is down, and never look at its own arguments. The tell that finally broke it was noticing that every call which HAD worked was one I had written without --rate.

Two asks, either of which would have saved the hour:

  1. Accept a negative rate, or reject it with a 400 and a message naming the argument. edge-tts itself takes -4% happily, so if the value needs a different spelling on the wire (-4% vs -04%), normalise it in the CLI.
  2. Do not describe a 500 as "service flapping" unconditionally. A 500 that repeats identically for the same arguments while health stays green is not a flap. Worth distinguishing "retried and it worked" from "retried four times, same result" in the hint, and saying which arguments were sent.

Context: I hit this generating the voiceover for the Adom Bridge mesh demo (six clips, en-US-AndrewNeural). Dropping --rate produced all six on the first attempt.

1 Reply

John Lauer · 1mo ago

Both asks done. Root cause was on the service, and the error text was the CLI's.

The 500: service-tts passed --rate and its value to edge-tts as two argv items, so -4% was read by argparse as an unknown option and edge-tts exited 2. The service wrapped that as a bare 500 ("edge-tts exited 2"). Nothing was unhealthy; every negative rate failed, every positive one worked.

service-tts (adom-inc/service-tts@93e0bb4, deployed by the container's watchdog):

  • edge-tts is now called with --flag=value, so a negative rate, or text that starts with a dash, can never be parsed as an option. -4% returns 200.
  • rate, voice and text are validated up front. A malformed value returns 400 with the field named, e.g. {"error":"rate must be a signed percentage like +10% or -4% (got \"fast\")","field":"rate"}.
  • Any edge-tts failure now carries the last stderr line and the arguments in the error body instead of just the exit code.

adom-tts 1.9.53:

  • --rate is validated in the CLI before anything is sent: +10%, -4%, and the spellings people type (10, -4, 15%) are normalised; anything else is refused with the flag named and the --rate=-4% spelling shown.
  • A 4xx prints service said: ... with the field the service named.
  • A 5xx that repeats identically on all four attempts is no longer called flapping. The message says it repeated with identical arguments, prints those arguments (voice, rate, chars), prints what the service said, and tells the caller to try the same text without --rate and --voice before blaming the service. The interim retry line just says "retrying". The events log carries the same detail.
  • Docs: the user skill and README state the rate contract.

Verified live against the deployed service after the watchdog picked up the commit: -4% returns 200 audio, fast returns 400 with the field named, and adom-tts say "..." --rate=-4% produces the file on the first attempt.

Log in to reply.