Introducing Highlights: the context that matters

HTTP 503 Service Unavailable: What It Means and How to Fix It

HTTP 503 Service Unavailable is a status code meaning the server cannot handle the request right now because of temporary overload or scheduled maintenance, and the condition will likely clear after a delay. The server may send a Retry-After header saying when to try again, which well-behaved clients and crawlers should honor before retrying.

Code
503
Name
Service Unavailable
Class
5xx server error
Retry?
Yes, with backoff

What causes a 503 error?

  • →Planned maintenance or a deploy that takes the service offline.
  • →Traffic above capacity, including traffic from aggressive crawlers.
  • →An autoscaler that has not caught up yet.
  • →A load balancer with no healthy backends.

How do you fix a 503 error when web scraping?

  • →Honor Retry-After when it is present, and back off exponentially when it is not.
  • →Lower your request rate. If your crawler is part of the load, retries make it worse.
  • →Schedule large crawls outside the site’s peak hours.

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

  • →Send Retry-After during maintenance so crawlers come back at the right time.
  • →Return 503 rather than 200 on maintenance pages, so search engines do not index the maintenance text.
  • →Shed load early with rate limits (429) before the whole service tips into 503s.

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

fetch() treats 503 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 503 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 503 error

What does 503 Service Unavailable mean?

The server is up but cannot take requests right now, usually because of overload or maintenance. It expects to recover.

How long does a 503 error last?

From seconds to hours. Check Retry-After for the server’s own estimate, and the site’s status page for maintenance windows.

Does a 503 hurt SEO?

A short 503 during maintenance is the recommended signal and does not hurt rankings. Long-running 503s can lead search engines to drop pages.

Which status codes are related to 503?

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.