affaan-m/ECC · warning · FileNotFoundError

File not found: {path}

Error message

File not found: {path}

What it means

In the content-hash-cache-pattern skill's example, compute_file_hash() raises FileNotFoundError when path.is_file() is False. This is a teaching snippet, not shipped library code — it documents the content-hash cache pattern. The is_file() guard runs before open(), so a missing/renamed/moved/non-regular file fails fast with a clear message instead of a generic OSError.

Source

Thrown at skills/content-hash-cache-pattern/SKILL.md:34

- Need a `--cache/--no-cache` CLI option
- Want to add caching to existing pure functions without modifying them

## Core Pattern

### 1. Content-Hash Based Cache Key

Use file content (not path) as the cache key:

```python
import hashlib
from pathlib import Path

_HASH_CHUNK_SIZE = 65536  # 64KB chunks for large files

def compute_file_hash(path: Path) -> str:
    """SHA-256 of file contents (chunked for large files)."""
    if not path.is_file():
        raise FileNotFoundError(f"File not found: {path}")
    sha256 = hashlib.sha256()
    with open(path, "rb") as f:
        while True:
            chunk = f.read(_HASH_CHUNK_SIZE)
            if not chunk:
                break
            sha256.update(chunk)
    return sha256.hexdigest()
```

**Why content hash?** File rename/move = cache hit. Content change = automatic invalidation. No index file needed.

### 2. Frozen Dataclass for Cache Entry

```python
from dataclasses import dataclass

@dataclass(frozen=True, slots=True)

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Check path.is_file() before calling, or catch FileNotFoundError.
  2. When used for cache invalidation, treat FileNotFoundError as a cache miss (drop the entry) rather than an error.
  3. Resolve symlinks with path.resolve() before hashing.
  4. Re-enumerate the file set if FileNotFoundError appears during bulk hashing.

Example fix

// before
h = compute_file_hash(path)

// after
def safe_file_hash(path: Path) -> str | None:
    try:
        return compute_file_hash(path)
    except FileNotFoundError:
        return None  # treat missing file as cache miss

h = safe_file_hash(path)
Defensive patterns

Strategy: try-catch

Validate before calling

from pathlib import Path

def hashable(path: Path) -> bool:
    return path.is_file()

Type guard

def is_file_not_found(exc: BaseException) -> bool:
    return isinstance(exc, FileNotFoundError)

Try / catch

try:
    h = compute_file_hash(path)
except FileNotFoundError:
    cache.invalidate(path)

Prevention

When it happens

Trigger: Calling compute_file_hash on a path that doesn't exist; path is a directory (is_file() False); the file was deleted between enumeration and hashing (TOCTOU); a relative path resolved against the wrong cwd; a symlink to a missing target.

Common situations: A stale cache entry pointing at a deleted file; a race where the file is moved after enumeration; passing a directory path by mistake; a dangling symlink.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/547aaed43c62baf3. Report an issue: GitHub.