Summary
ytdlp_downloader.py builds ydl_opts without retries, extractor_retries or fragment_retries. Through yt-dlp's Python API that means zero retries, because RetryManager.__init__ does:
self.retries = _retries or 0
An unset key arrives as None, and None or 0 is 0. The CLI does not have this problem because options.py sets default=10 for --retries and default=3 for --extractor-retries. Those defaults live in the argument parser, so nothing applies them when the library is driven directly.
Demonstrated without touching the network:
Transmute (key unset -> None) retries=0 total_attempts=1
CLI default --retries 10 retries=10 total_attempts=11
So a single transient HTTP 403 from YouTube, which yt-dlp would normally ride out, ends the download immediately.
Second half of the problem
"ignoreerrors": True means the per-entry failure never raises. extract_info returns with the entry as None, it gets filtered out here:
entries = [entry for entry in (raw_entries or []) if entry]
if not entries:
shutil.rmtree(staging_dir, ignore_errors=True)
raise DownloadError("yt-dlp completed but no files were downloaded")
and the caller answers 422. The real cause, ERROR: unable to download video data: HTTP Error 403: Forbidden, is printed by yt-dlp but never reaches the API response or the UI. From the user side a retryable network blip is indistinguishable from an unsupported URL.
Suggested fix
Two small changes in ydl_opts:
"retries": 10,
"extractor_retries": 3,
"fragment_retries": 10,
and capturing the yt-dlp error so the message can be surfaced instead of the generic "no files were downloaded". A logger hook or dropping ignoreerrors for the single-video case would both work, though ignoreerrors is clearly there on purpose for playlists, so the single-entry path is probably where to special case it.
On effect size, which I did not manage to measure
Being upfront about the limits of what I checked. I could not put a number on how much the retry setting helps in practice.
I hit this while YouTube was returning intermittent 403s. On the stock image at that point, success was about 42 percent across two different videos, so it was not specific to one video. By the time I ran the retries=0 against retries=10 comparison the condition had cleared, and both configurations scored 8 out of 8. With nothing failing there is nothing for a retry to recover, so the two are indistinguishable in that data.
Some of that intermittency was likely self inflicted, since I had pulled a fair number of test downloads from one address by then. Manufacturing another bad window to get a cleaner number did not seem like a reasonable thing to do to your upstream.
So treat the retry count as a code reading finding rather than a measured improvement. Making one attempt where yt-dlp's own CLI makes eleven looks wrong on its face, and the swallowed error message is worth fixing regardless of how often the underlying failure happens.
Summary
ytdlp_downloader.pybuildsydl_optswithoutretries,extractor_retriesorfragment_retries. Through yt-dlp's Python API that means zero retries, becauseRetryManager.__init__does:An unset key arrives as
None, andNone or 0is0. The CLI does not have this problem becauseoptions.pysetsdefault=10for--retriesanddefault=3for--extractor-retries. Those defaults live in the argument parser, so nothing applies them when the library is driven directly.Demonstrated without touching the network:
So a single transient HTTP 403 from YouTube, which yt-dlp would normally ride out, ends the download immediately.
Second half of the problem
"ignoreerrors": Truemeans the per-entry failure never raises.extract_inforeturns with the entry asNone, it gets filtered out here:and the caller answers 422. The real cause,
ERROR: unable to download video data: HTTP Error 403: Forbidden, is printed by yt-dlp but never reaches the API response or the UI. From the user side a retryable network blip is indistinguishable from an unsupported URL.Suggested fix
Two small changes in
ydl_opts:and capturing the yt-dlp error so the message can be surfaced instead of the generic "no files were downloaded". A
loggerhook or droppingignoreerrorsfor the single-video case would both work, thoughignoreerrorsis clearly there on purpose for playlists, so the single-entry path is probably where to special case it.On effect size, which I did not manage to measure
Being upfront about the limits of what I checked. I could not put a number on how much the retry setting helps in practice.
I hit this while YouTube was returning intermittent 403s. On the stock image at that point, success was about 42 percent across two different videos, so it was not specific to one video. By the time I ran the retries=0 against retries=10 comparison the condition had cleared, and both configurations scored 8 out of 8. With nothing failing there is nothing for a retry to recover, so the two are indistinguishable in that data.
Some of that intermittency was likely self inflicted, since I had pulled a fair number of test downloads from one address by then. Manufacturing another bad window to get a cleaner number did not seem like a reasonable thing to do to your upstream.
So treat the retry count as a code reading finding rather than a measured improvement. Making one attempt where yt-dlp's own CLI makes eleven looks wrong on its face, and the swallowed error message is worth fixing regardless of how often the underlying failure happens.