Introducing Highlights: the context that matters

HTTP 502 Bad Gateway: What It Means and How to Fix It

HTTP 502 Bad Gateway is a status code meaning a server acting as a gateway or proxy got an invalid response from the upstream server it contacted. Load balancers, CDNs, and reverse proxies such as nginx return it when the application behind them crashes, restarts, or answers with something that is not valid HTTP.

Code
502
Name
Bad Gateway
Class
5xx server error
Retry?
Yes, with backoff

What causes a 502 error?

  • →The application server crashed or is restarting during a deploy.
  • →The proxy points at the wrong upstream address or port.
  • →The upstream closed the connection or sent a malformed response.
  • →A firewall between the proxy and the upstream dropping traffic.

How do you fix a 502 error when web scraping?

  • →Retry with exponential backoff. Most 502s last seconds to minutes.
  • →Lower concurrency. A struggling upstream recovers faster with less load.
  • →If one proxy exit always gets 502 and others do not, the problem may be your proxy, not the site.

How do you fix a 502 error on your own server?

  • →Check the upstream application logs first, then the proxy’s error log for the upstream address and error.
  • →Use health checks and rolling deploys so the proxy never routes to a restarting instance.
  • →Match keep-alive timeouts so the upstream does not close connections the proxy is about to reuse.

How do you handle a 502 error in a retry loop?

fetch() treats 502 as temporary. It waits for Retry-After when the server sends a number of seconds, otherwise backs off exponentially with jitter, caps every wait at 60 seconds, and gives up after five attempts.

import random
import time

import requests

RETRYABLE = {408, 429, 500, 502, 503, 504, 520, 521, 522, 523, 524}


def fetch(url: str, max_attempts: int = 5) -> requests.Response:
    for attempt in range(max_attempts):
        try:
            response = requests.get(url, timeout=(10, 60))
        except requests.Timeout:
            time.sleep(2**attempt + random.uniform(0, 1))
            continue
        if response.status_code not in RETRYABLE:
            response.raise_for_status()
            return response
        retry_after = response.headers.get("Retry-After", "")
        backoff = 2**attempt + random.uniform(0, 1)
        time.sleep(min(int(retry_after) if retry_after.isdigit() else backoff, 60))
    raise RuntimeError(f"Gave up on {url} after {max_attempts} attempts")

How does Context.dev handle a 502 error?

Context.dev retries the fetch for you, and by default Scrape can reuse a capture made in the last 3 days (maxAgeMs), so a page that is briefly down may still come back from cache. If no capture is available, the failed output carries an error_code and message inside an HTTP 200 response, and a request where every output fails is not charged. The Context.dev SDKs retry twice with exponential backoff after connection errors and 408, 409, 429, and 5xx responses from the API itself.

See what the web scraping API does on every request, or read how to fix HTTP errors in web scraping for a longer walkthrough.

Frequently asked questions about a 502 error

What does err 502 mean?

A proxy, CDN, or load balancer could not get a valid response from the server behind it. The origin application is usually down, restarting, or misconfigured.

Is a 502 Bad Gateway temporary?

Usually. Most 502s clear when the upstream restarts or recovers. Persistent 502s point to a configuration error between proxy and upstream.

What is the difference between 502 and 504?

A 502 means the upstream sent a bad response. A 504 means it sent no response in time.

Which status codes are related to 502?

Sources

Last reviewed

Ship an agent that actually knows things.

Free tier, 10-minute integration, and the same API powering agents at Mintlify, daily.dev, and Propane. No credit card to start.