Skip to content

fix: pre-commit runs zero hooks — 'typescript' is not an identify tag, and no CI job catches it #196

Description

@pdettori

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

  • pre-commit validate-config .pre-commit-config.yaml exits 0.
  • pre-commit run --all-files runs every hook and passes (expect a formatting-only diff
    on first run, since Prettier has effectively never been enforced on .ts files — worth
    landing that reformat as its own commit so it does not bury real changes).
  • make fmt works from a clean pnpm install.
  • A CI job fails the build when hooks fail, so this cannot silently regress.
  • CONTRIBUTING.md mentions pre-commit install (it currently does not; only CLAUDE.md
    does).

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions