{"record":{"id":"54536efd97e6cd8d","repo":"Graphify-Labs/graphify","slug":"cannot-read-graph-file-path-exc-re-run-grap","errorCode":null,"errorMessage":"Cannot read graph file {path}: {exc}. Re-run 'graphify extract' to regenerate it.","messagePattern":"Cannot read graph file (.+?): (.+?)\\. Re-run 'graphify extract' to regenerate it\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"graphify/affected.py","lineNumber":293,"sourceCode":"            # The relation SITE in this node's file (call/import/reference line),\n            # labeled by [via_relation] so it's never mistaken for a def line.\n            location = f\"{hit.via_file or data.get('source_file') or '-'}:{hit.via_location}\"\n        else:\n            location = _format_location(data)  # honest fallback: the node's own def line\n        lines.append(\n            f\"- {_node_label(graph, hit.node_id)} [{hit.via_relation}] {location}\"\n        )\n    return \"\\n\".join(lines)\n\n\ndef load_graph(path: Path) -> nx.Graph:\n    import json\n    from networkx.readwrite import json_graph\n\n    try:\n        raw = json.loads(path.read_text(encoding=\"utf-8\"))\n    except (json.JSONDecodeError, OSError) as exc:\n        raise RuntimeError(\n            f\"Cannot read graph file {path}: {exc}. \"\n            \"Re-run 'graphify extract' to regenerate it.\"\n        ) from exc\n    # Force directed so stored caller→callee direction survives the round-trip;\n    # mirrors serve.py and __main__.py (#1174).\n    raw = {**raw, \"directed\": True}\n    # Normalize the edge key: graphify's `extract` output uses \"edges\" while\n    # networkx's node_link_data default is \"links\". Without this, an edges-keyed\n    # graph.json raises an uncaught KeyError: 'links' here — every other loader\n    # (__main__.py) already normalizes this (#738; same class as #1198).\n    if \"links\" not in raw and \"edges\" in raw:\n        raw = dict(raw, links=raw[\"edges\"])\n    try:\n        return json_graph.node_link_graph(raw, edges=\"links\")\n    except TypeError:\n        return json_graph.node_link_graph(raw)\n","sourceCodeStart":275,"sourceCodeEnd":310,"githubUrl":"https://github.com/Graphify-Labs/graphify/blob/7fe58b0b0f3873be9a21c30106b8b8527c353aa6/graphify/affected.py#L275-L310","documentation":"The #479 shrink-guard in the Windows variant of the export step (tools/skillgen/expected/graphify__skill-windows.md:459). to_json() refuses to overwrite an existing graphify-out/graph.json that has more nodes than the newly built graph, returns False, and the script exits 1 with the '--force' hint. The report and analysis sidecar are only written after a successful graph write, keeping all artifacts consistent (#1392).","triggerScenarios":"The PowerShell pipeline rebuilt a graph with fewer nodes than what is stored in the existing graphify-out/graph.json — e.g. an incremental update after files were deleted, a partial extraction that skipped files, or an old graph.json from a larger corpus still sitting in graphify-out/.","commonSituations":"graphify update after pruning the codebase; stale output directory from a previous project or branch with more files; PowerShell path handling causing a subset of files to be scanned; switching the target path without clearing graphify-out/.","solutions":["If the corpus legitimately shrank, re-run a full build with --force so the smaller graph intentionally replaces graph.json.","Otherwise diagnose the node-count regression: compare len(nodes) in the existing graph.json with the new G.number_of_nodes(); check .graphify_detect.json for skipped files.","Verify the INPUT_PATH used by the PowerShell run matches the original full-build path.","If graphify-out is inherited/stale, delete it and rebuild from scratch."],"exampleFix":"# before\n& (Get-Content graphify-out\\.graphify_python) graphify update .\n# ERROR: refused to shrink ... (#479)\n\n# after\n& (Get-Content graphify-out\\.graphify_python) graphify build --force .","handlingStrategy":"validation","validationCode":"import json\nfrom pathlib import Path\n\nold = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')).get('nodes', [])\nnew = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding='utf-8')).get('nodes') or []\nif len(new) < len(old):\n    print(f'shrink detected {len(old)} -> {len(new)}: use --force full rebuild if intentional')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat any drop in node count as a signal to audit skipped files before exporting.","Use --force full rebuild after intentional corpus deletions.","Keep one graphify-out/ per repository and per INPUT_PATH base.","Record the node count of the last successful build and compare on every update."],"tags":["graphify","windows","shrink-guard","export","data-integrity"],"backgroundTag":null,"analyzedSha":"7fe58b0b0f3873be9a21c30106b8b8527c353aa6","analyzedAt":"2026-08-14T19:23:21.323Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}