{"record":{"id":"7be03944959e0f7a","repo":"usestrix/strix","slug":"vulnerabilities-json-at-path-is-corrupt-exc","errorCode":null,"errorMessage":"vulnerabilities.json at {path} is corrupt ({exc}); refusing to start fresh — that would overwrite prior vulnerability MDs on disk. Inspect or delete the run dir.","messagePattern":"vulnerabilities\\.json at (.+?) is corrupt \\((.+?)\\); refusing to start fresh — that would overwrite prior vulnerability MDs on disk\\. Inspect or delete the run dir\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"critical","filePath":"strix/report/state.py","lineNumber":198,"sourceCode":"        if data:\n            self.run_record.update(data)\n            if isinstance(data.get(\"start_time\"), str):\n                self.start_time = data[\"start_time\"]\n            if isinstance(data.get(\"end_time\"), str):\n                self.end_time = data[\"end_time\"]\n            scan_results = data.get(\"scan_results\")\n            if isinstance(scan_results, dict):\n                self.scan_results = scan_results\n                self.final_scan_result = self._format_final_scan_result(scan_results)\n            self._hydrate_llm_usage(data.get(\"llm_usage\"))\n            logger.info(\"report state hydrated run.json from %s\", run_dir)\n\n        json_path = run_dir / \"vulnerabilities.json\"\n        if json_path.exists():\n            try:\n                data = json.loads(json_path.read_text(encoding=\"utf-8\"))\n            except (OSError, json.JSONDecodeError) as exc:\n                raise RuntimeError(\n                    f\"vulnerabilities.json at {json_path} is corrupt ({exc}); \"\n                    f\"refusing to start fresh — that would overwrite prior \"\n                    f\"vulnerability MDs on disk. Inspect or delete the run dir.\",\n                ) from exc\n            if not isinstance(data, list):\n                raise RuntimeError(\n                    f\"vulnerabilities.json at {json_path} is not a list\",\n                )\n            self.vulnerability_reports = [r for r in data if isinstance(r, dict)]\n            for r in self.vulnerability_reports:\n                rid = r.get(\"id\")\n                if isinstance(rid, str):\n                    self._saved_vuln_ids.add(rid)\n            logger.info(\n                \"report state hydrated %d vulnerability report(s)\",\n                len(self.vulnerability_reports),\n            )\n","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/usestrix/strix/blob/85513391305171ecc6faffe03da4a8bda5e3febb/strix/report/state.py#L180-L216","documentation":"ReportState hydrates itself from a run directory on startup. If vulnerabilities.json exists but cannot be read or parsed (OSError or JSONDecodeError), it raises RuntimeError instead of silently starting with an empty state. The explicit rationale: starting fresh would overwrite previously written vulnerability Markdown files on disk, so the corrupt file must be resolved by the operator first.","triggerScenarios":"Resuming or viewing a run whose strix_runs/<run>/vulnerabilities.json is truncated (e.g. process killed mid atomic-write, disk full) or unreadable (permissions, removed while reading). Any code path that constructs ReportState over that run dir (resume, viewer, report regeneration) triggers it.","commonSituations":"Scan process killed or OOM during a write; non-atomic external edits to the file; partial copy/sync of the run directory; filesystem permission changes between runs.","solutions":["Inspect vulnerabilities.json in the named run dir — if it is a truncated tail, salvage valid entries or delete the file, then retry.","If the run is disposable, delete the whole run directory and start a new scan.","Restore the file from a backup of the run dir if prior findings matter.","Check for the root cause (disk full, killed process) before retrying so the new write does not corrupt again."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import json\nfrom pathlib import Path\n\ndef vuln_json_loadable(run_dir: Path) -> bool:\n    p = run_dir / \"vulnerabilities.json\"\n    if not p.exists():\n        return True\n    try:\n        json.loads(p.read_text(encoding=\"utf-8\"))\n        return True\n    except (OSError, json.JSONDecodeError):\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    state = ReportState(run_dir)\nexcept RuntimeError as exc:\n    if \"vulnerabilities.json\" in str(exc) and \"corrupt\" in str(exc):\n        # operator decision required — do NOT auto-delete; prior MDs are at stake\n        raise\n    raise","preventionTips":["Never construct a fresh ReportState over a run dir with a corrupt vulnerabilities.json — the error exists to prevent overwriting saved MDs.","Back up the run dir before inspecting or repairing artifacts.","Avoid killing scans mid-write; let them finish or use the supported stop mechanism."],"tags":["state","json","corruption","report","resume"],"backgroundTag":null,"analyzedSha":"85513391305171ecc6faffe03da4a8bda5e3febb","analyzedAt":"2026-08-15T05:03:57.275Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}