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

A fail-fast guard (#1392) in the graphify build script: right after G = build_from_json(extraction, directed=IS_DIRECTED), the script aborts with SystemExit(1) if the graph has zero nodes. It exists so a botched or empty extraction can never clobber an existing good graph.json / GRAPH_REPORT.md / analysis sidecar. Note this devin variant calls build_from_json without the root= parameter used by the other skill variants.

Source

Thrown at tools/skillgen/expected/graphify__skill-devin.md:477

$(cat graphify-out/.graphify_python) -c "
import sys, json
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())
detection  = json.loads(Path('graphify-out/.graphify_detect.json').read_text())

G = build_from_json(extraction, 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)

# Persist the graph first and only write the report/analysis if it actually
# persisted - to_json refuses to shrink an existing graph.json (#479), and a
# report describing a graph we did not write would be a lie (#1392).
wrote = to_json(G, communities, 'graphify-out/graph.json')
if not wrote:
    print('ERROR: refused to shrink graphify-out/graph.json (fewer nodes than the existing graph). Run a full rebuild to be safe.')
    raise SystemExit(1)
report = generate(G, communities, cohesion, labels, gods, surprises, detection, tokens, 'INPUT_PATH', suggested_questions=questions)
Path('graphify-out/GRAPH_REPORT.md').write_text(report)

View on GitHub (pinned to 7fe58b0b0f)

Solutions

  1. Inspect graphify-out/.graphify_extract.json — if it has no nodes, fix and re-run the extraction step, not this one.
  2. Verify the input path actually contains extractable text/code files.
  3. Check extractor skip rules (binary extensions, ignore globs) for over-matching.
  4. Re-run extraction then this build step; previous outputs remain intact thanks to the guard.

Example fix

# before: empty extraction aborts before any write
G = build_from_json(extraction, directed=IS_DIRECTED)
if G.number_of_nodes() == 0:
    print('ERROR: Graph is empty - extraction produced no nodes.')
    raise SystemExit(1)

# after: validate the extract payload first
assert extraction.get('files'), 'extract has no files - re-run extraction step'
G = build_from_json(extraction, directed=IS_DIRECTED)
assert G.number_of_nodes() > 0, 'extract produced 0 nodes - check skip rules / input path'
Defensive patterns

Strategy: validation

Validate before calling

import json
from pathlib import Path

extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text())
files = extraction.get('files', [])
if not files or not any(f.get('nodes') for f in files):
    raise SystemExit('extraction empty - re-run extraction before building')
G = build_from_json(extraction, directed=IS_DIRECTED)
assert G.number_of_nodes() > 0, 'build produced 0 nodes'

Prevention

When it happens

Trigger: build_from_json() producing an empty graph from graphify-out/.graphify_extract.json — all files skipped by the extractor, a binary-only corpus, or a failed extraction pass that wrote no nodes.

Common situations: Extraction API failure leaving an empty extract file; input directory containing only skipped file types; over-aggressive ignore rules; wrong working directory so the extract file read is empty or from another project.

Related errors


AI-assisted analysis of Graphify-Labs/graphify@7fe58b0b0f (2026-08-14). Data as JSON: /api/errors/fd4a6464023fa253. Report an issue: GitHub.