Graphify-Labs/graphify · error · SystemExit
ERROR: Graph is empty - extraction produced no nodes.
Error message
ERROR: Graph is empty - extraction produced no nodes.
What it means
Fail-fast guard (#1392) in the graphify build pipeline: after build_from_json(extraction, root='INPUT_PATH', directed=IS_DIRECTED) reconstructs the graph from graphify-out/.graphify_extract.json, a zero-node result aborts with SystemExit(1) before graph.json, GRAPH_REPORT.md, or the analysis sidecar are touched. This protects existing artifacts from being overwritten by an empty graph.
Source
Thrown at tools/skillgen/expected/graphify__skill-droid.md:416
from graphify.build import build_from_json
from graphify.cluster import cluster, score_all
from graphify.analyze import god_nodes, surprising_connections, suggest_questions
from graphify.report import generate
from graphify.export import to_json
from pathlib import Path
extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
detection = json.loads(Path('graphify-out/.graphify_detect.json').read_text(encoding=\"utf-8\"))
# root= mirrors the --update runbook (#1361): relativize source_file to the same
# base so the full build and incremental --update never drift apart on re-extract.
G = build_from_json(extraction, root='INPUT_PATH', directed=IS_DIRECTED)
# Guard BEFORE any write: an empty extraction must not clobber a good graph.json /
# GRAPH_REPORT.md / analysis sidecar. Check immediately after build (#1392).
if G.number_of_nodes() == 0:
print('ERROR: Graph is empty - extraction produced no nodes.')
print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.')
raise SystemExit(1)
communities = cluster(G)
cohesion = score_all(G, communities)
tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)}
gods = god_nodes(G)
surprises = surprising_connections(G, communities)
labels = {cid: 'Community ' + str(cid) for cid in communities}
# Placeholder questions - regenerated with real labels in Step 5
questions = suggest_questions(G, communities, labels)
# Export FIRST and honor the #479 shrink-guard: to_json returns False (writing
# nothing) when the new graph is smaller than the existing graph.json. Only write
# GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so
# they never describe a graph that graph.json doesn't contain (#1392).
wrote = to_json(G, communities, 'graphify-out/graph.json')
if not wrote:
print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).')
print('If this shrink is intentional (you deleted files), re-run a full build with --force.')
raise SystemExit(1)View on GitHub (pinned to 7fe58b0b0f)
Solutions
- Inspect graphify-out/.graphify_extract.json for node content; empty means the failure is upstream in extraction.
- Make sure INPUT_PATH equals the root used during extraction so source_file relativization keeps every node.
- Review extractor skip/ignore rules for over-broad matches.
- Re-run extraction, then this build step — prior artifacts are preserved by the guard.
Example fix
# before: zero nodes abort the build
G = build_from_json(extraction, root='INPUT_PATH', directed=IS_DIRECTED)
if G.number_of_nodes() == 0:
print('ERROR: Graph is empty - extraction produced no nodes.')
raise SystemExit(1)
# after: pre-validate extraction payload and root agreement
files = extraction.get('files', [])
assert files and any(f.get('nodes') for f in files), 'nothing extracted - fix extraction step first'
G = build_from_json(extraction, root='INPUT_PATH', directed=IS_DIRECTED)
assert G.number_of_nodes() > 0 Defensive patterns
Strategy: validation
Validate before calling
import json
from pathlib import Path
extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding='utf-8'))
files = extraction.get('files', [])
assert files and any(f.get('nodes') for f in files), 'empty extraction - fix upstream before build'
G = build_from_json(extraction, root='INPUT_PATH', directed=IS_DIRECTED)
assert G.number_of_nodes() > 0, 'root mismatch or empty extract produced 0 nodes' Prevention
- Pre-validate the extraction sidecar for non-empty nodes before building.
- Pass the same root= to build_from_json as the extraction step used.
- Monitor extraction skip counts to catch all-files-skipped runs early.
- Keep input directories populated with extractable text files.
When it happens
Trigger: build_from_json() yielding G.number_of_nodes() == 0 because the extract file contains no nodes — all files skipped, binary-only corpus, or failed extraction. The root='INPUT_PATH' relativization can also drop every node if INPUT_PATH disagrees with the paths stored in the extract.
Common situations: Empty or truncated .graphify_extract.json after an extraction API failure; input dir with only skipped file types; ignore rules matching everything; INPUT_PATH mismatch with the extraction-time root.
Related errors
- ERROR: Graph is empty - extraction produced no nodes.
- ERROR: Graph is empty - extraction produced no nodes.
- ERROR: Graph is empty - extraction produced no nodes.
- ERROR: Graph is empty - extraction produced no nodes.
- ERROR: Graph is empty - extraction produced no nodes.
AI-assisted analysis of Graphify-Labs/graphify@7fe58b0b0f (2026-08-14).
Data as JSON: /api/errors/8ad8f05fbe0de0b6.
Report an issue: GitHub.