Repository: yt-dlp
Issue: yt-dlp should abort on first "File name too long" error
Labels: enhancement,triage,core:downloader

### DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE

- [X] I understand that I will be **blocked** if I *intentionally* remove or skip any mandatory\* field

### Checklist

- [X] I'm reporting a bug unrelated to a specific site
- [X] I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
- [X] I've checked that all provided URLs are playable in a browser with the same IP and same login details
- [X] I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/yt-dlp/yt-dlp/wiki/FAQ#video-url-contains-an-ampersand--and-im-getting-some-strange-output-1-2839-or-v-is-not-recognized-as-an-internal-or-external-command)
- [X] I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues **including closed ones**. DO NOT post duplicates
- [X] I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)

### Provide a description that is worded well enough to be understood

Still have 2023-12-30 (don't think much will have changed since then). This possibly concerns the twitter extractor only (not certain, and difficult for me to find a possible test case on another site).

I have just started to run into this a few days ago (possibly due to a change on their end. I have a custom output template of "-o '%(title).200s-%(id)s-%(uploader)s.%(ext)s'" (that I likely need to tweak more). Anyway, if yt-dlp encounters a "File name too long" error, it should abort immediately (at least that particular download, but possibly not an entire playlist) rather than continuing to try the remaining fragments. I can't imagine any scenario where a fragment produces a "File name too long" error and a subsequent fragment doesn't. I often change to another terminal (yes, I should probably wait to make certain that the download starts successfully), only to come back much later with everything off of the screen (and even out of the scrollback buffer).

### Provide verbose output that clearly demonstrates the problem

- [X] Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
- [ ] If using API, add `'verbose': True` to `YoutubeDL` params instead
- [X] Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below

### Complete Verbose Output

```shell
[debug] Command-line config: ['--restrict-filenames', '-o', '%(title).200s-%(id)s-%(uploader)s.%(ext)s', '-w', '-v', 'https://twitter.com/PicturesFoIder/status/1741648965970592043']
[debug] Encodings: locale UTF-8, fs utf-8, pref UTF-8, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version stable@2023.12.30 from yt-dlp/yt-dlp [f10589e34]
[debug] Python 3.11.7 (CPython x86_64 64bit) - Linux-6.1.53-with-glibc2.37 (OpenSSL 3.0.12 24 Oct 2023, glibc 2.37)
[debug] exe versions: ffmpeg 4.4.4 (setts), ffprobe 4.4.4
[debug] Optional libraries: certifi-3021.03.16, pycrypto-3.19.1, requests-2.31.0, urllib3-2.1.0
[debug] Proxy map: {}
[debug] Request Handlers: urllib, requests
[debug] Loaded 1798 extractors
[twitter] Extracting URL: https://twitter.com/PicturesFoIder/status/1741648965970592043
[twitter] 1741648965970592043: Downloading guest token
[twitter] 1741648965970592043: Downloading GraphQL JSON
[debug] [twitter] Extracting from video info: 1741648882524954624
[twitter] 1741648965970592043: Downloading m3u8 information
[debug] Sort order given by extractor: res, proto:m3u8, br, size
[debug] Formats sorted by: hasvid, ie_pref, res, proto:m3u8(8), br, size, lang, quality, fps, hdr:12(7), vcodec:vp9.2(10), channels, acodec, asr, vext, aext, hasaud, source, id
[debug] Default format spec: bestvideo*+bestaudio/best
[info] 1741648882524954624: Downloading 1 format(s): hls-1133
[debug] Invoking hlsnative downloader on "https://video.twimg.com/amplify_video/1741648882524954624/pl/avc1/1004x560/mp4a/128000/ilURejxq4Aek6EEZ.m3u8?container=fmp4"
[hlsnative] Downloading m3u8 manifest
[hlsnative] Total fragments: 24
[download] Destination: non_aesthetic_things_-_25_yr_old_pizza_delivery_man_runs_into_burning_house_saves_four_children_who_tell_him_another_might_be_in_the_house._He_goes_back_in_finds_the_girl_jumps_out_a_window_with_her_a-1741648882524954624-non_aesthetic_things.mp4
ERROR: unable to open for writing: [Errno 36] File name too long: 'non_aesthetic_things_-_25_yr_old_pizza_delivery_man_runs_into_burning_house_saves_four_children_who_tell_him_another_might_be_in_the_house._He_goes_back_in_finds_the_girl_jumps_out_a_window_with_her_a-1741648882524954624-non_aesthetic_things.mp4.part-Frag1.part'
Traceback (most recent call last):
  File "/usr/lib/python3.11/site-packages/yt_dlp/utils/_utils.py", line 592, in sanitize_open
    stream = locked_file(filename, open_mode, block=False).__enter__()
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/yt_dlp/utils/_utils.py", line 1585, in __init__
    self.f = os.fdopen(os.open(filename, flags, 0o666), mode, encoding=encoding)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
OSError: [Errno 36] File name too long: 'non_aesthetic_things_-_25_yr_old_pizza_delivery_man_runs_into_burning_house_saves_four_children_who_tell_him_another_might_be_in_the_house._He_goes_back_in_finds_the_girl_jumps_out_a_window_with_her_a-1741648882524954624-non_aesthetic_things.mp4.part-Frag1.part'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.11/site-packages/yt_dlp/downloader/http.py", line 260, in download
    ctx.stream, ctx.tmpfilename = self.sanitize_open(
                                  ^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/yt_dlp/downloader/common.py", line 245, in wrapper
    retry.error_callback(err, 1, 0)
  File "/usr/lib/python3.11/site-packages/yt_dlp/downloader/common.py", line 231, in error_callback
    return RetryManager.report_retry(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/yt_dlp/utils/_utils.py", line 5054, in report_retry
    raise e
  File "/usr/lib/python3.11/site-packages/yt_dlp/downloader/common.py", line 240, in wrapper
    return func(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/yt_dlp/downloader/common.py", line 251, in sanitize_open
    f, filename = sanitize_open(filename, open_mode)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/yt_dlp/utils/_utils.py", line 594, in sanitize_open
    stream = open(filename, open_mode)
             ^^^^^^^^^^^^^^^^^^^^^^^^^
OSError: [Errno 36] File name too long: 'non_aesthetic_things_-_25_yr_old_pizza_delivery_man_runs_into_burning_house_saves_four_children_who_tell_him_another_might_be_in_the_house._He_goes_back_in_finds_the_girl_jumps_out_a_window_with_her_a-1741648882524954624-non_aesthetic_things.mp4.part-Frag1.part'

[download] fragment not found; Skipping fragment 1 ...

[...]

ERROR: unable to open for writing: [Errno 36] File name too long: 'non_aesthetic_things_-_25_yr_old_pizza_delivery_man_runs_into_burning_house_saves_four_children_who_tell_him_another_might_be_in_the_house._He_goes_back_in_finds_the_girl_jumps_out_a_window_with_her_a-1741648882524954624-non_aesthetic_things.mp4.part-Frag25.part'
Traceback (most recent call last):
  File "/usr/lib/python3.11/site-packages/yt_dlp/utils/_utils.py", line 592, in sanitize_open
    stream = locked_file(filename, open_mode, block=False).__enter__()
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/yt_dlp/utils/_utils.py", line 1585, in __init__
    self.f = os.fdopen(os.open(filename, flags, 0o666), mode, encoding=encoding)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
OSError: [Errno 36] File name too long: 'non_aesthetic_things_-_25_yr_old_pizza_delivery_man_runs_into_burning_house_saves_four_children_who_tell_him_another_might_be_in_the_house._He_goes_back_in_finds_the_girl_jumps_out_a_window_with_her_a-1741648882524954624-non_aesthetic_things.mp4.part-Frag25.part'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.11/site-packages/yt_dlp/downloader/http.py", line 260, in download
    ctx.stream, ctx.tmpfilename = self.sanitize_open(
                                  ^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/yt_dlp/downloader/common.py", line 245, in wrapper
    retry.error_callback(err, 1, 0)
  File "/usr/lib/python3.11/site-packages/yt_dlp/downloader/common.py", line 231, in error_callback
    return RetryManager.report_retry(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/yt_dlp/utils/_utils.py", line 5054, in report_retry
    raise e
  File "/usr/lib/python3.11/site-packages/yt_dlp/downloader/common.py", line 240, in wrapper
    return func(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/yt_dlp/downloader/common.py", line 251, in sanitize_open
    f, filename = sanitize_open(filename, open_mode)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/yt_dlp/utils/_utils.py", line 594, in sanitize_open
    stream = open(filename, open_mode)
             ^^^^^^^^^^^^^^^^^^^^^^^^^
OSError: [Errno 36] File name too long: 'non_aesthetic_things_-_25_yr_old_pizza_delivery_man_runs_into_burning_house_saves_four_children_who_tell_him_another_might_be_in_the_house._He_goes_back_in_finds_the_girl_jumps_out_a_window_with_her_a-1741648882524954624-non_aesthetic_things.mp4.part-Frag25.part'

[download] fragment not found; Skipping fragment 25 ...
ERROR: The downloaded file is empty
  File "/usr/lib/python-exec/python3.11/yt-dlp", line 8, in <module>
    sys.exit(main())
  File "/usr/lib/python3.11/site-packages/yt_dlp/__init__.py", line 1009, in main
    _exit(*variadic(_real_main(argv)))
  File "/usr/lib/python3.11/site-packages/yt_dlp/__init__.py", line 999, in _real_main
    return ydl.download(all_urls)
  File "/usr/lib/python3.11/site-packages/yt_dlp/YoutubeDL.py", line 3541, in download
    self.__download_wrapper(self.extract_info)(
  File "/usr/lib/python3.11/site-packages/yt_dlp/YoutubeDL.py", line 3516, in wrapper
    res = func(*args, **kwargs)
  File "/usr/lib/python3.11/site-packages/yt_dlp/YoutubeDL.py", line 1576, in extract_info
    return self.__extract_info(url, self.get_info_extractor(key), download, extra_info, process)
  File "/usr/lib/python3.11/site-packages/yt_dlp/YoutubeDL.py", line 1587, in wrapper
    return func(self, *args, **kwargs)
  File "/usr/lib/python3.11/site-packages/yt_dlp/YoutubeDL.py", line 1743, in __extract_info
    return self.process_ie_result(ie_result, download, extra_info)
  File "/usr/lib/python3.11/site-packages/yt_dlp/YoutubeDL.py", line 1802, in process_ie_result
    ie_result = self.process_video_result(ie_result, download=download)
  File "/usr/lib/python3.11/site-packages/yt_dlp/YoutubeDL.py", line 2952, in process_video_result
    self.process_info(new_info)
  File "/usr/lib/python3.11/site-packages/yt_dlp/YoutubeDL.py", line 3418, in process_info
    success, real_download = self.dl(temp_filename, info_dict)
  File "/usr/lib/python3.11/site-packages/yt_dlp/YoutubeDL.py", line 3139, in dl
    return fd.download(name, new_info, subtitle)
  File "/usr/lib/python3.11/site-packages/yt_dlp/downloader/common.py", line 455, in download
    ret = self.real_download(filename, info_dict)
  File "/usr/lib/python3.11/site-packages/yt_dlp/downloader/hls.py", line 375, in real_download
    return self.download_and_append_fragments(ctx, fragments, info_dict)
  File "/usr/lib/python3.11/site-packages/yt_dlp/downloader/fragment.py", line 527, in download_and_append_fragments
    return self._finish_frag_download(ctx, info_dict)
  File "/usr/lib/python3.11/site-packages/yt_dlp/downloader/fragment.py", line 301, in _finish_frag_download
    self.report_error('The downloaded file is empty')
  File "/usr/lib/python3.11/site-packages/yt_dlp/YoutubeDL.py", line 1054, in report_error
    self.trouble(f'{self._format_err("ERROR:", self.Styles.ERROR)} {message}', *args, **kwargs)
  File "/usr/lib/python3.11/site-packages/yt_dlp/YoutubeDL.py", line 982, in trouble
    tb_data = traceback.format_list(traceback.extract_stack())
```