{"record":{"id":"b26fdb769fe94766","repo":"usestrix/strix","slug":"cannot-resume-scan-scan-id-agents-json-has-no-r","errorCode":null,"errorMessage":"Cannot resume scan {scan_id}: agents.json has no root agent (parent=None)","messagePattern":"Cannot resume scan (.+?): agents\\.json has no root agent \\(parent=None\\)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"strix/core/runner.py","lineNumber":219,"sourceCode":"        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,\n            )\n        for aid, parent in coordinator.parent_of.items():\n            if parent is None:\n                root_id = aid\n                break\n        if root_id is None:\n            raise RuntimeError(\n                f\"Cannot resume scan {scan_id}: agents.json has no root agent (parent=None)\",\n            )\n        logger.info(\n            \"Resume: restored coordinator with %d agent(s); root=%s\",\n            len(coordinator.statuses),\n            root_id,\n        )\n    else:\n        root_id = uuid.uuid4().hex[:8]\n\n    logger.info(\"Bringing up sandbox session for scan %s\", scan_id)\n    bundle = await session_manager.create_or_reuse(\n        scan_id,\n        image=image,\n        local_sources=local_sources or [],\n        extra_files=extra_files,\n        status_sink=status_sink,\n    )","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/usestrix/strix/blob/85513391305171ecc6faffe03da4a8bda5e3febb/strix/core/runner.py#L201-L237","documentation":"Raised on the resume path (strix/core/runner.py:219) after coordinator.restore(snap) succeeds but no agent in the restored parent_of map has parent None — i.e. the snapshot contains no root agent. Every Strix scan graph must have exactly one root agent (parent=None) to drive the run; a snapshot with only sub-agents is structurally invalid and resume is refused.","triggerScenarios":"Resuming from a hand-edited agents.json where the root entry was removed; a snapshot written by an older/different schema that serializes parentage differently (all agents report a parent); corrupted-but-parseable JSON that dropped the root record.","commonSituations":"Manual surgery on run artifacts; version skew between the Strix that wrote the snapshot and the one resuming; snapshots from aborted first-runs that never spawned the root correctly.","solutions":["Inspect agents.json and verify one entry has \"parent\": null; if absent, the snapshot is not a complete scan graph.","Resume with the same Strix version that produced the run (pip/uv pin) so the snapshot schema matches.","Otherwise start a new scan; notes/todos hydrated from the run dir still carry over context manually."],"exampleFix":"# before\n$ strix resume scan1   # agents.json has no root agent (parent=None)\n\n# after\n$ python -c \"import json;s=json.load(open('strix_runs/scan1/agents.json'));print([k for k,v in s.get('parent_of',{}).items() if v is None])\"\n# [] -> snapshot is incomplete; start a fresh scan instead","handlingStrategy":"validation","validationCode":"import json, pathlib\nsnap = json.loads((pathlib.Path(run_dir) / 'agents.json').read_text())\nhas_root = any(p is None for p in snap.get('parent_of', {}).values())\nif not has_root:\n    print('snapshot has no root agent; cannot resume — start a fresh scan')","typeGuard":"def snapshot_has_root(run_dir: str) -> bool:\n    import json, pathlib\n    s = json.loads((pathlib.Path(run_dir) / 'agents.json').read_text())\n    return any(p is None for p in s.get('parent_of', {}).values())","tryCatchPattern":"try:\n    await run_strix_scan(..., is_resume=True)\nexcept RuntimeError as exc:\n    if 'no root agent' in str(exc):\n        start_fresh_scan_with_notes_from(run_dir)  # manual context carry-over\n    else:\n        raise","preventionTips":["Never delete entries from agents.json.","Resume with the same Strix version that wrote the snapshot."],"tags":["resume","agent-graph","snapshot","validation"],"backgroundTag":null,"analyzedSha":"85513391305171ecc6faffe03da4a8bda5e3febb","analyzedAt":"2026-08-15T05:03:57.275Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}