File-not-found produces specific error
Why it matters
A raw ENOENT: no such file or directory, open 'path/to/file' stack trace tells the user the OS error code and the internal call stack — neither of which tells them what they should actually do. CWE-391 (Unchecked Error Condition) applies: the filesystem error is surfaced but not handled into a user-actionable message. When a CLI accepts user-specified file paths as arguments, it must own the responsibility of validating those paths before processing begins. Failing mid-processing — after partial output has already been written — is worse than failing fast at the boundary.
Severity rationale
Low because the error is immediately visible to the user and does not propagate silently — it degrades UX but does not cause data corruption or security exposure.
Remediation
Validate file existence at argument parse time, before any processing starts:
import { existsSync } from 'fs'
function validateFile(filePath: string): void {
if (!existsSync(filePath)) {
console.error(`Error: File not found: ${filePath}`)
console.error('Check the file path and try again.')
process.exit(2)
}
}
// call before any processing
validateFile(opts.input)
In click, use click.Path(exists=True) to get automatic validation with a clean error:
@cli.command()
@click.argument('file', type=click.Path(exists=True))
def lint(file):
"""Lint the specified FILE."""
# click errors before reaching here: "Error: Path 'missing.js' does not exist."
pass
The error message must name the specific path that was not found — generic "file not found" messages that omit the path force users to guess which argument was wrong.
Detection
-
ID:
file-not-found -
Severity:
low -
What to look for: List all file system operations that accept user-specified paths. For each, check how the CLI handles missing file inputs. Look for commands that accept file paths as arguments or options. Verify that attempting to process a nonexistent file produces a clear error naming the file, not a raw ENOENT or stack trace. Check that the error is emitted before attempting to process the file (fail fast).
-
Pass criteria: Missing file inputs produce a user-friendly error message that names the specific file that wasn't found and suggests what to check. The error is caught and handled, not an unhandled ENOENT exception — 100% of file access operations must produce a clear error message when the file does not exist. Report: "X file operations found, all Y handle missing files gracefully."
-
Fail criteria: Missing file inputs produce raw system errors (ENOENT), stack traces, or generic errors that don't name the missing file.
-
Skip (N/A) when: The CLI does not accept file path inputs. All checks skip when no CLI entry point is detected.
-
Detail on fail:
"Running 'mytool lint missing.js' produces raw 'Error: ENOENT: no such file or directory, open missing.js' instead of a friendly message"or"File existence is not checked before processing — error appears mid-processing with a stack trace" -
Remediation: Validate file existence before processing:
// Node.js — check file existence first import { existsSync } from 'fs' function validateFile(filePath: string): void { if (!existsSync(filePath)) { console.error(`Error: File not found: ${filePath}`) console.error('Check the file path and try again.') process.exit(2) } }# Python — click.Path handles this automatically @cli.command() @click.argument('file', type=click.Path(exists=True)) def lint(file): """Lint the specified FILE.""" pass # click will error: "Error: Path 'missing.js' does not exist."
External references
- cwe · CWE-391 — Unchecked Error Condition
Taxons
History
- 2026-04-18·v1.0.0·Initial import from cli-quality·automated