How to read a rejected commit
The pre-commit hooks block a commit that would break the build or the conventions. The output is long — especially on large commits — and the line that explains the rejection is rarely the last one printed. This guide is about finding it. For what the hooks run and why, see what happens when you commit.
Find the verdict, ignore the collateral
The run always ends with husky's husky - pre-commit script failed (code 1) line and npm's error
tail — scroll up from there. A large commit is linted in concurrent chunks, and one failing chunk
cancels all others; the cancelled chunks print as noise:
✖ Task killed: node ./scripts/dia-scripts/index.mjs lint metadata
✖ Task killed: node ./scripts/dia-scripts/index.mjs lint metadata
Every Task killed: line is a consequence, not a cause. The block you want names its task with a
colon and ends in a verdict:
✖ node ./scripts/dia-scripts/index.mjs lint metadata:
[x] 2 violation(s) introduced by this commit, on lines it changed:
force-app/main/default/classes/CaseService.cls:42 pmd:ApexCRUDViolation
Validate CRUD permission before SOQL/DML operation
[i] 8 further pre-existing violation(s) in the same files.
The verdicts and what to do
| Verdict block | Meaning | Fix |
|---|---|---|
[x] N violation(s) introduced by this commit, on lines it changed |
The lint gate blocks only what your commit introduced. Pre-existing counts ([i] …) are informational. |
Fix the named lines, or suppress deliberately. Re-commit. |
[x] N violation(s) introduced by this commit … naming a regex:Salesforce…, regex:…Token, regex:PrivateKeyBlock or regex:GenericCredentialAssignment rule under lint secrets |
A credential-shaped value sits on a line you are committing. The value has not left your machine. | Follow how to handle a committed secret from step 4; for a placeholder, add the DO-NOT-USE marker. |
✖ header must not be longer than 100 characters (and other commitlint rules), then husky - commit-msg script failed (code 1) |
The message was rejected, not the change. The files stay staged. | Commit again with a conventional message (fix: …, feat: …, chore: …) — npm run cm (Commitizen) writes a conforming one; nothing else to redo. |
file.md:12 MD013/line-length … |
markdownlint rejected a staged markdown file. | Fix the line (or adjust .markdownlintrc.js deliberately). Re-commit. |
| Jest output with failing specs | The JavaScript step runs the tests related to your staged files. | Fix code or test, re-commit. |
| Build/webpack errors after lint-staged | npm run validate runs a build check after the per-file tasks. |
Fix the build, re-commit. |
Error (…) without a violations table |
The scan itself crashed — not a verdict about your code. | Read the error; if it names a missing file or tool, fix the environment and re-commit. |
Where the output surfaces
- Terminal: everything above appears inline. Nothing else to know.
- VS Code: the Source Control commit button shows only a small error toast; the full hook output is in the Git output channel (the toast's button — "Show Command Output" or "Open Git Log" depending on the version). Committing from the integrated terminal shows it directly.
The state you are left in
Your work is intact either way: staged files stay staged, nothing is half-committed. A failure
inside lint-staged also rolls back the formatting it had just applied (you will see
Reverting to original state because of errors...); a failure in the later build check or in
commit-msg keeps it. The full scan report is readable under logs/ when the verdict has scrolled
away. Fix the cause — npm run format:changed and npm run lint re-check without committing — and
run the same git commit again.
Do not bypass the hooks with --no-verify — see
bypassing the hooks only moves the failure.