Skip to content

fix: graceful ENOENT error when DESIGN.md is missing (#132)#145

Open
Emp1500 wants to merge 2 commits into
google-labs-code:mainfrom
Emp1500:fix/enoent-friendly-error
Open

fix: graceful ENOENT error when DESIGN.md is missing (#132)#145
Emp1500 wants to merge 2 commits into
google-labs-code:mainfrom
Emp1500:fix/enoent-friendly-error

Conversation

@Emp1500

@Emp1500 Emp1500 commented Jun 28, 2026

Copy link
Copy Markdown

fix(cli): graceful error on missing or unreadable input file

##Before
ERROR ENOENT: no such file or directory, open 'DESIGN.md'
at readFileSync (node:fs:441:20)
at readInput (...index.js:24123:12)

##After

File missing:
Error: "DESIGN.md" not found. Create a DESIGN.md file or pass "-" to read from stdin.

Permission denied:
Error: "DESIGN.md" could not be read: permission denied.

Any other I/O error:
Error: "DESIGN.md" could not be read:

##Solution

Introduces a typed FileReadError class. readInput now throws it instead of calling process.exit directly. A friendlyMessage getter on the class checks the underlying OS error code
(ENOENT, EACCES, etc.) to produce an accurate message — so the error never says "not found" when the real problem is permissions.

Each command catches FileReadError, writes the plain-text message to stderr, and exits with code 2.

##Why this approach is better than a plain process.exit wrap:

  • readInput is unit-testable without mocking process.exit
  • FileReadError.filePath pinpoints which file failed (matters for diff, which reads two files)
  • FileReadError.friendlyMessage centralises message logic in one place — commands stay clean
  • Exit-code policy stays in the command layer where it belongs

##Changes

  • utils.ts — FileReadError class with friendlyMessage getter + readInput throws instead of exits
  • utils.test.ts — 6 new tests for readInput and FileReadError, zero mocking required
  • commands/lint.ts, commands/diff.ts, commands/export.ts — catch FileReadError, write error.friendlyMessage to stderr, exit code 2

Fixes #132

Emp1500 added 2 commits June 28, 2026 04:14
… stderr (google-labs-code#132)

Introduce a typed `FileReadError` class in `readInput` so the function
throws instead of calling `process.exit` directly. Each command handler
catches it and writes a plain-text error to stderr:

  Error: "DESIGN.md" not found.
  Create a DESIGN.md file or pass "-" to read from stdin.

This replaces the unhandled Node.js stack trace dump reported in google-labs-code#132.
`readInput` is now unit-testable without mocking `process.exit`, and
`FileReadError.filePath` identifies the specific missing file (important
for `diff`, which reads two files).
Replace the hardcoded "not found" string in all command handlers with
a friendlyMessage getter on FileReadError that checks the OS error code:
- ENOENT → "not found. Create a DESIGN.md file or pass '-' for stdin."
- EACCES → "could not be read: permission denied."
- other  → "could not be read: <raw message>"

This prevents a misleading "not found" message when the file exists
but cannot be read due to permissions or other I/O errors.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ENOENT: no such file or directory error when DESIGN.md is missing

1 participant