# File-not-found produces specific error

- **Pattern:** `ab-000656` (`cli-quality.error-handling.file-not-found`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000656
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000656)

## 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:

```ts
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:

```python
@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:

  ```ts
  // 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
  # 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

Taxons: user-experience, error-resilience

HTML version: https://auditbuffet.com/patterns/ab-000656
