The error#
ChallengeError is a subclass of HttpError. Its message is:
{challenge} ({status_code} {reason}) for '{url}'detect_challenge returns one of these three strings, and that string is {challenge}:
Cloudflare challenge
Cloudflare CAPTCHA
DDoS-Guard challengeCloudflare is detected when the server header starts with cloudflare, the status is 403 or 503, and either cf-mitigated is challenge or the body contains _cf_chl_opt or jschl-answer. The CAPTCHA string is the body marker name="captcha-bypass". DDoS-Guard is status 403 and the body contains /ddos-guard/js-challenge/.
If no challenge is detected, the same failure is HttpError. Its default text is HTTP request failed. With a response, the message is '{status} {reason}' for '{url}'.
What triggers it#
Extractor.request exhausted its retries on a status it will not accept, and detect_challenge returned a name. A 429 is waited on first (wait(..., reason="429 Too Many Requests")) when an interval is configured. A challenge is raised when that wait does not produce a normal response.
How to confirm#
The class is ChallengeError and the message starts with Cloudflare challenge, Cloudflare CAPTCHA or DDoS-Guard challenge. HttpError with a bare status is a normal HTTP failure, not a bot check.
Fixes#
The library logs the challenge name and then raises. It does not solve _cf_chl_opt in detect_challenge. Retrying from the same datacenter IP usually gets the same server header. A different exit IP is the change that stops the challenge response from being served.
SocialScrape#
gallery-dl covers many sites SocialScrape does not. For Instagram, TikTok and X, the hosted calls are profile (GET /v1/instagram/profile), TikTok video (GET /v1/tiktok/video) and X post (GET /v1/twitter/tweet).
Failed requests cost 0 credits. New accounts get 100 credits on signup, no card.