diff --git a/CHANGES.md b/CHANGES.md
index 9a9be4b..e4240ea 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -18,6 +18,9 @@
 
 <!-- Changes to how Black can be configured -->
 
+- Shorten the length of the name of the cache file to fix crashes on file systems that
+  do not support long paths (#4176)
+
 ### Packaging
 
 <!-- Changes to how Black is packaged, such as dependency requirements -->
diff --git a/src/black/cache.py b/src/black/cache.py
index cfdbc21..35bddb5 100644
--- a/src/black/cache.py
+++ b/src/black/cache.py
@@ -13,6 +13,7 @@ from platformdirs import user_cache_dir
 
 from _black_version import version as __version__
 from black.mode import Mode
+from black.output import err
 
 if sys.version_info >= (3, 11):
     from typing import Self
@@ -64,7 +65,13 @@ class Cache:
         resolve the issue.
         """
         cache_file = get_cache_file(mode)
-        if not cache_file.exists():
+        try:
+            exists = cache_file.exists()
+        except OSError as e:
+            # Likely file too long; see #4172 and #4174
+            err(f"Unable to read cache file {cache_file} due to {e}")
+            return cls(mode, cache_file)
+        if not exists:
             return cls(mode, cache_file)
 
         with cache_file.open("rb") as fobj:
diff --git a/src/black/mode.py b/src/black/mode.py
index 68919fb..128d2b9 100644
--- a/src/black/mode.py
+++ b/src/black/mode.py
@@ -192,6 +192,9 @@ class Deprecated(UserWarning):
     """Visible deprecation warning."""
 
 
+_MAX_CACHE_KEY_PART_LENGTH: Final = 32
+
+
 @dataclass
 class Mode:
     target_versions: Set[TargetVersion] = field(default_factory=set)
@@ -228,6 +231,19 @@ class Mode:
             )
         else:
             version_str = "-"
+        if len(version_str) > _MAX_CACHE_KEY_PART_LENGTH:
+            version_str = sha256(version_str.encode()).hexdigest()[
+                :_MAX_CACHE_KEY_PART_LENGTH
+            ]
+        features_and_magics = (
+            ",".join(sorted(f.name for f in self.enabled_features))
+            + "@"
+            + ",".join(sorted(self.python_cell_magics))
+        )
+        if len(features_and_magics) > _MAX_CACHE_KEY_PART_LENGTH:
+            features_and_magics = sha256(features_and_magics.encode()).hexdigest()[
+                :_MAX_CACHE_KEY_PART_LENGTH
+            ]
         parts = [
             version_str,
             str(self.line_length),
@@ -236,10 +252,7 @@ class Mode:
             str(int(self.is_ipynb)),
             str(int(self.skip_source_first_line)),
             str(int(self.magic_trailing_comma)),
-            sha256(
-                (",".join(sorted(f.name for f in self.enabled_features))).encode()
-            ).hexdigest(),
             str(int(self.preview)),
-            sha256((",".join(sorted(self.python_cell_magics))).encode()).hexdigest(),
+            features_and_magics,
         ]
         return ".".join(parts)

diff --git a/tests/test_black.py b/tests/test_black.py
index 6dbe25a..123ea0b 100644
--- a/tests/test_black.py
+++ b/tests/test_black.py
@@ -44,6 +44,7 @@ from black import Feature, TargetVersion
 from black import re_compile_maybe_verbose as compile_pattern
 from black.cache import FileData, get_cache_dir, get_cache_file
 from black.debug import DebugVisitor
+from black.mode import Mode, Preview
 from black.output import color_diff, diff
 from black.report import Report
 
@@ -2065,6 +2066,30 @@ class TestCaching:
         monkeypatch.setenv("BLACK_CACHE_DIR", str(workspace2))
         assert get_cache_dir().parent == workspace2
 
+    def test_cache_file_length(self) -> None:
+        cases = [
+            DEFAULT_MODE,
+            # all of the target versions
+            Mode(target_versions=set(TargetVersion)),
+            # all of the features
+            Mode(enabled_features=set(Preview)),
+            # all of the magics
+            Mode(python_cell_magics={f"magic{i}" for i in range(500)}),
+            # all of the things
+            Mode(
+                target_versions=set(TargetVersion),
+                enabled_features=set(Preview),
+                python_cell_magics={f"magic{i}" for i in range(500)},
+            ),
+        ]
+        for case in cases:
+            cache_file = get_cache_file(case)
+            # Some common file systems enforce a maximum path length
+            # of 143 (issue #4174). We can't do anything if the directory
+            # path is too long, but ensure the name of the cache file itself
+            # doesn't get too crazy.
+            assert len(cache_file.name) <= 96
+
     def test_cache_broken_file(self) -> None:
         mode = DEFAULT_MODE
         with cache_dir() as workspace:

cache uses filenames that might be too long on some systems
**Describe the bug**

Running black 24.1.0 (without --check) can produce filenames in user's cache folder that are too long for some filesystems e.g. eCryptFS only allows filenames that are 143 chars long

The resulting error is:

```
Traceback (most recent call last):
  File "/home/hottwaj/.pyenv/versions/3.10.2/envs/test-venv/bin/black", line 8, in <module>
    sys.exit(patched_main())
  File "src/black/__init__.py", line 1593, in patched_main
  File "/home/hottwaj/.pyenv/versions/3.10.2/envs/test-venv/lib/python3.10/site-packages/click/core.py", line 1130, in __call__
    return self.main(*args, **kwargs)
  File "/home/hottwaj/.pyenv/versions/3.10.2/envs/test-venv/lib/python3.10/site-packages/click/core.py", line 1055, in main
    rv = self.invoke(ctx)
  File "/home/hottwaj/.pyenv/versions/3.10.2/envs/test-venv/lib/python3.10/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/hottwaj/.pyenv/versions/3.10.2/envs/test-venv/lib/python3.10/site-packages/click/core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "/home/hottwaj/.pyenv/versions/3.10.2/envs/test-venv/lib/python3.10/site-packages/click/decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "src/black/__init__.py", line 703, in main
  File "/home/hottwaj/.pyenv/versions/3.10.2/envs/test-venv/lib/python3.10/site-packages/black/concurrency.py", line 101, in reformat_many
    loop.run_until_complete(
  File "/home/hottwaj/.pyenv/versions/3.10.2/lib/python3.10/asyncio/base_events.py", line 641, in run_until_complete
    return future.result()
  File "/home/hottwaj/.pyenv/versions/3.10.2/envs/test-venv/lib/python3.10/site-packages/black/concurrency.py", line 137, in schedule_formatting
    cache = Cache.read(mode)
  File "src/black/cache.py", line 67, in read
  File "/home/hottwaj/.pyenv/versions/3.10.2/lib/python3.10/pathlib.py", line 1288, in exists
    self.stat()
  File "/home/hottwaj/.pyenv/versions/3.10.2/lib/python3.10/pathlib.py", line 1095, in stat
    return self._accessor.stat(self, follow_symlinks=follow_symlinks)
OSError: [Errno 36] File name too long: '/home/hottwaj/.cache/black/24.1.0/cache.-.130.0.0.0.0.1.e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.0.e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.pickle'
```


**Environment**

<!-- Please complete the following information: -->

- Black's version: 24.1.0
- OS and Python version: Linux, Python 3.10.2, home folder encrypted with eCryptFS


tests/test_black.py::TestCaching::test_cache_file_length
tests/test_black.py::BlackTestCase::test_assertFormatEqual_print_full_tree tests/test_black.py::BlackTestCase::test_assertFormatEqual_print_tree_diff tests/test_black.py::BlackTestCase::test_assert_equivalent_different_asts tests/test_black.py::BlackTestCase::test_async_as_identifier tests/test_black.py::BlackTestCase::test_bpo_2142_workaround tests/test_black.py::BlackTestCase::test_bpo_33660_workaround tests/test_black.py::BlackTestCase::test_broken_symlink tests/test_black.py::BlackTestCase::test_check_diff_use_together tests/test_black.py::BlackTestCase::test_cli_unstable tests/test_black.py::BlackTestCase::test_code_option tests/test_black.py::BlackTestCase::test_code_option_changed tests/test_black.py::BlackTestCase::test_code_option_check tests/test_black.py::BlackTestCase::test_code_option_check_changed tests/test_black.py::BlackTestCase::test_code_option_color_diff tests/test_black.py::BlackTestCase::test_code_option_config tests/test_black.py::BlackTestCase::test_code_option_diff tests/test_black.py::BlackTestCase::test_code_option_fast tests/test_black.py::BlackTestCase::test_code_option_parent_config tests/test_black.py::BlackTestCase::test_code_option_safe tests/test_black.py::BlackTestCase::test_debug_visitor tests/test_black.py::BlackTestCase::test_detect_debug_f_strings tests/test_black.py::BlackTestCase::test_detect_pos_only_arguments tests/test_black.py::BlackTestCase::test_empty_ff tests/test_black.py::BlackTestCase::test_endmarker tests/test_black.py::BlackTestCase::test_equivalency_ast_parse_failure_includes_error tests/test_black.py::BlackTestCase::test_expression_diff tests/test_black.py::BlackTestCase::test_expression_diff_with_color tests/test_black.py::BlackTestCase::test_expression_ff tests/test_black.py::BlackTestCase::test_false_positive_symlink_output_issue_3384 tests/test_black.py::BlackTestCase::test_find_project_root tests/test_black.py::BlackTestCase::test_find_pyproject_toml tests/test_black.py::BlackTestCase::test_find_user_pyproject_toml_linux tests/test_black.py::BlackTestCase::test_find_user_pyproject_toml_windows tests/test_black.py::BlackTestCase::test_for_handled_unexpected_eof_error tests/test_black.py::BlackTestCase::test_format_file_contents tests/test_black.py::BlackTestCase::test_get_features_used tests/test_black.py::BlackTestCase::test_get_features_used_decorator tests/test_black.py::BlackTestCase::test_get_features_used_for_future_flags tests/test_black.py::BlackTestCase::test_get_future_imports tests/test_black.py::BlackTestCase::test_infer_target_version tests/test_black.py::BlackTestCase::test_invalid_cli_regex tests/test_black.py::BlackTestCase::test_invalid_config_return_code tests/test_black.py::BlackTestCase::test_lib2to3_parse tests/test_black.py::BlackTestCase::test_line_ranges_in_pyproject_toml tests/test_black.py::BlackTestCase::test_line_ranges_with_code_option tests/test_black.py::BlackTestCase::test_line_ranges_with_ipynb tests/test_black.py::BlackTestCase::test_line_ranges_with_multiple_sources tests/test_black.py::BlackTestCase::test_line_ranges_with_source tests/test_black.py::BlackTestCase::test_line_ranges_with_stdin tests/test_black.py::BlackTestCase::test_multi_file_force_py36 tests/test_black.py::BlackTestCase::test_multi_file_force_pyi tests/test_black.py::BlackTestCase::test_newline_comment_interaction tests/test_black.py::BlackTestCase::test_no_src_fails tests/test_black.py::BlackTestCase::test_normalize_line_endings tests/test_black.py::BlackTestCase::test_normalize_path_ignore_windows_junctions_outside_of_root tests/test_black.py::BlackTestCase::test_one_empty_line tests/test_black.py::BlackTestCase::test_one_empty_line_ff tests/test_black.py::BlackTestCase::test_parse_pyproject_toml tests/test_black.py::BlackTestCase::test_parse_pyproject_toml_project_metadata tests/test_black.py::BlackTestCase::test_pep_572_version_detection tests/test_black.py::BlackTestCase::test_pep_695_version_detection tests/test_black.py::BlackTestCase::test_pipe_force_py36 tests/test_black.py::BlackTestCase::test_pipe_force_pyi tests/test_black.py::BlackTestCase::test_piping tests/test_black.py::BlackTestCase::test_piping_diff tests/test_black.py::BlackTestCase::test_piping_diff_with_color tests/test_black.py::BlackTestCase::test_preserves_line_endings tests/test_black.py::BlackTestCase::test_preserves_line_endings_via_stdin tests/test_black.py::BlackTestCase::test_python37 tests/test_black.py::BlackTestCase::test_read_pyproject_toml tests/test_black.py::BlackTestCase::test_read_pyproject_toml_from_stdin tests/test_black.py::BlackTestCase::test_reformat_one_with_stdin tests/test_black.py::BlackTestCase::test_reformat_one_with_stdin_and_existing_path tests/test_black.py::BlackTestCase::test_reformat_one_with_stdin_empty tests/test_black.py::BlackTestCase::test_reformat_one_with_stdin_filename tests/test_black.py::BlackTestCase::test_reformat_one_with_stdin_filename_ipynb tests/test_black.py::BlackTestCase::test_reformat_one_with_stdin_filename_pyi tests/test_black.py::BlackTestCase::test_report_normal tests/test_black.py::BlackTestCase::test_report_quiet tests/test_black.py::BlackTestCase::test_report_verbose tests/test_black.py::BlackTestCase::test_required_version_does_not_match_on_minor_version tests/test_black.py::BlackTestCase::test_required_version_does_not_match_version tests/test_black.py::BlackTestCase::test_required_version_matches_partial_version tests/test_black.py::BlackTestCase::test_required_version_matches_version tests/test_black.py::BlackTestCase::test_root_logger_not_used_directly tests/test_black.py::BlackTestCase::test_single_file_force_py36 tests/test_black.py::BlackTestCase::test_single_file_force_pyi tests/test_black.py::BlackTestCase::test_skip_magic_trailing_comma tests/test_black.py::BlackTestCase::test_skip_source_first_line tests/test_black.py::BlackTestCase::test_skip_source_first_line_when_mixing_newlines tests/test_black.py::BlackTestCase::test_spellcheck_pyproject_toml tests/test_black.py::BlackTestCase::test_src_and_code_fails tests/test_black.py::BlackTestCase::test_string_quotes tests/test_black.py::BlackTestCase::test_tab_comment_indentation tests/test_black.py::BlackTestCase::test_works_in_mono_process_only_environment tests/test_black.py::TestCaching::test_get_cache_dir tests/test_black.py::TestCaching::test_cache_broken_file tests/test_black.py::TestCaching::test_cache_single_file_already_cached tests/test_black.py::TestCaching::test_cache_multiple_files tests/test_black.py::TestCaching::test_no_cache_when_writeback_diff[no-color] tests/test_black.py::TestCaching::test_no_cache_when_writeback_diff[with-color] tests/test_black.py::TestCaching::test_output_locking_when_writeback_diff[no-color] tests/test_black.py::TestCaching::test_output_locking_when_writeback_diff[with-color] tests/test_black.py::TestCaching::test_no_cache_when_stdin tests/test_black.py::TestCaching::test_read_cache_no_cachefile tests/test_black.py::TestCaching::test_write_cache_read_cache tests/test_black.py::TestCaching::test_filter_cached tests/test_black.py::TestCaching::test_filter_cached_hash tests/test_black.py::TestCaching::test_write_cache_creates_directory_if_needed tests/test_black.py::TestCaching::test_failed_formatting_does_not_get_cached tests/test_black.py::TestCaching::test_write_cache_write_fail tests/test_black.py::TestCaching::test_read_cache_line_lengths tests/test_black.py::TestFileCollection::test_include_exclude tests/test_black.py::TestFileCollection::test_gitignore_used_as_default tests/test_black.py::TestFileCollection::test_gitignore_used_on_multiple_sources tests/test_black.py::TestFileCollection::test_exclude_for_issue_1572 tests/test_black.py::TestFileCollection::test_gitignore_exclude tests/test_black.py::TestFileCollection::test_nested_gitignore tests/test_black.py::TestFileCollection::test_nested_gitignore_directly_in_source_directory tests/test_black.py::TestFileCollection::test_invalid_gitignore tests/test_black.py::TestFileCollection::test_invalid_nested_gitignore tests/test_black.py::TestFileCollection::test_gitignore_that_ignores_subfolders tests/test_black.py::TestFileCollection::test_empty_include tests/test_black.py::TestFileCollection::test_include_absolute_path tests/test_black.py::TestFileCollection::test_exclude_absolute_path tests/test_black.py::TestFileCollection::test_extend_exclude tests/test_black.py::TestFileCollection::test_symlinks tests/test_black.py::TestFileCollection::test_get_sources_with_stdin_symlink_outside_root tests/test_black.py::TestFileCollection::test_get_sources_with_stdin tests/test_black.py::TestFileCollection::test_get_sources_with_stdin_filename tests/test_black.py::TestFileCollection::test_get_sources_with_stdin_filename_and_exclude tests/test_black.py::TestFileCollection::test_get_sources_with_stdin_filename_and_extend_exclude tests/test_black.py::TestFileCollection::test_get_sources_with_stdin_filename_and_force_exclude tests/test_black.py::TestFileCollection::test_get_sources_with_stdin_filename_and_force_exclude_and_symlink tests/test_black.py::TestDeFactoAPI::test_format_str tests/test_black.py::TestDeFactoAPI::test_format_file_contents