Prettier 3.x: --check fails for file inside repo, passes for byte-identical file outside repo
Prettier 3.9.6. prettier --check on a file outside the current working directory passes, while the byte-identical file inside the project fails:
$ cd /Users/me/work/myrepo
$ git show HEAD:docs/page.md > /tmp/head.md # baseline copy, outside the repo
$ cp /tmp/head.md ./_same.md # identical bytes, inside the repo
$ md5sum /tmp/head.md ./_same.md | awk '{print $1}' | sort -u | wc -l
1
$ npx prettier --check /tmp/head.md
Checking formatting...
All matched files use Prettier code style! # exit 0
$ npx prettier --check ./_same.md
Checking formatting...
[warn] _same.md
[warn] Code style issues found in the above file. # exit 1No config is involved: prettier --find-config-path reports none for either path, there is no config file anywhere up either tree, and the divergence survives --no-config --no-editorconfig.
The damaging part is that the file was never checked, and nothing in the output says so. The success message and exit code are identical for "checked 5 files, all clean" and "checked nothing at all" — there is no file count, and no warning that a target was skipped. -l / --list-different has the same shape: prints nothing and exits 0 both when files are clean and when they were ignored.
This bites an agent or script that establishes a formatting baseline by copying a file to a scratch directory and checking it there — a natural way to answer "was this file already unformatted before I edited it?". The scratch copy always passes, so the baseline reads clean and the conclusion drawn is the opposite of the truth.
The default ignore path is the cause. Prettier relativizes each target against the CWD, so /tmp/head.md becomes ../../../../tmp/head.md, which the project's ignore rules match; the file is dropped before parsing and zero files are checked. Disabling the ignore file exposes the real result:
$ npx prettier --ignore-path /dev/null --check /tmp/head.md
[warn] ../../../../tmp/head.md
[warn] Code style issues found in the above file. # exit 1Changing the CWD so the path no longer relativizes into ignored territory also works:
$ cd /tmp && npx prettier --check /tmp/head.md
[warn] ../../tmp/head.md
[warn] Code style issues found in the above file. # exit 1Rules that follow from this:
- Check files in place. Never copy a file out of the project to test its formatting. If you need a baseline for content that is not on disk (a git blob, a generated file), write it inside the project tree, check it there, then delete it.
- Pass
--ignore-path /dev/nullwhenever the target path is absolute or crosses out of the CWD. It converts a vacuous pass into a real answer. - Treat a check that names no files as inconclusive, not green. If a script depends on the result, make it assert that the expected filenames appear in the output rather than trusting exit 0.
--debug-checknames each file it actually processes. - Match the project's real formatting scope before running
--writeanywhere. A repo whose pre-commit hook formats only one subtree will have unformatted files everywhere else, and a strayprettier --writethere produces a large diff of pure reformatting churn unrelated to your change.