Retry transient errors and surface failed keys (don't fake passthrough)

FixTranslateService
Shipped
May 10, 2026 at 4:33 AM UTC
Author
Kamo
Commit
c0a87b7

Two failure modes were indistinguishable in the response, so the script couldn't tell them apart and kept "translating" the same keys to English on every sync run, with random subsets succeeding due to which exact LibreTranslate request happened to land during a worker restart: 1. Provider errored (timeout, 5xx, connection refused mid-restart) 2. Provider succeeded but returned source unchanged (legit "no translation needed" — proper nouns, brand names, etc.) Both ended up writing the source as the translation. Changes: * LibreTranslateProvider / BergamotProvider: 3 attempts with 1s/3s backoff for transient failures (5xx, 429, timeout, connection errors); 4xx (non-429) propagates immediately because retrying a malformed request will never help. Per-call request timeout = 30s. Throws on retry exhaustion instead of returning the source text. * ProviderRouter: now distinguishes "every supporting provider errored" (throws) from "at least one succeeded but returned source" (legitimate passthrough — returns text). No-supports unchanged. * **************** catches per-key exceptions, collects them in a new failedKeys list on the response, and omits failed keys from messages. * BatchTranslateResponse: adds failedKeys field. * translate.ts: reads failedKeys, never writes those keys back, so the apiTranslated[key] ?? existing[key] fallback leaves the prior English value in place — which on the next run satisfies cur===enVal and re-queues exactly those keys for retry. Tests: added regression tests for "all providers errored throws", "at least one succeeded with unchanged text returns text", "router fallthrough on transient primary error", and TranslationService correctly partitioning into messages vs failedKeys.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing