{"record":{"id":"5e5a21d10bb77de6","repo":"yt-dlp/yt-dlp","slug":"e","errorCode":null,"errorMessage":"e","messagePattern":"e","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"yt_dlp/utils/_utils.py","lineNumber":5300,"sourceCode":"\n    def __iter__(self):\n        while self._should_retry():\n            self.error = NO_DEFAULT\n            self.attempt += 1\n            yield self\n            if self.error:\n                self.error_callback(self.error, self.attempt, self.retries)\n\n    @staticmethod\n    def report_retry(e, count, retries, *, sleep_func, info, warn, error=None, suffix=None):\n        \"\"\"Utility function for reporting retries\"\"\"\n        if count > retries:\n            if error:\n                return error(f'{e}. Giving up after {count - 1} retries') if count > 1 else error(str(e))\n            raise e\n\n        if not count:\n            return warn(e)\n        elif isinstance(e, ExtractorError):\n            e = remove_end(str_or_none(e.cause) or e.orig_msg, '.')\n        warn(f'{e}. Retrying{format_field(suffix, None, \" %s\")} ({count}/{retries})...')\n\n        delay = float_or_none(sleep_func(n=count - 1)) if callable(sleep_func) else sleep_func\n        if delay:\n            info(f'Sleeping {delay:.2f} seconds ...')\n            time.sleep(delay)\n\n\n@partial_application\ndef make_archive_id(ie, video_id):\n    ie_key = ie if isinstance(ie, str) else ie.ie_key()\n    return f'{ie_key.lower()} {video_id}'\n\n\n@partial_application\ndef truncate_string(s, left, right=0):","sourceCodeStart":5282,"sourceCodeEnd":5318,"githubUrl":"https://github.com/yt-dlp/yt-dlp/blob/81ecd58b1394793e6da9998cc19fdb45657f1685/yt_dlp/utils/_utils.py#L5282-L5318","documentation":"This is RetryManager.report_retry (yt_dlp/utils/_utils.py): the reporting hub for every yt-dlp retry loop (--retries, --fragment-retries, --extractor-retries). When attempts exceed the retry budget and no error callback was supplied, it re-raises the last exception verbatim ('raise e') - the surfaced message is the underlying network/HTTP/extractor error itself, optionally preceded by '<e>. Retrying (n/N)...' warnings and followed by nothing. With an error callback it reports '<e>. Giving up after N retries' instead of raising.","triggerScenarios":"A failure persists for all attempts: dead/expired fragment URLs (404 from CDN), 429 rate limiting, geo-blocks, DNS/proxy failures, or an extractor error repeated across --extractor-retries. Each retry emits a warning line; the final raise surfaces as DownloadError/ExtractorError wrapping the original exception.","commonSituations":"Expired HLS/DASH manifests where fragments rot between playlist fetch and download; aggressive throttling triggering 429; flaky proxies/VPNs dropping mid-download; resuming large downloads after long pauses.","solutions":["Re-run the command - yt-dlp resumes and often completes on fresh fragment URLs","Raise the budgets and add backoff: --retries 10 --fragment-retries 10 --retry-sleep linear=1:2:5 (or exponential)","Check the underlying cause in the message: 403/geo -> fix headers/geo (update yt-dlp); 429 -> slow down (--limit-rate, --sleep-requests); network -> fix DNS/proxy","Embedders: construct RetryManager with an error_callback so exhaustion is reported to your handler instead of raising"],"exampleFix":"Wrap the retry loop body and re-raise with context: except Exception as e: self.report_error(str(e)); continue the retry loop only while count < retries","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"from yt_dlp import YoutubeDL\nfrom yt_dlp.utils import DownloadError\n\nfor attempt in range(3):  # outer retry around yt-dlp's own retries\n    try:\n        with YoutubeDL(opts) as ydl:\n            ydl.download([url])\n        break\n    except DownloadError as e:\n        logger.warning('attempt %d failed: %s', attempt + 1, e)\nelse:\n    logger.error('gave up on %s', url)","preventionTips":["Set generous budgets upfront: 'retries', 'fragment_retries', 'extractor_retries' in opts or --retries/--fragment-retries on CLI","Add backoff via 'retry_sleep_functions' (or --retry-sleep exponential) instead of default fixed delays","For long downloads, re-run the same command to resume from .part files instead of starting over","Watch for 429s and throttle with --limit-rate / --sleep-requests rather than only raising retries"],"tags":["retry","network","download","resilience"],"backgroundTag":"retries-exhausted","analyzedSha":"81ecd58b1394793e6da9998cc19fdb45657f1685","analyzedAt":"2026-08-22T12:21:25.439Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}