Graphify-Labs/graphify · error · ValueError

all community node IDs are stale — none exist in the graph.

Error message

all community node IDs are stale — none exist in the graph. Re-run `graphify extract .` to regenerate .graphify_analysis.json.

What it means

graphify.wiki.to_wiki() filters the communities dict against the current graph's node set before rendering, because analysis JSON can drift from G after dedup, re-extraction, or incremental updates (NetworkX 3.x returns empty DegreeViews for missing nodes instead of raising, which would crash sorted()). After filtering, if not a single node ID from the communities dict exists in G, every community became empty and the code raises this ValueError rather than clearing wiki/ for nothing. The message tells you the sidecar and the graph are fully out of sync.

Source

Thrown at graphify/wiki.py:266

    # Filter stale node IDs that exist in communities but not in G.
    # Analysis JSON can drift from the graph after dedup / re-extract / update.
    # NetworkX 3.x returns DegreeView({}) for missing nodes instead of raising,
    # which crashes sorted() with TypeError; G.neighbors()/G.nodes[] also raise.
    import sys as _sys
    _g_nodes = set(G.nodes)
    _orig_total = sum(len(ns) for ns in communities.values())
    communities = {cid: [n for n in nodes if n in _g_nodes] for cid, nodes in communities.items()}
    communities = {cid: nodes for cid, nodes in communities.items() if nodes}
    _kept_total = sum(len(ns) for ns in communities.values())
    if _kept_total < _orig_total:
        print(
            f"wiki: dropped {_orig_total - _kept_total} stale node ID(s) not in graph "
            f"({len(communities)} communities remaining)",
            file=_sys.stderr,
        )

    if not communities:
        raise ValueError(
            "all community node IDs are stale — none exist in the graph. "
            "Re-run `graphify extract .` to regenerate .graphify_analysis.json."
        )

    # Clear stale .md files from previous runs to prevent orphan accumulation.
    # Community labels are LLM-generated (per skill.md Step 5) and non-deterministic
    # across runs — the same conceptual community may be named differently each time
    # (e.g. "AutoAgent Skills" → "AutoAgent Methodology"), leaving the previous file
    # as an orphan. Since to_wiki() owns wiki/ entirely (always writes the full set),
    # it can safely clear .md files at the start of each call.
    for old_article in out.glob("*.md"):
        old_article.unlink()

    labels = community_labels or {cid: f"Community {cid}" for cid in communities}
    cohesion = cohesion or {}
    god_nodes_data = god_nodes_data or []

    # Build node->community lookup once; node attrs never carry community (it lives in

View on GitHub (pinned to 7fe58b0b0f)

Solutions

  1. Re-run `graphify extract .` to regenerate .graphify_analysis.json so its node IDs match the current graph
  2. If artifacts came from different runs, do a clean full rebuild (delete graphify-out/ sidecars first) so graph.json and .graphify_analysis.json are produced by the same extraction
  3. If you build G yourself, confirm you are loading the same graph.json the communities were clustered from (check node-count and a sample node ID against set(G.nodes))

Example fix

# before
G = load_graph('graphify-out/graph.json')
communities = json.loads(Path('graphify-out/.graphify_analysis.json').read_text())['communities']
to_wiki(G, communities, 'graphify-out/wiki')  # ValueError: all stale

# after
import subprocess, sys
_g_nodes = set(G.nodes)
_ids = {n for ns in communities.values() for n in ns}
if not _ids & _g_nodes:
    sys.exit('analysis JSON fully stale — re-run `graphify extract .`')
to_wiki(G, communities, 'graphify-out/wiki')
Defensive patterns

Strategy: validation

Validate before calling

analysis = json.loads(Path('graphify-out/.graphify_analysis.json').read_text(encoding='utf-8'))
communities = analysis['communities']
_g_nodes = set(G.nodes)
_known = {n for members in communities.values() for n in members} & _g_nodes
if not _known:
    raise SystemExit('analysis JSON is fully stale — re-run `graphify extract .` before to_wiki')

to_wiki(G, communities, 'graphify-out/wiki')

Type guard

def communities_match_graph(communities: dict, G) -> bool:
    """True when at least one community node ID exists in G."""
    nodes = set(G.nodes)
    return any(n in nodes for members in communities.values() for n in members)

Try / catch

try:
    to_wiki(G, communities, 'graphify-out/wiki')
except ValueError as e:
    if 'stale' in str(e):
        raise SystemExit('sidecar and graph are out of sync — full re-extract required') from e
    raise

Prevention

When it happens

Trigger: Calling to_wiki(G, communities) where every node ID listed in communities is absent from G.nodes — e.g. G was rebuilt from scratch (new stable node IDs/hashes) while .graphify_analysis.json still holds node IDs from an older extraction; or node dedup renamed/merged all old IDs. A stderr warning ('wiki: dropped N stale node ID(s)…') precedes the raise.

Common situations: Re-running `graphify extract .` after large refactors or file renames, then feeding the fresh graph together with a stale .graphify_analysis.json from a previous run; mixing artifacts from a full build and an incremental --update run.

Related errors


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