Summary
.pre-commit-config.yaml does not validate, so pre-commit run executes zero hooks —
it aborts before running any of them. Nothing in CI runs the hooks or any formatter either,
so Prettier is currently unenforced end to end and this has gone unnoticed.
This is not a stale local install: pre-commit 4.3.0 (current) rejects the committed config.
Reproduce
$ pre-commit run --all-files
An error has occurred: InvalidConfigError:
==> File .pre-commit-config.yaml
==> At Config()
==> At key: repos
==> At Repository(repo='https://github.com/pre-commit/mirrors-prettier')
==> At key: hooks
==> At Hook(id='prettier')
==> At key: types_or
==> At index 1
=====> Type tag 'typescript' is not recognized. Try upgrading identify and pre-commit?
$ pre-commit validate-config .pre-commit-config.yaml; echo "exit=$?"
exit=1
Note the failure blocks all hooks, including shellcheck, gitleaks, check-yaml and
trailing-whitespace — not just Prettier. A contributor who runs pre-commit install gets a
commit-time abort, and one who does not gets no checks at all.
Root cause
identify has no typescript tag. The tags for TypeScript sources are ts and tsx:
$ python3 -c "from identify.identify import ALL_TAGS; import identify.extensions as e; \
print('typescript' in ALL_TAGS, 'ts' in ALL_TAGS, e.EXTENSIONS.get('ts'), e.EXTENSIONS.get('tsx'))"
False True {'text', 'ts'} {'text', 'tsx'}
The hint in pre-commit's error message ("Try upgrading identify and pre-commit?") is
misleading here — upgrading does not help, because the tag never existed under that name.
.ts files were therefore never matched by this hook even when the config did load.
Verified fix
One line, in .pre-commit-config.yaml:
- id: prettier
- types_or: [javascript, typescript, json, yaml, markdown]
+ types_or: [javascript, ts, tsx, json, yaml, markdown]
$ pre-commit validate-config /tmp/fixed-precommit.yaml; echo "exit=$?"
exit=0
(tsx is included deliberately — it is a separate identify tag, so ts alone would leave
.tsx files unformatted, which is the same silent gap in a new place.)
Two related gaps worth fixing in the same pass
1. make fmt is broken independently of the hook. Prettier is not declared in any
package.json in the workspace, so:
$ pnpm exec prettier --version
ERR_PNPM_RECURSIVE_EXEC_NO_PACKAGE No package found in this workspace
.prettierrc and .prettierignore are both committed, so formatting is clearly intended.
Note this is a separate failure from the hook: mirrors-prettier installs its own Prettier
in a pre-commit-managed environment, so fixing the tag makes the hook work while
make fmt stays broken. Fix needs Prettier added as a root devDependency (pinned to match
whatever version the hook uses, so the two cannot disagree about formatting).
2. Nothing in CI runs the hooks, which is why both went unnoticed. Current jobs:
| Workflow |
Jobs |
ci.yml |
check (pnpm test), proto (buf lint/generate, go build+test) |
security-scans.yml |
shellcheck (over deploy/ only), hadolint (root Dockerfile), CodeQL, Trivy, dependency-review |
scorecard.yml |
OSSF scorecard |
No job runs pre-commit, make lint, or Prettier. So a config that runs zero hooks is
indistinguishable from a green build. Adding a lint job that runs
pre-commit run --all-files would have caught this on the commit that introduced it, and
would keep the local and CI story identical.
Acceptance
Optional follow-up
pre-commit/mirrors-prettier is archived upstream and pinned here to a pre-release
(v4.0.0-alpha.8). Once the above is green it may be worth moving to a maintained hook, or a
repo: local hook invoking the repo's own pinned Prettier — which would also guarantee that
make fmt and the hook can never format differently. Not a blocker.
How this surfaced
Found while validating #174 / #195: pre-commit run --files ... on that branch's changed
files aborted with the error above, so the hooks could not be used as a pre-push gate. The
CI-equivalent checks were run by hand instead (find deploy/ -name '*.sh' -exec shellcheck -x -S warning {} +, plus YAML and whitespace checks).
Assisted-By: Claude Code
Summary
.pre-commit-config.yamldoes not validate, sopre-commit runexecutes zero hooks —it aborts before running any of them. Nothing in CI runs the hooks or any formatter either,
so Prettier is currently unenforced end to end and this has gone unnoticed.
This is not a stale local install:
pre-commit4.3.0 (current) rejects the committed config.Reproduce
Note the failure blocks all hooks, including shellcheck, gitleaks, check-yaml and
trailing-whitespace — not just Prettier. A contributor who runs
pre-commit installgets acommit-time abort, and one who does not gets no checks at all.
Root cause
identifyhas notypescripttag. The tags for TypeScript sources aretsandtsx:The hint in pre-commit's error message ("Try upgrading identify and pre-commit?") is
misleading here — upgrading does not help, because the tag never existed under that name.
.tsfiles were therefore never matched by this hook even when the config did load.Verified fix
One line, in
.pre-commit-config.yaml:(
tsxis included deliberately — it is a separate identify tag, sotsalone would leave.tsxfiles unformatted, which is the same silent gap in a new place.)Two related gaps worth fixing in the same pass
1.
make fmtis broken independently of the hook. Prettier is not declared in anypackage.jsonin the workspace, so:.prettierrcand.prettierignoreare both committed, so formatting is clearly intended.Note this is a separate failure from the hook:
mirrors-prettierinstalls its own Prettierin a pre-commit-managed environment, so fixing the tag makes the hook work while
make fmtstays broken. Fix needs Prettier added as a root devDependency (pinned to matchwhatever version the hook uses, so the two cannot disagree about formatting).
2. Nothing in CI runs the hooks, which is why both went unnoticed. Current jobs:
ci.ymlcheck(pnpm test),proto(buf lint/generate, go build+test)security-scans.ymlshellcheck(overdeploy/only),hadolint(rootDockerfile), CodeQL, Trivy, dependency-reviewscorecard.ymlNo job runs
pre-commit,make lint, or Prettier. So a config that runs zero hooks isindistinguishable from a green build. Adding a
lintjob that runspre-commit run --all-fileswould have caught this on the commit that introduced it, andwould keep the local and CI story identical.
Acceptance
pre-commit validate-config .pre-commit-config.yamlexits 0.pre-commit run --all-filesruns every hook and passes (expect a formatting-only diffon first run, since Prettier has effectively never been enforced on
.tsfiles — worthlanding that reformat as its own commit so it does not bury real changes).
make fmtworks from a cleanpnpm install.CONTRIBUTING.mdmentionspre-commit install(it currently does not; onlyCLAUDE.mddoes).
Optional follow-up
pre-commit/mirrors-prettieris archived upstream and pinned here to a pre-release(
v4.0.0-alpha.8). Once the above is green it may be worth moving to a maintained hook, or arepo: localhook invoking the repo's own pinned Prettier — which would also guarantee thatmake fmtand the hook can never format differently. Not a blocker.How this surfaced
Found while validating #174 / #195:
pre-commit run --files ...on that branch's changedfiles aborted with the error above, so the hooks could not be used as a pre-push gate. The
CI-equivalent checks were run by hand instead (
find deploy/ -name '*.sh' -exec shellcheck -x -S warning {} +, plus YAML and whitespace checks).Assisted-By: Claude Code