Skip to content

fix: emit actionable error when --edit cannot find COMMIT_EDITMSG (#589)#4755

Merged
escapedcat merged 2 commits into
masterfrom
fix/edit-flag-missing-commit-editmsg
May 14, 2026
Merged

fix: emit actionable error when --edit cannot find COMMIT_EDITMSG (#589)#4755
escapedcat merged 2 commits into
masterfrom
fix/edit-flag-missing-commit-editmsg

Conversation

@escapedcat

Copy link
Copy Markdown
Member

Fixes: #589

Catch ENOENT from reading the edit file and throw a message that explains --edit is meant for a commit-msg hook and points at --from / --to or --edit for other use cases. Avoids the raw fs error on fresh checkouts.

Catch ENOENT from reading the edit file and throw a message that
explains --edit is meant for a commit-msg hook and points at --from /
--to or --edit <file> for other use cases. Avoids the raw fs error
on fresh checkouts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@escapedcat escapedcat requested a review from Copilot May 11, 2026 09:55
@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

Emit actionable error when --edit cannot find COMMIT_EDITMSG

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Catch ENOENT error when reading COMMIT_EDITMSG file
• Provide actionable error message explaining --edit usage
• Guide users to --from/--to or --edit <file> alternatives
• Add test case for missing COMMIT_EDITMSG scenario
Diagram
flowchart LR
  A["getEditCommit function"] -->|readFile fails| B["Catch ENOENT error"]
  B -->|Check error code| C["Throw helpful error message"]
  C -->|Explain --edit usage| D["Guide to alternatives"]
  D -->|--from/--to or --edit file| E["User gets clear guidance"]
Loading

Grey Divider

File Changes

1. @commitlint/read/src/get-edit-commit.ts Error handling +14/-1

Add error handling for missing COMMIT_EDITMSG file

• Wrapped fs.readFile() call in try-catch block
• Added ENOENT error handling with descriptive message
• Error message explains --edit is for commit-msg hooks
• Suggests --from/--to or --edit <file> as alternatives

@commitlint/read/src/get-edit-commit.ts


2. @commitlint/read/src/read.test.ts 🧪 Tests +8/-0

Add test for missing COMMIT_EDITMSG error handling

• Added new test case for fresh repository scenario
• Tests that --edit throws actionable error without COMMIT_EDITMSG
• Uses regex pattern to verify error message content
• Validates error mentions commit-msg hook context

@commitlint/read/src/read.test.ts


Grey Divider

ⓘ You are approaching your monthly quota for Qodo. Upgrade your plan

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented May 11, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (1)

Grey Divider


Action required

1. --edit ENOENT now throws 📎 Requirement gap ≡ Correctness
Description
The new logic throws an Error when .git/COMMIT_EDITMSG is missing, which will cause a non-zero
exit attributable solely to the missing file. The compliance requirement explicitly states this
scenario must not fail the process and should be treated as a pass/no-op on fresh checkouts.
Code

@commitlint/read/src/get-edit-commit.ts[R19-31]

+	let editFile: Buffer;
+	try {
+		editFile = await fs.readFile(editFilePath);
+	} catch (err) {
+		if ((err as NodeJS.ErrnoException).code === "ENOENT") {
+			throw new Error(
+				`No commit message file found at ${editFilePath}.\n` +
+					`--edit reads the message prepared by 'git commit' and is intended to run from a commit-msg hook. ` +
+					`If you want to lint existing history, use --from / --to instead; to lint a specific file, pass its path as --edit <file>.`,
+			);
+		}
+		throw err;
+	}
Evidence
PR Compliance ID 1 requires @commitlint/cli to complete without throwing/failing when
.git/COMMIT_EDITMSG is absent on fresh checkouts. The changed code explicitly throws a new Error
on ENOENT, and the new test asserts that behavior, indicating the process will fail due to missing
COMMIT_EDITMSG.

Handle missing .git/COMMIT_EDITMSG without crashing in @commitlint/cli
@commitlint/read/src/get-edit-commit.ts[19-31]
@commitlint/read/src/read.test.ts[19-25]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The implementation throws when `--edit` cannot find `COMMIT_EDITMSG` (`ENOENT`). Compliance requires this fresh-checkout scenario to not crash and to not exit non-zero solely due to the missing file (treat as pass/no-op).
## Issue Context
The added test currently enforces throwing an error, which contradicts the compliance success criteria.
## Fix Focus Areas
- @commitlint/read/src/get-edit-commit.ts[19-31]
- @commitlint/read/src/read.test.ts[19-25]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Misleading missing edit message ✓ Resolved 🐞 Bug ≡ Correctness
Description
getEditCommit throws the same commit-msg-hook guidance for any ENOENT when reading the edit file,
even if the user explicitly provided --edit <file> (string). This can mislead users (and callers)
when the real issue is simply a wrong/missing custom path rather than the default COMMIT_EDITMSG
being absent.
Code

@commitlint/read/src/get-edit-commit.ts[R19-31]

+	let editFile: Buffer;
+	try {
+		editFile = await fs.readFile(editFilePath);
+	} catch (err) {
+		if ((err as NodeJS.ErrnoException).code === "ENOENT") {
+			throw new Error(
+				`No commit message file found at ${editFilePath}.\n` +
+					`--edit reads the message prepared by 'git commit' and is intended to run from a commit-msg hook. ` +
+					`If you want to lint existing history, use --from / --to instead; to lint a specific file, pass its path as --edit <file>.`,
+			);
+		}
+		throw err;
+	}
Evidence
getEditFilePath returns a custom resolved file path when edit is a string, but getEditCommit’s
ENOENT handler does not distinguish between edit: true (default COMMIT_EDITMSG) and `edit:
"somefile"` (user-provided path). As a result, the thrown message about being intended for a
commit-msg hook and suggesting --edit  can be incorrect/misleading for the explicit file-path
case.

@commitlint/read/src/get-edit-commit.ts[17-31]
@commitlint/read/src/get-edit-file-path.ts[6-12]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`getEditCommit()` throws the same ENOENT error message for both:
- default edit mode (`edit === true`) where `.git/COMMIT_EDITMSG` is expected, and
- explicit file mode (`typeof edit === "string"`) where the user passed `--edit <file>`.
This makes the guidance misleading for the explicit file case.
## Issue Context
`getEditFilePath()` resolves a user-provided `edit` string to an arbitrary path, but `getEditCommit()`’s ENOENT handler does not branch on the original `edit` value.
## Fix Focus Areas
- @commitlint/read/src/get-edit-commit.ts[17-31]
- @commitlint/read/src/get-edit-file-path.ts[6-12]
## Suggested change
- In the ENOENT catch:
- If `edit === true` (or boolean/empty-flag case), keep the current commit-msg-hook guidance.
- If `typeof edit === "string"`, throw a message specific to a missing user-provided file (e.g., `Edit file not found at ...; check the path passed to --edit`).
- (Optional, Node 22+) Preserve the original error as `cause` to retain debugging context.
- Add a unit test asserting the explicit-file missing-path message when `read({ edit: "does-not-exist", cwd })` rejects.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves the UX of @commitlint/read when edit: true (CLI: --edit) is used in a repository where .git/COMMIT_EDITMSG does not exist (e.g., a fresh checkout with no commits yet), replacing the raw filesystem error with a more actionable message and adding a regression test.

Changes:

  • Catch ENOENT when reading the edit commit message file and throw an explanatory error message.
  • Add a test asserting the actionable error is thrown on a freshly initialized repo without COMMIT_EDITMSG.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
@commitlint/read/src/get-edit-commit.ts Wraps fs.readFile to translate ENOENT into a more actionable error message.
@commitlint/read/src/read.test.ts Adds a regression test for edit: true behavior on a fresh repo without COMMIT_EDITMSG.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread @commitlint/read/src/get-edit-commit.ts
Comment thread @commitlint/read/src/get-edit-commit.ts
- Attach the caught ENOENT as `cause` to satisfy preserve-caught-error
  and aid debugging.
- When `--edit <file>` was supplied, point users at the path they
  passed instead of the commit-msg-hook guidance.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@escapedcat escapedcat merged commit bb10907 into master May 14, 2026
15 checks passed
@escapedcat escapedcat deleted the fix/edit-flag-missing-commit-editmsg branch May 14, 2026 08:31
@knocte

knocte commented May 14, 2026

Copy link
Copy Markdown
Contributor

Mmm, looks like code_quality CI is not being run in PRs?

@knocte

knocte commented May 14, 2026

Copy link
Copy Markdown
Contributor

Actually, it ran, I'm confused.

escapedcat added a commit that referenced this pull request May 14, 2026
The --edit error handling change in #4755 merged with an unformatted
multi-line throw expression, breaking the format check on subsequent CI
runs. Collapse it to oxfmt's expected single-line form.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

no such file or directory COMMIT_EDITMSG on new checkout

3 participants