{"record":{"id":"f2f98203a429724d","repo":"affaan-m/ECC","slug":"local-artifact-unavailable-or-unsafe","errorCode":null,"errorMessage":"local artifact unavailable or unsafe","messagePattern":"local artifact unavailable or unsafe","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/integration.py","lineNumber":154,"sourceCode":"            if count > expected_size:\n                raise ValueError(\"artifact byte count exceeded during reading\")\n            digest.update(data)\n            if parse_json:\n                chunks.append(data)\n        # Rewalk the named path: a pinned old directory fd can outlive a rename.\n        fresh_parent = _parent_fd(path)\n        try:\n            after = os.stat(path.name, dir_fd=fresh_parent, follow_symlinks=False)\n        finally:\n            os.close(fresh_parent)\n        if (_identity(before) != _identity(os.fstat(descriptor))\n                or _identity(before) != _identity(after)):\n            raise ValueError(\"artifact changed during reading\")\n        if expected_hash is not None and digest.hexdigest() != expected_hash:\n            raise ValueError(\"artifact SHA-256 mismatch\")\n        return _load_json(b\"\".join(chunks)) if parse_json else None\n    except (OSError, AttributeError) as exc:\n        raise ValueError(\"local artifact unavailable or unsafe\") from exc\n    finally:\n        if descriptor is not None:\n            os.close(descriptor)\n        if parent is not None:\n            os.close(parent)\n\n\ndef load_application_request(path: str | Path) -> dict:\n    \"\"\"Load only a bounded resident request; never follow a config symlink.\"\"\"\n    value = _read_local(str(Path(path).absolute()), parse_json=True)\n    if not isinstance(value, dict):\n        raise ValueError(\"application request must be a JSON object\")\n    return value\n\n\ndef _load_json(data: bytes) -> Any:\n    def unique(pairs):\n        result = {}","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/integration.py#L136-L172","documentation":"This is the wrapper applied to any `OSError` or `AttributeError` escaping the body of `_read_local` — e.g. missing path components, permission errors, a non-existent file, `st_flags` absent on the platform, or `dir_fd`/`O_NOFOLLOW` unsupported by the OS/filesystem. The library converts these low-level failures into a single, uniform `ValueError` so callers get one predictable error for 'the artifact could not be safely read locally'.","triggerScenarios":"Path does not exist or an intermediate directory is missing; read permission denied; the final path component vanished between validation and open; `os.O_NOFOLLOW`/`dir_fd`/`st_flags` unavailable (platform or filesystem limitation); too many open fds causing EMFILE during open.","commonSituations":"Typo'd artifact path; running the tool as a user without read access to a build directory; using an old kernel or exotic filesystem (some network mounts) lacking `dir_fd` support; artifacts deleted by a cleanup job before load.","solutions":["Confirm the canonical absolute path exists and is readable: `os.path.isfile(p) and os.access(p, os.R_OK)` before calling.","Catch this `ValueError`, inspect `__cause__` (the original `OSError`) to learn the real reason (ENOENT, EACCES, etc.), and fix that underlying condition.","Regenerate the artifact if a cleanup/retention job deleted it, or restore it from the build output.","If `AttributeError` indicates a platform limitation (`st_flags`, `O_NOFOLLOW`), run the pipeline on a filesystem/OS that supports the required fd-based safeguards, or vendor a fallback reader."],"exampleFix":"// before\ntry:\n    req = load_application_request(p)\nexcept ValueError:\n    pass  # reason swallowed\n// after\ntry:\n    req = load_application_request(p)\nexcept ValueError as e:\n    cause = e.__cause__  # original OSError: e.g. FileNotFoundError / PermissionError\n    log.error(f\"artifact {p} unreadable: {cause}\")\n    raise","handlingStrategy":"try-catch","validationCode":"import os\ndef assert_loadable(path: str) -> None:\n    if not os.path.isabs(path):\n        raise ValueError(\"path must be absolute\")\n    if not os.path.isfile(path):\n        raise FileNotFoundError(path)\n    if not os.access(path, os.R_OK):\n        raise PermissionError(path)","typeGuard":null,"tryCatchPattern":"try:\n    req = load_application_request(p)\nexcept ValueError as e:\n    if str(e) == \"local artifact unavailable or unsafe\":\n        cause = e.__cause__            # the original OSError / AttributeError\n        log.error(f\"cannot read {p}: {cause!r}\")\n        if isinstance(cause, FileNotFoundError):\n            regenerate_artifact(p)\n        elif isinstance(cause, PermissionError):\n            fix_permissions(p)\n        req = load_application_request(p)\n    else:\n        raise","preventionTips":["Always inspect `__cause__` when this wrapper fires — it names the real OS-level problem.","Pre-flight check existence, type, and read permission before invoking the loader.","Run the pipeline on filesystems/kernels that support `dir_fd` and `O_NOFOLLOW` (avoid exotic network mounts).","Exclude artifact directories from aggressive cleanup/retention jobs while the pipeline runs."],"tags":["filesystem","io-error","error-wrapping"],"backgroundTag":"file-read-failed","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}