Skip to content

Commit c83078f

Browse files
sjsyrekclaude
andcommitted
docs: align retry troubleshooting and changelog with the shipped transport policy
TROUBLESHOOTING no longer claims universal 5xx auto-retry or the fixed backoff ladder; API.md documents the shared wall-clock retry budget next to the global flags. The changelog drops the watch filesWatched entry (that counter was deliberately left for a follow-up issue, not fixed in this batch) and gains the trace-ID cross-quoting and idempotent-classification fixes that shipped with it. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent ae34cd7 commit c83078f

3 files changed

Lines changed: 8 additions & 5 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7979
- **sync**: TMS request URLs are built with the URL API: a trailing slash on `server:` no longer produces a doubled separator, a base path is preserved, and a URL with a query string or fragment is rejected instead of silently truncating the API path. TMS timeouts now exit with the network-error code (5) instead of 1, TMS error messages redact credentials embedded in the server URL, and `deepl sync pull` enforces a 32 MiB cap on the response body while reading it, instead of after the whole payload had been parsed.
8080
- **api**: Non-idempotent POST requests are no longer re-submitted after a client-side timeout. Every failure short of a 4xx reached the retry loop for all HTTP methods, so a batch or document upload that outlived the 30 s timeout was silently re-sent up to three more times — each already accepted and billed server-side (confirmed with server-side request counts: 4 per timed-out translate and upload), with the worst case being duplicate admin API keys whose secret is returned only once. Automatic retry is now restricted to idempotent methods (GET, HEAD, PUT, DELETE); a POST is replayed only on an error that proves the request never reached the server (`ECONNREFUSED`, `ENOTFOUND`, `EAI_AGAIN`). A 429 is still retried for every method, honoring `Retry-After`.
8181
- **api**: A client-side timeout now exits 5 (network error) instead of 6 (invalid input), matching the documented exit-code contract. Error classification substring-matched the message and missed axios's `timeout of 30000ms exceeded` (`ECONNABORTED` and `ERR_CANCELED` were absent entirely), falling through to `ValidationError` — so CI that retries on 5 and hard-fails on 6 did exactly the wrong thing on a flaky network. Classification now branches on `error.code` and the absence of a response. An HTTP 401 is likewise mapped to `AuthError` (exit 2) instead of falling through to exit 6.
82-
- **api**: Retries run under an overall time budget rather than only a per-attempt timeout, so a never-responding server no longer holds a single command for two minutes (measured 125 s before). Honest `Retry-After` waits are not charged against the budget.
82+
- **api**: Retries run under an overall time budget rather than only a per-attempt timeout — twice the request timeout by default — so a never-responding server no longer holds a single command for two minutes (measured 125 s before). Honest `Retry-After` waits are not charged against the budget.
83+
- **api**: The Trace ID quoted in an error message now belongs to the request that failed rather than the client's last-seen response, so concurrent requests no longer cross-quote each other's Trace IDs.
84+
- **api**: Errors already classified by the API client are no longer re-classified when a client wraps its own error handling, which could turn a validation error into a network error and drop its recovery hint. Error messages also no longer print a doubled `Network error: Network error:` prefix.
8385
- **api**: The document translation result endpoint is never retried — the download is effectively single-use, so a retry after a timeout on a large file could permanently lose an already-billed translation — and document transfers get their own larger timeout.
8486
- **voice**: `deepl voice` now actually reconnects after a transport failure. The socket `error` handler marked the stream ended before the `close` event that always follows arrived, so the reconnect path (up to 3 attempts, `--reconnect` on by default) was unreachable for a real network drop — only a clean remote close ever reconnected. A reconnect that exhausts its attempts now closes the audio input instead of leaving the stream generator awaiting forever.
85-
- **watch**: `deepl watch` statistics now report the number of watched files; the counter was never incremented.
8687

8788
### Security
8889

‎docs/API.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ Options that work with all commands:
5656
--max-retries N Maximum automatic retries for retryable requests (default: 3)
5757
```
5858

59+
Automatic retries apply to idempotent requests, and to rate-limited (429) responses for every method; a request that submits work is otherwise never replayed. Retries share a wall-clock budget of twice `--timeout`, so raising `--max-retries` alone does not extend how long the CLI waits on an unresponsive endpoint.
60+
5961
**Examples:**
6062

6163
```bash

‎docs/TROUBLESHOOTING.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ Common issues and solutions when using the DeepL CLI.
139139

140140
2. For batch/directory translation, the CLI uses concurrency control internally. Avoid running multiple CLI instances simultaneously on the same API key.
141141

142-
3. The CLI automatically retries with exponential backoff (1s, 2s, 4s, up to 10s, max 3 retries). If errors persist, wait and try again.
142+
3. Retries honor the server's `Retry-After` header when present, falling back to full-jitter exponential backoff (max 3 retries by default; see the global `--max-retries` flag). If errors persist, wait and try again.
143143

144144
---
145145

@@ -167,7 +167,7 @@ Common issues and solutions when using the DeepL CLI.
167167
export HTTP_PROXY=http://proxy.example.com:8080
168168
```
169169

170-
4. The CLI retries on transient network errors automatically with exponential backoff.
170+
4. The CLI retries idempotent requests on transient network errors automatically. Requests that submit work (translations, document uploads, glossary creation) are replayed only when the error proves the request never reached the server, so they are never double-billed — for those, rerun the command (exit code 5 is safe to retry at the script level).
171171

172172
### "Request failed with status code 503"
173173

@@ -183,7 +183,7 @@ Common issues and solutions when using the DeepL CLI.
183183
deepl translate "Hello" --to es --no-cache
184184
```
185185

186-
3. The CLI automatically retries on 503 errors with exponential backoff. If the error persists, the API may be experiencing an extended outage.
186+
3. Read-only requests are retried automatically on 503. Requests that submit work (translate, document upload) surface the error immediately so they are never double-billed; retry them at the script level (exit code 5). If the error persists, the API may be experiencing an extended outage.
187187

188188
---
189189

0 commit comments

Comments
 (0)