Analysis6 min read

Proxy errors explained: 407, 429, 502 and 504

Identify which layer returned a proxy error, check authentication and rate limits, and decide when a bounded retry of a failed request is safe.

On this page

A 407 indicates that proxy authentication is required. A 429 indicates rate limiting, but the response alone does not tell you which requests share that limit. A 502 or 504 indicates an upstream response or timeout problem. First identify where the response originated, then check authentication, limits or connectivity as appropriate.

First, identify the responding layer

An HTTPS request through an HTTP proxy normally has two exchanges: the proxy answers a CONNECT request, then the client communicates with the destination through the tunnel. An HTTPS proxy adds a TLS connection to the proxy before CONNECT. In an ordinary tunnel without TLS interception, a response received after destination TLS comes from the destination's infrastructure, which may include a CDN or reverse proxy.

The following example prints the CONNECT status separately from the HTTP response status. It requires curl 8.3 or later and uses Basic proxy authentication. Set PROXY_URL to your provider's credential-free HTTP(S) gateway, and have your secret manager populate PROXY_USERNAME and PROXY_PASSWORD in the environment. Use the authentication method your provider documents.

Save this as proxy-status.sh and run sh proxy-status.sh without shell tracing. It makes one GET request, discards the body and preserves curl's exit status. curl imports the credentials itself, so the shell does not expand them into command arguments.

sh
: "${PROXY_URL:?Set a credential-free HTTP(S) proxy URL}"
case "$PROXY_URL" in
  http://*|https://*) ;;
  *) printf '%s\n' 'PROXY_URL must use http:// or https://' >&2; exit 2 ;;
esac
case "$PROXY_URL" in
  *'@'*|*'?'*|*'#'*)
    printf '%s\n' 'Keep credentials, queries and fragments out of PROXY_URL' >&2
    exit 2 ;;
esac

curl --disable --silent --fail --http1.1 \
  --noproxy '' --proxy "$PROXY_URL" --proxy-basic \
  --variable %PROXY_USERNAME --variable %PROXY_PASSWORD \
  --expand-proxy-user '{{PROXY_USERNAME}}:{{PROXY_PASSWORD}}' \
  --connect-timeout 5 --max-time 15 --retry 0 \
  --output /dev/null \
  --write-out 'exit=%{exitcode} http=%{http_code} connect=%{http_connect} seconds=%{time_total}\n' \
  'https://example.com/'

--disable stays first to ignore curlrc settings, and --noproxy '' prevents an inherited exclusion from bypassing the selected gateway. The five-second connection budget and fifteen-second total budget are starting points for this small diagnostic. The command neither follows redirects nor retries, and prints numeric results without a verbose trace. See the curl manual for these options.

Read the fields together. connect=407 means the proxy challenged authentication during CONNECT. connect=200 http=429 means the tunnel was accepted and an HTTP 429 arrived afterwards. http=000 means no HTTP response status was recorded for the transfer; inspect the CONNECT status and curl exit code. A successful CONNECT does not establish that TLS setup or the body transfer completed.

For a plain HTTP destination, there is normally no tunnel. The proxy forwards the request, so the returned status may come from the proxy or the destination. Provider headers and branded error pages can offer clues, but appearance alone does not establish the sender. Use the provider's documented errors or request diagnostics when attribution remains uncertain.

407 Proxy Authentication Required

A 407 must include a Proxy-Authenticate challenge. The client may retry with Proxy-Authorization; the destination's Authorization header does not provide proxy authentication. These requirements come from RFC 9110, section 15.5.8.

Start with these checks:

  • Confirm the gateway, username and password match the active provider configuration.
  • Check that credentials are in the proxy-authentication setting, rather than the destination-authentication setting.
  • If the provider encodes country or session targeting in the username, check its documented format. How a malformed target is reported depends on the provider.
  • If the library requires a proxy URL containing credentials, encode the username and password separately so reserved characters cannot change the URL structure.

The 407 fix guide covers authentication diagnosis. The Python Requests guide demonstrates explicit proxy configuration and credential encoding. Follow the library's documented format before adding retries.

429 Too Many Requests

A 429 reports rate limiting. RFC 6585, section 4 deliberately leaves user identification and request counting to the responding service. The limit might apply to an account, credential, session, address, resource or wider service.

The sender tells you whose policy to investigate. A proxy may be enforcing a plan or concurrency limit; the destination may be enforcing its own request limit. Neither case establishes the scope from the status alone. Read the response details and documented limit, and honour Retry-After when supplied.

Reduce traffic at the affected scope. For a shared account limit, that can mean coordinating all workers using that account. For a limit tied to one resource, it can mean slowing requests to that resource. If the scope is unknown, reduce concurrency while investigating. Changing an exit does not establish that a limit has reset.

Backoff also needs a bound: if the required wait exceeds the remaining job deadline, stop or schedule the work for later. Repeatedly retrying during the same limit window adds load without resolving the limit.

502 and 504: an upstream failure or delay

A 502 Bad Gateway indicates an invalid upstream response. A 504 Gateway Timeout indicates that a gateway did not receive a timely upstream response. Their HTTP definitions do not identify the failed component.

In a proxy pool, investigate the exit, intervening gateways and the destination. Use provider diagnostics and a small, authorised control request to narrow the fault. Keep the destination and client settings consistent when comparing gateways, and change one variable at a time.

Three client decisions matter:

  • Whether repetition is safe. For an approved request safe to repeat, allow a small number of attempts with backoff inside an overall deadline. A failed response to a write does not prove the write was never applied. Check the operation's state or documented idempotency mechanism before resubmitting it. See HTTP retry semantics.
  • How long the job can wait. Set deadlines from the job's latency budget. A shorter client deadline limits waiting but does not repair an upstream failure. The timeout guide explains connection, transfer and overall job budgets.
  • Which failures are increasing. Track 502 and 504 separately by gateway, destination and region alongside application success rate. A change confined to one route is a reason to investigate that route, not proof that the entire pool is unhealthy.

Use a fresh connection or a different exit only when that change fits the diagnosis and session requirements. A new exit can also change the user's session context, so it is not a universal retry strategy.

403 and HTTP 200 responses with unusable content

A 403 indicates refusal. It can reflect a forward proxy's access policy or a refusal from the destination's infrastructure. Check the responding layer and its documented reason before changing credentials, headers or addresses.

A harder case to detect is an HTTP 200 response containing a challenge page, login screen or incomplete application shell. The status records an HTTP outcome; your application must also validate the content it needs. For example, a product-data task should check the expected product identifier and required fields, not just a word that might also appear in an error page.

The diagnostic command above discards the body. The Python guide likewise demonstrates configuration and status checking, so a production client needs its own destination-specific body validation. The Amazon and Google observations show why that additional check matters.

Choose the next check

Use this table after identifying the responding layer. These are starting checks, not proof of a root cause.

Observed resultWhat to investigateFirst action
CONNECT 407Proxy authenticationCheck the challenge, credential configuration and provider account.
CONNECT 429 or destination 429The responding service's limitHonour Retry-After and reduce traffic at the documented scope.
502 or 504Upstream response or timing failureCompare diagnostics; retry only work safe to repeat within its budget.
CONNECT 403 or destination 403Access policy or authorisationCheck which layer refused the request and why.
HTTP 200 with an incomplete or unexpected bodyApplication success criteriaValidate required content before counting success.
No HTTP statusConnection, tunnel or TLS progressRead curl's exit code and follow the timeout guide's stage checks.

For repeated measurements, the benchmark method explains transport logs, timing distributions and their limits. Keep the content result and any provider diagnosis alongside those logs so a status count does not become an unsupported explanation.

Sources

  1. RFC 9110: HTTP authentication, gateway responses and retry semantics
  2. RFC 6585: section 4, 429 Too Many Requests
  3. curl manual: variables, CONNECT status and timeout options

Tagged:ProxiesTroubleshooting