{"record":{"id":"547aaed43c62baf3","repo":"affaan-m/ECC","slug":"file-not-found-path","errorCode":null,"errorMessage":"File not found: {path}","messagePattern":"File not found: (.+?)","errorType":"exception","errorClass":"FileNotFoundError","httpStatus":null,"severity":"warning","filePath":"skills/content-hash-cache-pattern/SKILL.md","lineNumber":34,"sourceCode":"- Need a `--cache/--no-cache` CLI option\n- Want to add caching to existing pure functions without modifying them\n\n## Core Pattern\n\n### 1. Content-Hash Based Cache Key\n\nUse file content (not path) as the cache key:\n\n```python\nimport hashlib\nfrom pathlib import Path\n\n_HASH_CHUNK_SIZE = 65536  # 64KB chunks for large files\n\ndef compute_file_hash(path: Path) -> str:\n    \"\"\"SHA-256 of file contents (chunked for large files).\"\"\"\n    if not path.is_file():\n        raise FileNotFoundError(f\"File not found: {path}\")\n    sha256 = hashlib.sha256()\n    with open(path, \"rb\") as f:\n        while True:\n            chunk = f.read(_HASH_CHUNK_SIZE)\n            if not chunk:\n                break\n            sha256.update(chunk)\n    return sha256.hexdigest()\n```\n\n**Why content hash?** File rename/move = cache hit. Content change = automatic invalidation. No index file needed.\n\n### 2. Frozen Dataclass for Cache Entry\n\n```python\nfrom dataclasses import dataclass\n\n@dataclass(frozen=True, slots=True)","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/skills/content-hash-cache-pattern/SKILL.md#L16-L52","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nh = compute_file_hash(path)\n\n// after\ndef safe_file_hash(path: Path) -> str | None:\n    try:\n        return compute_file_hash(path)\n    except FileNotFoundError:\n        return None  # treat missing file as cache miss\n\nh = safe_file_hash(path)","handlingStrategy":"try-catch","validationCode":"from pathlib import Path\n\ndef hashable(path: Path) -> bool:\n    return path.is_file()","typeGuard":"def is_file_not_found(exc: BaseException) -> bool:\n    return isinstance(exc, FileNotFoundError)","tryCatchPattern":"try:\n    h = compute_file_hash(path)\nexcept FileNotFoundError:\n    cache.invalidate(path)","preventionTips":["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."],"tags":["file-io","cache","hashing","skill-example"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}