affaan-m/ECC · error · ValueError
local artifact unavailable or unsafe
Error message
local artifact unavailable or unsafe
What it means
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'.
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.
Example fix
// before
try:
req = load_application_request(p)
except ValueError:
pass # reason swallowed
// after
try:
req = load_application_request(p)
except ValueError as e:
cause = e.__cause__ # original OSError: e.g. FileNotFoundError / PermissionError
log.error(f"artifact {p} unreadable: {cause}")
raise Defensive patterns
Strategy: try-catch
Validate before calling
import os
def assert_loadable(path: str) -> None:
if not os.path.isabs(path):
raise ValueError("path must be absolute")
if not os.path.isfile(path):
raise FileNotFoundError(path)
if not os.access(path, os.R_OK):
raise PermissionError(path) Try / catch
try:
req = load_application_request(p)
except ValueError as e:
if str(e) == "local artifact unavailable or unsafe":
cause = e.__cause__ # the original OSError / AttributeError
log.error(f"cannot read {p}: {cause!r}")
if isinstance(cause, FileNotFoundError):
regenerate_artifact(p)
elif isinstance(cause, PermissionError):
fix_permissions(p)
req = load_application_request(p)
else:
raise Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Cannot create exclusive receipt
- ECC_MEMORY_INCOMPLETE
- all overlays must be readable local files
- all takes must be readable local files
- artifact byte count exceeded during reading
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/f2f98203a429724d.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/integration.py:154
if count > expected_size:
raise ValueError("artifact byte count exceeded during reading")
digest.update(data)
if parse_json:
chunks.append(data)
# Rewalk the named path: a pinned old directory fd can outlive a rename.
fresh_parent = _parent_fd(path)
try:
after = os.stat(path.name, dir_fd=fresh_parent, follow_symlinks=False)
finally:
os.close(fresh_parent)
if (_identity(before) != _identity(os.fstat(descriptor))
or _identity(before) != _identity(after)):
raise ValueError("artifact changed during reading")
if expected_hash is not None and digest.hexdigest() != expected_hash:
raise ValueError("artifact SHA-256 mismatch")
return _load_json(b"".join(chunks)) if parse_json else None
except (OSError, AttributeError) as exc:
raise ValueError("local artifact unavailable or unsafe") from exc
finally:
if descriptor is not None:
os.close(descriptor)
if parent is not None:
os.close(parent)
def load_application_request(path: str | Path) -> dict:
"""Load only a bounded resident request; never follow a config symlink."""
value = _read_local(str(Path(path).absolute()), parse_json=True)
if not isinstance(value, dict):
raise ValueError("application request must be a JSON object")
return value
def _load_json(data: bytes) -> Any:
def unique(pairs):
result = {}View on GitHub (pinned to 8321021c54)