odysseus-dev/odysseus · error · ValueError
could not read {path}: {exc}
Error message
could not read {path}: {exc} What it means
Raised by load_json_file in scripts/pr_blocker_audit.py when opening or reading the given path raises OSError — the file does not exist, is a directory, or the process lacks read permission. Like the JSON error, it is normalized to ValueError with the path embedded, so the audit script reports a uniform error for unusable input files.
Source
Thrown at scripts/pr_blocker_audit.py:161
self.stream.write(f"\r{' ' * self.last_len}\r")
self.stream.flush()
self.last_len = 0
def summary(self, message: str) -> None:
if self.enabled:
self.finish_line()
self.stream.write(f"{message}\n")
self.stream.flush()
def load_json_file(path: Path):
try:
with path.open("r", encoding="utf-8") as handle:
return json.load(handle)
except json.JSONDecodeError as exc:
raise ValueError(f"invalid JSON in {path}: {exc.msg} at line {exc.lineno}, column {exc.colno}") from exc
except OSError as exc:
raise ValueError(f"could not read {path}: {exc}") from exc
def fetch_live_prs(repo: str, fetch_files: bool = True, progress: ProgressReporter | None = None, limit: int = 1000):
progress = progress or ProgressReporter(False)
fields = (
"number,title,author,files,mergeStateStatus,reviewDecision,updatedAt,url"
if fetch_files
else "number,title,author,mergeStateStatus,reviewDecision,updatedAt,url"
)
cmd = ["gh", "pr", "list", "--repo", repo, "--state", "open", "--limit", str(limit), "--json", fields]
progress.phase("Fetching open PR list...")
try:
payload = _run_gh_json(cmd)
except RuntimeError:
api_path = f"repos/{repo}/pulls?state=open&per_page=100"
payload = _run_gh_json(["gh", "api", "--paginate", api_path])
payload = _limit_payload(payload, limit)
if not fetch_files:View on GitHub (pinned to f9235ebbf1)
Solutions
- Confirm the file exists at the exact path: ls -l <path> from the same directory you run the script from.
- Use an absolute path to eliminate cwd ambiguity.
- Fix permissions (chmod +r) or copy the file somewhere readable if running in a restricted environment.
- Expand any ~ or $VAR manually: use realpath <path> to get the literal location.
Example fix
# before $ python scripts/pr_blocker_audit.py --input prs.json # run from another dir ValueError: could not read prs.json: [Errno 2] No such file or directory # after $ python scripts/pr_blocker_audit.py --input /abs/path/to/prs.json
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
def check_readable_file(path: str) -> Path:
p = Path(path).expanduser().resolve()
if not p.is_file():
raise FileNotFoundError(f'not a file: {p}')
if not p.stat().st_size:
raise ValueError(f'empty file: {p}')
return p Type guard
import os
def is_readable_file(path: str) -> bool:
return os.path.isfile(os.path.expanduser(path)) and os.access(os.path.expanduser(path), os.R_OK) Try / catch
try:
payload = load_json_file(Path(args.input))
except ValueError as e:
if 'could not read' in str(e):
print(f'Check path/permissions: {e}', file=sys.stderr)
raise SystemExit(2) Prevention
- Pass absolute paths to CLI tools; resolve ~ with expanduser yourself.
- Assert the file exists and is non-empty immediately after capturing it, not at audit time.
- Run the script from the directory containing the snapshot, or derive paths from a known root.
When it happens
Trigger: Passing a wrong/misspelled --input path; relative path resolved from a different working directory; pointing at a directory instead of a file; permission bits or sandboxing denying read access; a path containing an unexpanded ~ or shell variable.
Common situations: Running the script from a different cwd so a relative snapshot path misses; typos in long filenames; the snapshot file was moved or deleted between capture and audit; running under a restricted container without volume read access.
Related errors
- invalid JSON in {path}: {exc.msg} at line {exc.lineno}, colu
- expected input JSON to be a list of pull requests or an obje
- gh returned invalid JSON: {exc}
- URL is required
- d && d.detail ? d.detail : ('HTTP ' + res.status)
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/c4c75f05572ff241.
Report an issue: GitHub.