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
- Check path.is_file() before calling, or catch FileNotFoundError.
- When used for cache invalidation, treat FileNotFoundError as a cache miss (drop the entry) rather than an error.
- Resolve symlinks with path.resolve() before hashing.
- 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
- Check path.is_file() before hashing.
- Treat FileNotFoundError as cache invalidation, not an error.
- Resolve symlinks before hashing to match the canonical path.
- Re-enumerate the file set if FileNotFoundError appears during bulk hashing.
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.