tobywf: Please let me know if there's anything you need from me to get this merged (did I forget a label or an assignee?). Would be nice to get it in before the refactor happens :)
diff --git a/black.py b/black.py
index d9348a3..26a2915 100644
--- a/black.py
+++ b/black.py
@@ -394,7 +394,7 @@ def target_version_option_callback(
 @click.option(
     "--config",
     type=click.Path(
-        exists=False, file_okay=True, dir_okay=False, readable=True, allow_dash=False
+        exists=True, file_okay=True, dir_okay=False, readable=True, allow_dash=False
     ),
     is_eager=True,
     callback=read_pyproject_toml,

Black --check returns 1 when invalid config file is specified
**Describe the bug**

`--check` returns `1` when invalid `--config` is specified, not some higher error code as implied. This can make debugging issues tricky for CI integrations relying on return codes. I wouldn't go so far as to call it a bug, but it was a bit unexpected to me.

(It also happens without `--check`.)

**To Reproduce**

```console
$ printf "def a():\n    pass\n" | black - --check; echo "return: $?"
def a():
    pass
All done! ✨ 🍰 ✨
1 file left unchanged.
return: 0
$ printf "def a():\n    pass\n" | black - --check --config "foo"; echo "return: $?"
Error: Could not open file foo: Error reading configuration file: [Errno 2] No such file or directory: 'foo'
return: 1
```

**Expected behavior**

`--check` says:

> Don't write the files back, just return the status.  Return code 0 means nothing would change.  Return code 1 means some files would be reformatted.  Return code 123 means there was an internal error.

So I would expect this case to return an error code other than `1`.

**Environment (please complete the following information):**

- Version: `19.10b0`, `master` (both tested)
- OS and Python version: macOS 10.15.3 with Python 3.7.7; and Ubuntu 18.04.4 with Python 3.6.9

**Does this bug also happen on master?**

Yes (tested via cloning and `pipenv shell`)

**Additional context**

This can be very awkward to debug in a CI environment if you rely on return codes only.

diff --git a/tests/test_black.py b/tests/test_black.py
index acbaade..7a4a3bb 100644
--- a/tests/test_black.py
+++ b/tests/test_black.py
@@ -1645,6 +1645,16 @@ def test_blackd_main(self) -> None:
                 raise result.exception
             self.assertEqual(result.exit_code, 0)
 
+    def test_invalid_config_return_code(self) -> None:
+        tmp_file = Path(black.dump_to_file())
+        try:
+            tmp_config = Path(black.dump_to_file())
+            tmp_config.unlink()
+            args = ["--config", str(tmp_config), str(tmp_file)]
+            self.invokeBlack(args, exit_code=2, ignore_config=False)
+        finally:
+            tmp_file.unlink()
+
 
 class BlackDTestCase(AioHTTPTestCase):
     async def get_application(self) -> web.Application:

pip install -e .[d]
parse_log_pytest
requirements.txt
pytest
apt-get update apt-get install -y gcc
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
aiohappyeyeballs==2.6.1
aiohttp==3.11.14
aiohttp-cors==0.8.0
aiosignal==1.3.2
appdirs==1.4.4
async-timeout==5.0.1
attrs==25.3.0
-e git+https://github.com/psf/black.git@8126b4f6a9342290de4655e6a8a78cd288ce7daa#egg=black
click==8.1.8
exceptiongroup==1.2.2
frozenlist==1.5.0
idna==3.10
iniconfig==2.1.0
multidict==6.2.0
mypy-extensions==1.0.0
packaging==24.2
pathspec==0.12.1
pluggy==1.5.0
propcache==0.3.1
pytest==8.3.5
regex==2024.11.6
toml==0.10.2
tomli==2.2.1
typed-ast==1.5.5
typing_extensions==4.13.0
yarl==1.18.3

name: black
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - aiohappyeyeballs==2.6.1
      - aiohttp==3.11.14
      - aiohttp-cors==0.8.0
      - aiosignal==1.3.2
      - appdirs==1.4.4
      - async-timeout==5.0.1
      - attrs==25.3.0
      - black==19.10b1.dev51+g8126b4f
      - click==8.1.8
      - exceptiongroup==1.2.2
      - frozenlist==1.5.0
      - idna==3.10
      - iniconfig==2.1.0
      - multidict==6.2.0
      - mypy-extensions==1.0.0
      - packaging==24.2
      - pathspec==0.12.1
      - pluggy==1.5.0
      - propcache==0.3.1
      - pytest==8.3.5
      - regex==2024.11.6
      - toml==0.10.2
      - tomli==2.2.1
      - typed-ast==1.5.5
      - typing-extensions==4.13.0
      - yarl==1.18.3
prefix: /opt/conda/envs/black

tests/test_black.py::BlackTestCase::test_invalid_config_return_code
tests/test_black.py::BlackTestCase::test_expression tests/test_black.py::BlackTestCase::test_expression_diff tests/test_black.py::BlackTestCase::test_expression_ff tests/test_black.py::BlackTestCase::test_shhh_click
tests/test_black.py::BlackTestCase::test_assertFormatEqual 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_beginning_backslash tests/test_black.py::BlackTestCase::test_black tests/test_black.py::BlackTestCase::test_blackd_main tests/test_black.py::BlackTestCase::test_bracket_match tests/test_black.py::BlackTestCase::test_broken_symlink tests/test_black.py::BlackTestCase::test_cache_broken_file tests/test_black.py::BlackTestCase::test_cache_multiple_files tests/test_black.py::BlackTestCase::test_cache_single_file_already_cached tests/test_black.py::BlackTestCase::test_cantfit tests/test_black.py::BlackTestCase::test_check_diff_use_together tests/test_black.py::BlackTestCase::test_collections tests/test_black.py::BlackTestCase::test_comment_after_escaped_newline tests/test_black.py::BlackTestCase::test_comments tests/test_black.py::BlackTestCase::test_comments2 tests/test_black.py::BlackTestCase::test_comments3 tests/test_black.py::BlackTestCase::test_comments4 tests/test_black.py::BlackTestCase::test_comments5 tests/test_black.py::BlackTestCase::test_comments6 tests/test_black.py::BlackTestCase::test_comments7 tests/test_black.py::BlackTestCase::test_composition tests/test_black.py::BlackTestCase::test_conv tests/test_black.py::BlackTestCase::test_debug_visitor tests/test_black.py::BlackTestCase::test_detect_pos_only_arguments tests/test_black.py::BlackTestCase::test_driver tests/test_black.py::BlackTestCase::test_empty tests/test_black.py::BlackTestCase::test_empty_exclude tests/test_black.py::BlackTestCase::test_empty_ff tests/test_black.py::BlackTestCase::test_empty_include tests/test_black.py::BlackTestCase::test_empty_lines tests/test_black.py::BlackTestCase::test_endmarker tests/test_black.py::BlackTestCase::test_failed_formatting_does_not_get_cached tests/test_black.py::BlackTestCase::test_filter_cached tests/test_black.py::BlackTestCase::test_fmtonoff tests/test_black.py::BlackTestCase::test_fmtonoff2 tests/test_black.py::BlackTestCase::test_fmtonoff3 tests/test_black.py::BlackTestCase::test_format_file_contents tests/test_black.py::BlackTestCase::test_fstring tests/test_black.py::BlackTestCase::test_function tests/test_black.py::BlackTestCase::test_function2 tests/test_black.py::BlackTestCase::test_function_trailing_comma tests/test_black.py::BlackTestCase::test_get_features_used tests/test_black.py::BlackTestCase::test_get_future_imports tests/test_black.py::BlackTestCase::test_gitignore_exclude tests/test_black.py::BlackTestCase::test_grammar tests/test_black.py::BlackTestCase::test_import_spacing tests/test_black.py::BlackTestCase::test_include_exclude tests/test_black.py::BlackTestCase::test_invalid_include_exclude tests/test_black.py::BlackTestCase::test_lib2to3_parse tests/test_black.py::BlackTestCase::test_literals 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_new_line_between_class_and_code tests/test_black.py::BlackTestCase::test_no_cache_when_stdin tests/test_black.py::BlackTestCase::test_no_cache_when_writeback_diff tests/test_black.py::BlackTestCase::test_no_files tests/test_black.py::BlackTestCase::test_numeric_literals tests/test_black.py::BlackTestCase::test_numeric_literals_ignoring_underscores tests/test_black.py::BlackTestCase::test_numeric_literals_py2 tests/test_black.py::BlackTestCase::test_parse tests/test_black.py::BlackTestCase::test_pep_570 tests/test_black.py::BlackTestCase::test_pep_572 tests/test_black.py::BlackTestCase::test_pep_572_version_detection tests/test_black.py::BlackTestCase::test_pgen 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_preserves_line_endings tests/test_black.py::BlackTestCase::test_preserves_line_endings_via_stdin tests/test_black.py::BlackTestCase::test_pygram tests/test_black.py::BlackTestCase::test_python2 tests/test_black.py::BlackTestCase::test_python2_print_function tests/test_black.py::BlackTestCase::test_python2_unicode_literals tests/test_black.py::BlackTestCase::test_python37 tests/test_black.py::BlackTestCase::test_python38 tests/test_black.py::BlackTestCase::test_pytree tests/test_black.py::BlackTestCase::test_read_cache_line_lengths tests/test_black.py::BlackTestCase::test_read_cache_no_cachefile tests/test_black.py::BlackTestCase::test_remove_empty_parentheses_after_class tests/test_black.py::BlackTestCase::test_remove_parens 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_root_logger_not_used_directly tests/test_black.py::BlackTestCase::test_self tests/test_black.py::BlackTestCase::test_setup 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_slices tests/test_black.py::BlackTestCase::test_string_prefixes tests/test_black.py::BlackTestCase::test_string_quotes tests/test_black.py::BlackTestCase::test_stub tests/test_black.py::BlackTestCase::test_symlink_out_of_root_directory tests/test_black.py::BlackTestCase::test_tab_comment_indentation tests/test_black.py::BlackTestCase::test_token tests/test_black.py::BlackTestCase::test_tokenize tests/test_black.py::BlackTestCase::test_tricky_unicode_symbols tests/test_black.py::BlackTestCase::test_tuple_assign tests/test_black.py::BlackTestCase::test_write_cache_creates_directory_if_needed tests/test_black.py::BlackTestCase::test_write_cache_read_cache tests/test_black.py::BlackTestCase::test_write_cache_write_fail tests/test_black.py::BlackDTestCase::test_blackd_diff tests/test_black.py::BlackDTestCase::test_blackd_invalid_line_length tests/test_black.py::BlackDTestCase::test_blackd_invalid_python_variant tests/test_black.py::BlackDTestCase::test_blackd_line_length tests/test_black.py::BlackDTestCase::test_blackd_pyi tests/test_black.py::BlackDTestCase::test_blackd_python_variant tests/test_black.py::BlackDTestCase::test_blackd_request_needs_formatting tests/test_black.py::BlackDTestCase::test_blackd_request_no_change tests/test_black.py::BlackDTestCase::test_blackd_request_syntax_error tests/test_black.py::BlackDTestCase::test_blackd_response_black_version_header tests/test_black.py::BlackDTestCase::test_blackd_supported_version tests/test_black.py::BlackDTestCase::test_blackd_unsupported_version
black.py
black.py