Retries and idempotency

Retry the right errors, safely

Not every failure deserves a retry. Retrying the wrong status wastes quota; retrying without care can duplicate side effects.

What to retry

  • 429 rate limited — retry with exponential backoff and jitter; treat it as a signal to lower concurrency.
  • 500 provider or service error — retry with backoff. The failure was upstream or transient.
attempt 1 → fail
attempt 2 → wait 1s  + jitter
attempt 3 → wait 2s  + jitter
attempt 4 → wait 4s  + jitter
give up (or alert)

What not to retry

  • 402 quota exceeded — automatic retries just burn attempts; resolve plan/quota first.
  • 401, 400, 404, 422 — deterministic request problems. Fix the key, body, or feature choice.

Full details in the error catalog.

Idempotent-by-design requests

Chat completion requests are not automatically idempotent: the same request can produce different output at non-zero temperature. If you must retry a completed-but- dropped response, make the retry cheap and deterministic:

curl https://api.hardcarrx.com/v1/chat/completions \
  -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "openai",
    "model": "gpt-4.1-mini",
    "messages": [{"role": "user", "content": "Hello"}],
    "temperature": 0
  }'
  • Set temperature: 0 when reproducibility matters.
  • Keep requests small so a retry after a timeout is cheap.
  • Correlate attempts with the returned request logs ( request-log troubleshooting) to confirm whether the first attempt actually completed.

Memory writes

/v1/memory/store creates a new memory object on each call — a blind retry stores duplicates. Check the response memory_id before retrying; use /v1/memory/query on your metadata to detect an already-stored write.