scrapy 429 too many requests retry middleware ignoring Retry-After header
Fixes Scrapy retry middleware skipping the server's Retry-After header on 429s: RETRY_HTTP_CODES config, custom middleware, and backoff. Use when 429s retry immediately instead of waiting. Not for 403 bot blocks or IP bans where retrying is the wrong move.
TL;DR
Scrapy's retry middleware does not honor Retry-After out of the box. Add 429 to RETRY_HTTP_CODES (or write a small middleware that sleeps the header's value), and set a sane RETRY_TIMES and download delay. If 429s keep coming after you honor the header, the site wants you slower or gone.
scrapy 429 too many requests retry middleware ignoring Retry-After headerUse this when
- Logs show
429 Unknown Statusretried immediately, seconds apart. - The target sends a
Retry-Afterheader that your spider never waits for. - You are crawling with permission and the fix is politeness, not volume.
Not for this skill when
- The status is 403. That is a refusal, and retry middleware is not the tool.
- The 429 comes with a block page or CAPTCHA. Waiting does not fix a challenge.
Steps
- Confirm the header is present: log
response.headers.get(b"Retry-After")on a 429. Verify: you see an integer number of seconds. - Add the code to retries:
RETRY_HTTP_CODES = [500, 502, 503, 504, 522, 524, 408, 429]in settings.py. Verify: retries still occur, now classified as retryable. - Install a middleware that reads the header before retrying. Minimal version: subclass
RetryMiddleware, inprocess_responsecheckresponse.status == 429, read the header,time.sleep(value)or reschedule withdont_filter=True. Verify: request spacing on 429s matches the header value in logs. - Set
RETRY_TIMES = 3andDOWNLOAD_DELAY = 2as a floor. Verify: overall request rate drops and 429 frequency falls. - If 429s persist after honoring Retry-After twice, back off the crawl (halve CONCURRENT_REQUESTS) or stop that domain. Verify: the domain stops returning 429 for the next hour.
Variant phrasings
scrapy retry middleware 429
The short phrasing, lands on the same settings.
scrapy does not wait Retry-After
Symptom phrasing, points at the custom middleware in step 3.
scrapy too many requests immediate retry
Behavior phrasing, the diagnosis in step 1.
Compatibility: Scrapy 2.x. The default retry middleware honors nothing about timing; the header handling is always custom.
Why it happens
The retry middleware was built for transient 5xx failures, where immediate retry is fine. A 429 is a rate signal, not a blip, and the stock middleware treats it identically: it re-queues the request with no delay. Honoring Retry-After is a small custom-middleware job, not a setting, which is why so many spiders miss it.
Edge cases / pitfalls
- Some servers send
Retry-Afteras an HTTP date, not seconds. Parse both. AUTOTHROTTLE_ENABLEDhelps with gradual overload but does not read the header either. Use both.- Sleeping inside
process_responseblocks the whole engine. For big crawls, reschedule with a delayed re-request instead oftime.sleep. - A 429 that never clears after backoff is a soft ban. Continuing to crawl is the problem, not the middleware.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_tyOrw6VaTjTHqPP8h02NQw