Skip to content

A dropped connection during synthesis is an outage too, and the ElevenLabs status split lives in one place - #548

Merged
joaocarvoli merged 3 commits into
mainfrom
joao/eng-1122-translation_helpers-synthesize_speech-lets-a-transport-error
Sep 25, 2026
Merged

joaocarvoli merged 3 commits into
mainfrom
joao/eng-1122-translation_helpers-synthesize_speech-lets-a-transport-error

Conversation

@joaocarvoli

Copy link
Copy Markdown
Member

translation_helper/synthesize_speech.py posted to ElevenLabs with no catch around it: a dropped connection or a read timeout rose raw, a generic 500, where the other four clients answer UpstreamServiceError (502). It now catches httpx.HTTPError the way they do.

Five near-identical copies of the status-to-exception split remained after ENG-1093, three on the wide rule (401, 403, 429 or ≥ 500 are the upstream's failure; other 4xx are ours) and two, platform/stt.py and platform/tts.py, still on the narrow one, so a revoked key or a spent quota on the platform routes answered 400. The split lives once now, in app/core/exceptions.py beside the two classes it returns, with the docstring that said why 401 and 403 belong upstream; every client reads it with its own message unchanged, and the two platform routes answer 502 for a revoked key like the rest.


Verificação: 3 commits (transporte; helper compartilhado, refactor puro; stt/tts alargados); teste novo parametrizado ConnectError/ReadTimeout em test_th_audio_service.py (vermelho sem o fix); testes 401/403 em test_platform/test_stt.py e test_tts_service.py (vermelhos sem o alargamento); grep: uma definição do split; suíte dos cinco chamadores (110) e suíte inteira verdes; ruff, mypy limpos; revisora (poço-lupa) sem achados.

🤖 Generated with Claude Code

joaocarvoli and others added 3 commits September 25, 2026 10:55
…tage too

synthesize_speech's own TTS post was the one ElevenLabs call in the repo still
unwrapped: every other caller (transcribe_audio, platform/stt, platform/tts,
project_health's elevenlabs_client) already turns a dropped connection or a
read timeout into UpstreamServiceError, but this one let httpx.HTTPError rise
raw past the status-code check that only fires once a response exists — so a
network failure to ElevenLabs answered the client as a generic 500 instead of
the 502 every other path here already gives.

ENG-1093 (#542) scoped this gap out on purpose: it wrapped project_health's two
calls and widened the status split everywhere but named synthesize_speech's
TTS post as the one still open, tracked for a follow-up. This closes it, with
the same try/except httpx.HTTPError shape the other four already use.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… not three

translation_helper/synthesize_speech.py, translation_helper/transcribe_audio.py
and project_health/voice/elevenlabs_client.py each carried their own copy of
the same status-to-exception mapping (401/403/429 or >=500 -> UpstreamServiceError,
other 4xx -> ValidationError), widened to agree by ENG-1093/#542 but never
merged. app/core/exceptions.py already owns both classes and every one of
these callers already imports from it, so the shared function goes there
instead of a new module, with the docstring transcribe_audio.py carried since
it names the rationale (401/403 is not silence any more than a rate limit is).

The shared helper takes the message explicitly rather than building one string
for every caller, so each site keeps the exact wording it had ("TTS request
failed with status..." vs "Transcription request failed..."). No behaviour
changes here: every caller's own tests, unmodified, still pass, and each
still raises the same exception type with the same message for the same
status code as before.

platform/stt.py and platform/tts.py still keep their own narrower copy
(429 or >=500 only, no 401/403) — collapsing those into the same split is a
real behaviour change and lands as its own commit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…lure too

platform/stt.py and platform/tts.py were the two ElevenLabs callers still
splitting status codes the old way (429 or >=500 only): 401 and 403 read as
ValidationError there, a bad-request 400 for a key ElevenLabs itself revoked
or a quota it says is spent. The other three callers already widened this to
401/403/429/>=500 in ENG-1093/#542, and bed7bec's own body named platform/tts
as the copy left untouched.

Both now call the shared app.core.exceptions.upstream_or_validation_error,
closing the last two copies of this split — one definition, five callers.

Falsified per file: narrowing the shared helper back to 429-and-above made
each file's own new 401/403 cases fail with ValidationError again; restoring
it turned both files, and the whole suite, green.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@linear-code

linear-code Bot commented Sep 25, 2026

Copy link
Copy Markdown

ENG-1122

@little-henok little-henok Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read the whole diff: the core helper, the five clients, the three test files.

Checked that the refactor is behaviour-preserving where it claims to be — every message string survives verbatim, the three wide callers keep the wide rule, and grep leaves exactly one definition of the split in app/. The new transport catch at app/services/translation_helper/synthesize_speech.py:374 is byte-identical to the five siblings it joins. The two platform widenings land where the body says they do: nothing in app/ catches ValidationError around either call, and app/api/platform/stt.py:82 wraps the cleanup rather than the transcription, so a revoked key really does answer 502 now.

I could not run the suite from this environment, so the green run and the new parametrised cases stand unverified from here — CI settles that.

Nothing to raise. That is the whole set for this PR.

@joaocarvoli
joaocarvoli merged commit ef09bdb into main Sep 25, 2026
6 checks passed
@joaocarvoli
joaocarvoli deleted the joao/eng-1122-translation_helpers-synthesize_speech-lets-a-transport-error branch September 25, 2026 16:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant