{"record":{"id":"9ebc9550fe8db59a","repo":"usestrix/strix","slug":"cannot-resume-scan-scan-id-agents-json-is-unrea","errorCode":null,"errorMessage":"Cannot resume scan {scan_id}: agents.json is unreadable: {exc}","messagePattern":"Cannot resume scan (.+?): agents\\.json is unreadable: (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"strix/core/runner.py","lineNumber":194,"sourceCode":"    logger.info(\"LLM model resolved: %s\", resolved_model)\n    chat_completions_tools = uses_chat_completions_tool_schema(resolved_model, settings)\n\n    if coordinator is None:\n        coordinator = AgentCoordinator()\n    coordinator.set_snapshot_path(agents_path)\n\n    from strix.tools.notes.tools import hydrate_notes_from_disk\n    from strix.tools.todo.tools import hydrate_todos_from_disk\n\n    hydrate_todos_from_disk(state_dir)\n    hydrate_notes_from_disk(state_dir)\n\n    root_id: str | None = None\n    if is_resume:\n        try:\n            snap = json.loads(agents_path.read_text(encoding=\"utf-8\"))\n        except (OSError, json.JSONDecodeError) as exc:\n            raise RuntimeError(\n                f\"Cannot resume scan {scan_id}: agents.json is unreadable: {exc}\",\n            ) from exc\n        if not agents_db.exists():\n            raise RuntimeError(\n                f\"Cannot resume scan {scan_id}: missing SDK session database at {agents_db}\",\n            )\n        await coordinator.restore(snap)\n        report_state = get_global_report_state()\n        if report_state is not None:\n            budget_stopped, reserve_stopped = recomputed_budget_flags(\n                report_state.get_total_llm_cost(),\n                max_budget_usd,\n                interactive=interactive,\n            )\n            await coordinator.reset_budget_stops(\n                budget_stopped=budget_stopped,\n                reserve_stopped=reserve_stopped,\n                budget_paused=interactive and coordinator.budget_paused,","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/usestrix/strix/blob/85513391305171ecc6faffe03da4a8bda5e3febb/strix/core/runner.py#L176-L212","documentation":"Raised on the resume path of run_strix_scan (strix/core/runner.py:194) when the run directory's agents.json snapshot cannot be read as UTF-8 text (OSError) or does not parse as JSON (JSONDecodeError). The snapshot holds the agent-graph state needed to restore the coordinator, so a corrupt or missing file makes resumption impossible; the original exception is chained via `from exc`.","triggerScenarios":"Calling run_strix_scan(resume=True) / strix resume <scan_id> when agents.json was truncated by a crash or disk-full, edited by hand, saved with invalid JSON, or has unreadable permissions.","commonSituations":"Killing the strix process (or a power loss) mid-write of agents.json; syncing run directories through tools that mangle encoding; running as a different user with weaker file permissions.","solutions":["Inspect agents.json in the run directory (strix_runs/<run>/agents.json): validate it with `python -m json.tool` and check permissions.","If it is truncated/corrupt beyond repair, start a fresh scan instead of resuming — artifacts in the run dir are still readable for reporting.","Restore agents.json from a backup of the run directory if one exists.","Prevent recurrence: avoid force-killing strix mid-scan; use graceful stop so snapshots flush."],"exampleFix":"# before\n$ strix resume my-scan   # RuntimeError: agents.json is unreadable\n\n# after\n$ python -m json.tool strix_runs/my-scan/agents.json   # locate the syntax error\n$ strix -n -t ./ --run-name my-scan-2                # or start fresh","handlingStrategy":"validation","validationCode":"import json, pathlib\nsnap_path = pathlib.Path(run_dir) / 'agents.json'\ntry:\n    json.loads(snap_path.read_text(encoding='utf-8'))\nexcept (OSError, json.JSONDecodeError) as exc:\n    print(f'cannot resume: snapshot bad ({exc}); start a new scan')","typeGuard":"def snapshot_is_resumable(run_dir: str) -> bool:\n    import json, pathlib\n    p = pathlib.Path(run_dir) / 'agents.json'\n    try:\n        json.loads(p.read_text(encoding='utf-8'))\n    except (OSError, json.JSONDecodeError):\n        return False\n    return True","tryCatchPattern":"try:\n    await run_strix_scan(..., is_resume=True)\nexcept RuntimeError as exc:\n    if 'agents.json is unreadable' in str(exc):\n        # fall back to a fresh run; old artifacts remain readable\n        await run_strix_scan(..., is_resume=False)\n    else:\n        raise","preventionTips":["Stop scans gracefully so snapshots flush fully.","Back up the run directory before resuming.","Never hand-edit agents.json."],"tags":["resume","persistence","json","filesystem"],"backgroundTag":null,"analyzedSha":"85513391305171ecc6faffe03da4a8bda5e3febb","analyzedAt":"2026-08-15T05:03:57.275Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}