{"record":{"id":"6223e63f0c7c6d1f","repo":"JuliusBrussee/caveman","slug":"file-not-found-filepath-6223e6","errorCode":null,"errorMessage":"File not found: {filepath}","messagePattern":"File not found: (.+?)","errorType":"validation","errorClass":"FileNotFoundError","httpStatus":null,"severity":"error","filePath":"skills/caveman-compress/scripts/compress.py","lineNumber":282,"sourceCode":"ORIGINAL (reference only):\n{original}\n\nCOMPRESSED (fix this):\n{compressed}\n\nReturn ONLY the fixed compressed file. No explanation.\n\"\"\"\n\n\n# ---------- Core Logic ----------\n\n\ndef compress_file(filepath: Path) -> bool:\n    # Resolve and validate path\n    filepath = filepath.resolve()\n    MAX_FILE_SIZE = 500_000  # 500KB\n    if not filepath.exists():\n        raise FileNotFoundError(f\"File not found: {filepath}\")\n    if filepath.stat().st_size > MAX_FILE_SIZE:\n        raise ValueError(f\"File too large to compress safely (max 500KB): {filepath}\")\n\n    # Refuse files that look like they contain secrets or PII. Compressing ships\n    # the raw bytes to the Anthropic API — a third-party boundary — so we fail\n    # loudly rather than silently exfiltrate credentials or keys. Override is\n    # intentional: the user must rename the file if the heuristic is wrong.\n    if is_sensitive_path(filepath):\n        raise ValueError(\n            f\"Refusing to compress {filepath}: filename looks sensitive \"\n            \"(credentials, keys, secrets, or known private paths). \"\n            \"Compression sends file contents to the Anthropic API. \"\n            \"Rename the file if this is a false positive.\"\n        )\n\n    print(f\"Processing: {filepath}\")\n\n    if not should_compress(filepath):","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/skills/caveman-compress/scripts/compress.py#L264-L300","documentation":"Raised by compress_file() after resolving the argument with Path.resolve(): the target file does not exist on disk. The check runs before size/sensitivity checks, so a nonexistent path always fails here first, with the resolved absolute path in the message.","triggerScenarios":"Invoking the compress skill or compress.py with a path that is misspelled, relative to a different cwd, already deleted/moved, or a symlink whose target is gone (resolve() surfaces the dead target).","commonSituations":"Agent passes a path quoted from an old conversation after the file was renamed; relative paths evaluated from a different working directory; case-sensitivity mismatches on Linux; a temp file cleaned up mid-session.","solutions":["Check the resolved path printed in the error with ls — it is absolute, so cwd confusion is ruled out.","Fix the typo or pass the correct current location of the file.","If the file was expected to exist, find where it moved (git status / glob for the filename) and re-run with the new path."],"exampleFix":"# before\ncompress_file(Path('docs/README-caveman.md'))  # FileNotFoundError: .../docs/README-caveman.md\n\n# after\ncompress_file(Path('docs/README.md'))","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef compressible_path(raw: str) -> bool:\n    p = Path(raw).resolve()\n    return p.is_file() and not p.is_symlink() or p.exists()","typeGuard":null,"tryCatchPattern":"try:\n    compress_file(path)\nexcept FileNotFoundError as e:\n    # resolved absolute path is in the message; locate the moved file and re-run\n    path = relocate(path)\n    raise","preventionTips":["Pass absolute paths to compress_file — resolve() makes the error message unambiguous.","Verify existence (Path(p).is_file()) in the calling agent before invoking the skill.","Re-glob for the filename if it was renamed instead of guessing paths."],"tags":["filesystem","path","validation"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}