odysseus-dev/odysseus · error · ValueError

invalid JSON in {path}: {exc.msg} at line {exc.lineno}, colu

Error message

invalid JSON in {path}: {exc.msg} at line {exc.lineno}, column {exc.colno}

What it means

Raised by load_json_file in scripts/pr_blocker_audit.py when a JSON file passed as an offline input (PR snapshot, cache, or config) fails to parse with json.load. The original json.JSONDecodeError message, line, and column are embedded, and the exception is re-raised as ValueError so callers only need to handle one exception type for bad input files.

Source

Thrown at scripts/pr_blocker_audit.py:159

    def finish_line(self) -> None:
        if self.enabled and self.last_len:
            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])

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Open the file at the reported line/column and fix the JSON syntax error (the message gives the exact position).
  2. Validate with an external tool first: python -m json.tool <file> or jq . <file> to get a second opinion on the error location.
  3. If the file is JSONL or a gh --paginate capture, wrap it into a single array before passing it (e.g. jq -s . < in > out).
  4. Re-capture the file from its source (gh pr list --json ...) instead of hand-editing.

Example fix

# before
$ python scripts/pr_blocker_audit.py --input prs.json
ValueError: invalid JSON in prs.json: Expecting ',' delimiter at line 12, column 5

# after
$ python -m json.tool prs.json   # locate/fix line 12
$ python scripts/pr_blocker_audit.py --input prs.json
Defensive patterns

Strategy: validation

Validate before calling

import json
from pathlib import Path

def validate_json_input(path: str | Path) -> dict | list:
    p = Path(path)
    data = json.loads(p.read_text(encoding='utf-8-sig'))  # tolerate BOM
    return data

Type guard

def is_valid_json_file(path: str) -> bool:
    try:
        with open(path, 'r', encoding='utf-8-sig') as fh:
            json.load(fh)
        return True
    except (json.JSONDecodeError, OSError):
        return False

Try / catch

try:
    payload = load_json_file(Path(args.input))
except ValueError as e:
    if 'invalid JSON in' in str(e):
        print(f'Fix the JSON syntax error: {e}', file=sys.stderr)
    raise SystemExit(2)

Prevention

When it happens

Trigger: Running pr_blocker_audit.py with --input <file> (or any flag that loads a JSON snapshot) where the file has a syntax error: trailing comma, unescaped newline in a string, BOM, truncated download, or JSONL content fed where a single JSON document is expected.

Common situations: Hand-editing a gh pr list --json dump and breaking syntax; a partially-written/interrupted file capture; piping JSONL (one object per line) into an argument that expects one array; Windows BOM prepended by an editor.

Understand the failure class

Related errors


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/60117f9f8d4b91af. Report an issue: GitHub.