Updated

Why agent retries cost more than you think

A failed tool call is not just one wasted request. The agent appends the error to the conversation and re-sends the whole history, so every retry costs more tokens than the last. A long run that dies late returns nothing for all of it. Start at fastaf.co.

Answer first

  • Fail fast: set a timeout on each data call and a hard cap on attempts (2-3).
  • Retry only errors that can change: 429, 502, 503 and network timeouts. A 400, 402, 404 or 422 will come back the same.
  • Keep error traces short: pass the agent a one-line error, not the full response.
  • Use a data API that does not bill failures, so retries cost tokens only.

FastAF source timeouts and outages use 503 with Retry-After: 5 and {error: {code: "upstream_timeout" | "upstream_unavailable", message, stage: "upstream_fetch", retry_after: 5}}, not a billable result. Reserved credits on /v1 are refunded; x402 does not settle. See source outages.

What FastAF does

  • With x402, failed calls are not charged: the payment is verified before the call and settled only when FastAF answers 200. Source errors, empty results, blocks and invalid input are not settled.
  • FastAF already retries a transient failure once on its side for search routes (Google, Bing, news, shopping and the other structured searches), inside the same paid call. Keep your own retries few.
  • The 402 price quote comes back before any payment: on 28 October 2026, eight unpaid requests got it in 61-308 ms.
  • Fixed prices per call (Google search $0.003). Retries do not add to the bill, because only an attempt answered with 200 is settled: the worst case is calls x price. See the x402 price list.

Pattern

import time
import requests

URL = "https://api.fastaf.co/x402/v1/serp"
RETRY_ON = {429, 502, 503}  # temporary; 400, 402, 404, 422 will not change on a retry


def search(query, session=None, attempts=3):
    """Return (data, None) or (None, one-line error for the agent)."""
    http = session or requests.Session()
    error = "search failed: not attempted"
    for attempt in range(attempts):
        wait = 2 ** attempt  # 1 s, then 2 s
        try:
            r = http.get(URL, params={"query": query}, timeout=20)
        except requests.RequestException as exc:
            error = f"search failed: {type(exc).__name__}"
        else:
            if r.status_code == 200:
                return r.json(), None
            error = f"search failed: HTTP {r.status_code}"
            if r.status_code not in RETRY_ON:
                break
            if r.headers.get("Retry-After", "").isdigit():
                wait = int(r.headers["Retry-After"])
        if attempt + 1 < attempts:
            time.sleep(wait)
    return None, error


data, error = search("mcp registry")
print(error or data)

Run as is, with a plain requests.Session, it stops at the first attempt with search failed: HTTP 402: nothing pays the quote. To pay, pass a session wrapped by an x402 client, for example wrapRequestsWithPayment(requests.Session(), client) from the x402 Python package (pip install "x402[clients,evm]") with an EVM signer registered for Base. The client signs the 402 quote and retries the same request; FastAF settles only if that request returns 200. For a complete client in JavaScript (@x402/fetch with a wallet key), see the x402 example in the docs.

A client timeout is not a FastAF failure: FastAF decides on settlement from its own answer, not from whether your client is still waiting. Keep the timeout above the normal latency of the route you call.

Related: heavy pages and timeouts, fallback search provider, agent spend caps.

Try it: 500 free credits every month after email verification, or x402 with no account.

Source of the advice: builders on X, October 2026 (retry storms in agent loops).

Reference

Other sources

Compare