mvanhorn/last30days-skill · error · HandoffContractError
{label.capitalize()} file {file_path} is not valid JSON: {ex
Error message
{label.capitalize()} file {file_path} is not valid JSON: {exc} What it means
`_load_host_file` raises HandoffContractError when the host-authored judgments/angles file is readable but fails `json.loads`. Because these files are hand- or model-authored (unlike the engine-written bundle/pending artifacts), the usual causes are authoring mistakes: trailing commas, comments, single quotes, smart quotes from rich-text editors, or truncation. The chained JSONDecodeError pinpoints the line/column; the label is capitalized in the message (e.g. 'Judgments file ... is not valid JSON').
Source
Thrown at skills/last30days/scripts/lib/discovery_handoff.py:627
angle_inputs=angle_inputs,
mock=bool(payload.get("mock")),
path=path,
)
def _load_host_file(path: str | Path, label: str) -> dict[str, Any]:
"""Load a host-authored handoff file with strict top-level checks."""
file_path = Path(path).expanduser()
try:
raw = file_path.read_text(encoding="utf-8")
except OSError as exc:
raise HandoffContractError(
f"Could not read {label} file {file_path}: {exc}"
) from exc
try:
payload = json.loads(raw)
except json.JSONDecodeError as exc:
raise HandoffContractError(
f"{label.capitalize()} file {file_path} is not valid JSON: {exc}"
) from exc
if not isinstance(payload, dict):
raise HandoffContractError(
f"{label.capitalize()} file {file_path} must be a top-level JSON "
f"object, got {type(payload).__name__}."
)
return payload
def _require_bundle_binding(
payload: dict[str, Any],
bundle: NominationsBundle | PendingReport,
*,
label: str,
save_dir: str | Path | None,
config_dir: Path | None,
) -> None:View on GitHub (pinned to c7460f6114)
Solutions
- Run `python3 -m json.tool <file>` (or `jq . <file>`) — the error location matches the message's JSONDecodeError.
- Fix the specific syntax issue: remove trailing commas/comments, use double quotes for all strings and keys, ensure the whole document is one JSON value.
- If the file was mangled beyond easy repair, regenerate it (host tooling or the authoring step) rather than hand-patching.
- Write future host files via `json.dump` from a script instead of by hand.
Example fix
// before (judgments.json)
{
'bundle_id': 'abc', // my notes
'judgments': [],
}
// after
{"bundle_id": "abc", "judgments": []} Defensive patterns
Strategy: validation
Validate before calling
import json
from pathlib import Path
def host_json_parses(path: Path) -> bool:
try:
json.loads(path.read_text(encoding="utf-8"))
return True
except (OSError, json.JSONDecodeError):
return False Try / catch
from lib import discovery_handoff
try:
payload = discovery_handoff._load_host_file("judgments.json", "judgments")
except discovery_handoff.HandoffContractError as exc:
if "not valid JSON" in exc.message:
# authoring error: run python3 -m json.tool to find the syntax fault
... Prevention
- Validate every host-authored file with `python3 -m json.tool <file>` before invoking the leg.
- Generate judgments/angles files with json.dump (or the host tooling) rather than typing JSON by hand.
- Paste JSON only as plain text; rich-text editors introduce smart quotes that break strict JSON parsing.
When it happens
Trigger: A judgments file with a trailing comma or `// comment`; copy-pasting JSON through a chat/markdown renderer that swapped straight quotes for curly ones; saving the file mid-edit; writing YAML or a Python-literal dict instead of JSON.
Common situations: LLM hosts emitting JSON with unquoted keys or single quotes; editors auto-inserting BOMs; users annotating the file with comments; `print()` of a Python dict saved as 'json'.
Related errors
- {label} {path} is not valid JSON: {exc}
- {label} {path} must be a top-level JSON object, got {type(pa
- Nominations bundle {path} must carry a top-level "nomination
- Nominations bundle {path} contains no readable nominations (
- Pending discovery report {path} must carry a top-level \"rep
AI-assisted analysis of mvanhorn/last30days-skill@c7460f6114 (2026-08-15).
Data as JSON: /api/errors/0ef735d11ab2b063.
Report an issue: GitHub.