Repository navigation
graphify tree renders an empty viewer on any merged graph — merge-graphs drops source_file from every node #4522
Description
graphify tree renders an empty viewer on any merged graph — merge-graphs drops source_file from every node
Summary
graphify merge-graphs produces a merged graph.json whose nodes carry src/source but no source_file. graphify tree filters on source_file (tree_html.py build_tree: file_nodes = [n for n in nodes if n.get("source_file")]), so running tree against a merged graph — the primary cross-repo use case for merge-graphs — always produces the "(empty graph)" viewer: title (empty graph) — graphify tree viewer, 15 KB output, zero hierarchy.
Reproduction (graphify 0.9.92, Ubuntu 22.04, Python 3.12)
# two normal per-repo extractions — both carry source_file:
$ graphify extract repo-a --code-only && graphify extract repo-b --code-only
$ python3 -c "import json; g=json.load(open('repo-a/graphify-out/graph.json')); \
print(sum(1 for n in g['nodes'] if n.get('source_file')), '/', len(g['nodes']))"
3248 / 3461 # fine
# merge them:
$ graphify merge-graphs repo-a/graphify-out/graph.json repo-b/graphify-out/graph.json --out world/graphify-out/graph.json
$ python3 -c "import json; g=json.load(open('world/graphify-out/graph.json')); \
print(sum(1 for n in g['nodes'] if n.get('source_file')), '/', len(g['nodes']))"
0 / 3607 # source_file gone on every node
$ graphify tree --graph world/graphify-out/graph.json --output WORLD_TREE.html
$ grep -o "<title>[^<]*</title>" WORLD_TREE.html
<title>(empty graph) — graphify tree viewer</title>Merged node shape after the merge (attrs renamed, source_file dropped):
{"id": "src_engine_dashboard_corvusdashboard_physicsbody", "label": "PhysicsBody",
"type": "code", "community": 25, "community_name": "Dashboard Physics Engine",
"src": "src/engine/dashboard/CorvusDas...", "origin": "ast", "source": "corvus-colony"}Per-repo input node shape (what tree_html needs):
{"id": "...", "label": "PhysicsBody", "_callable": true, ..., "source_file": "src/engine/dashboard/...", ...}Expected
graphify tree on a merged graph shows the full cross-repo hierarchy (repo-tag roots → dirs → symbols), the same way it does for a single-repo graph. Either:
- merge-graphs preserves
source_file(repo-relative, as inputs store it), or build_treefalls back tosrc/sourcewhensource_fileis absent.
Workaround we're running
Re-derive source_file from src post-merge, then run tree without --root (paths are repo-relative so an absolute --root matches 0/134 files and raises):
for n in g["nodes"]:
if not n.get("source_file") and (n.get("src") or n.get("source")):
n["source_file"] = str(n.get("src") or n.get("source"))After this patch the same merged graph renders a correct 259 KB tree with both repo roots.
Environment
- graphify 0.9.92 (
pip install --user graphifyy), networkx merge path vianx.compose+_prefix - Ubuntu 22.04, Python 3.12.10
- Also worth noting:
--rootwith an absolute path fails on merged graphs because stored paths are repo-relative ("error: --root ... matched 0 of 134 source files"), which compounds this — there's no way to anchor a merged tree without knowing each input's relative layout.
Real-world corpus: corvus-colony (3461 AST nodes) + semantic vault graph (164 nodes) = 3607-node merged world graph.
Activity
github-actions commentedon Oct 17, 2026
Thanks for opening this issue, @jessework840. A maintainer will take a look soon.
If you would like to discuss it in real time, come say hi on our Discord server. For longer-form questions and ideas there is also GitHub Discussions.
To help us triage, please make sure the report includes what you expected, what actually happened, and the steps (and a small sample) to reproduce it.
fix(tree): one root per repo on merged graphs; refuse graphs with no …
Deepjyoti-Sarmah commentedon Oct 18, 2026
I couldn't reproduce this on 0.9.92.
merge-graphskeptsource_fileon every node: 6 of 6 and 5 of 5 in two small repos, and 11 of 11 after the merge. The PyPI wheel for 0.9.92 is the same code as the tag, so this is the version you ran.I also merged three real graphs built by 0.9.90 and older (23,712 nodes): all 23,036 nodes that had
source_filestill had it after the merge.Your merged node also doesn't match what
merge-graphswrites. It prefixes every id with the repo (corvus-colony::src_engine_...) and addsrepoandlocal_id. Your node has no prefix, hastype,originandsrcwhere graphify writesfile_type,_originandsource_file, and its path ends in.... Nothing in graphify writes those keys, so I think something in your pipeline rewrote the graph after the merge.Two things would settle it:
world/graphify-out/graph.json.head -c 800 world/graphify-out/graph.json, run right aftermerge-graphs.About
--root: it takes a repo-relative path, becausesource_fileis stored that way. An absolute path that matches nothing is refused on purpose (#2534).There is a real tree bug on merged graphs: when two repos both have
src/main.py, the viewer fuses them into one file. That's #4524, and #4541 and #4525 both fix it. #4541 also turns a graph with nosource_fileinto an error instead of a blank viewer.