Common Debugging Approaches for Graph Build Failures and Parsing Errors in Code-Review-Graph
Graph build failures in code-review-graph typically stem from missing Tree-sitter grammars, malformed NodeInfo/EdgeInfo objects, or unresolved bare call endpoints, all of which can be diagnosed through parser probes, SQLite inspection, and targeted single-file parsing.
The code-review-graph repository constructs a multilingual code-knowledge graph by parsing source files with Tree-sitter and persisting extracted nodes and edges in a SQLite store. When the build process crashes or the parser logs warnings about unavailable grammars, developers need systematic debugging approaches to identify whether the root cause lies in parser loading, data validation, or cross-file resolution.
Verify Tree-sitter Parser Availability
The first diagnostic step targets the parser load probe in code_review_graph/parser.py. The function _parser_load_probe_succeeds (lines 78-90) determines whether a native Tree-sitter grammar can be loaded within the allotted timeout.
Inspect the Probe Cache
The module maintains a process-wide dictionary _PARSER_PROBE_RESULTS that caches availability status. Check this cache to see which languages failed initialization:
from code_review_graph.parser import _PARSER_PROBE_RESULTS
print(_PARSER_PROBE_RESULTS)
If your target language is missing or returns False, the probe failed during startup.
Run Manual Probes
Test a specific grammar directly using the internal probe runner:
from code_review_graph.parser import _run_parser_load_probe
print(_run_parser_load_probe("python", 5.0))
A True result confirms the native grammar loads successfully. False indicates one of three issues: the tree-sitter-language-pack package is not installed, the binary is incompatible with your OS/CPU architecture, or the timeout is too restrictive.
Adjust Environment Timeouts
The default timeout is 5 seconds, controlled by the CRG_PARSER_LOAD_TIMEOUT_SECONDS environment variable. On slow CI runners or resource-constrained environments, increase this value:
export CRG_PARSER_LOAD_TIMEOUT_SECONDS=15
Clear Unavailable Markers
When _mark_parser_unavailable logs a warning like Skipping unavailable tree-sitter parser for <lang>, the grammar is permanently marked unavailable for the process lifetime. To reset this state, delete the SQLite metadata entry parser_unavailable in the metadata table, or remove the entire database:
rm -rf ~/.code-review-graph/*.db
Inspect SQLite Schema and Intermediate Rows
When GraphStore.store_file_nodes_edges in code_review_graph/graph.py (lines 81-96) aborts with a transaction rollback, the issue usually involves malformed data or resource constraints.
Open and Examine the Database
The default database location is ~/.code-review-graph/graph.db or the path returned by incremental.get_db_path. Inspect the schema:
sqlite3 /path/to/graph.db ".schema"
Detect Orphaned Data
After a failed build, you may have nodes without edges or edges referencing non-existent nodes. Run these queries to find orphaned records:
-- Nodes with no outgoing edges
SELECT * FROM nodes WHERE qualified_name NOT IN (SELECT source_qualified FROM edges);
-- Edges referencing unknown sources
SELECT * FROM edges WHERE source_qualified NOT IN (SELECT qualified_name FROM nodes);
Identify Duplicate Qualified Names
Duplicate qualified_name values trigger the ON CONFLICT(qualified_name) DO UPDATE clause, potentially overwriting data silently. Detect duplicates with:
SELECT qualified_name, COUNT(*) c
FROM nodes
GROUP BY qualified_name
HAVING c > 1;
Validate JSON Metadata
Language-specific extractors store metadata in the extra JSON column. Corrupted JSON raises json.JSONDecodeError and aborts transactions. Validate existing rows:
SELECT id, extra
FROM nodes
WHERE NOT json_valid(extra);
Isolate Parsing Errors with Single-File Testing
Rather than running full builds, invoke the low-level parse_file function directly to test specific files:
python -c "
from code_review_graph.parser import parse_file
from pathlib import Path
path = Path('src/example/foo.py')
node_infos, edge_infos = parse_file(path)
print('Nodes:', len(node_infos), 'Edges:', len(edge_infos))
"
If this raises a SyntaxError or returns empty structures, the bug resides in the language-specific extractor functions within parser.py.
Resolve Bare Call and Tested-By Edge Failures
When the parser cannot resolve a cross-file reference, it creates edges with bare names (e.g., target='doStuff'). The post-processing routine _resolve_bare_endpoints in graph.py (lines 111-130) attempts to qualify these, but may leave edges unchanged if no unique candidate exists.
Inspect Resolution Candidates
The resolver builds a mapping of names to (qualified_name, file_path) tuples. Check candidate availability manually:
from code_review_graph.graph import GraphStore
gs = GraphStore('/tmp/debug.db')
print(gs._resolve_bare_endpoints('CALLS', 'target_qualified'))
Verify Import Statements
Resolution only succeeds when the target appears in the same file or a file imported by the call site. Missing or mismatched import statements prevent promotion from bare names to qualified names.
Manual Edge Correction
As a last resort, update the database directly:
-- Find the bare edge
SELECT * FROM edges WHERE id=42;
-- Qualify the target manually
UPDATE edges
SET target_qualified='my.module::doStuff'
WHERE id=42;
Leverage Built-in Diagnostic Tools
The detect_changes_tool exposed via the MCP server in main.py includes a debug mechanism for parsing failures. Run with minimal detail for a concise report:
code-review-graph detect-changes --detail-level minimal
The JSON output contains a parsing_errors field listing files that failed to parse along with exception messages like SyntaxError: invalid syntax.
Execute Clean Rebuilds
When incremental debugging fails to reveal the cause, a clean rebuild guarantees consistent state:
# Remove existing database
rm -rf ~/.code-review-graph/*.db
# Re-install language pack to ensure native grammars compile
pip install -U tree-sitter-language-pack
# Full rebuild
code-review-graph build-or-update-graph --full-rebuild
Monitor output for Skipping unavailable tree-sitter parser warnings. Either install missing grammars or exclude problematic languages via EXCLUDED_LANGUAGES in code_review_graph/config_keys.py.
Summary
- Probe Tree-sitter availability using
_PARSER_PROBE_RESULTSand_run_parser_load_probeto identify missing or incompatible grammars. - Inspect SQLite integrity by checking for orphaned nodes, duplicate qualified names, and invalid JSON in the
extracolumn. - Test individual files with
parse_file()to isolate syntax errors and extractor bugs. - Resolve bare edges by verifying import statements or manually updating the
edgestable when automatic resolution fails. - Use diagnostic tools like
detect_changes_toolto surface parsing errors without full builds. - Perform clean rebuilds after clearing the database and reinstalling language packs to eliminate corrupted state.
Frequently Asked Questions
Why does the parser skip certain languages with "unavailable" warnings?
The warning indicates that _parser_load_probe_succeeds returned False for that language, usually because the Tree-sitter grammar binary is missing, corrupted, or incompatible with your platform. Install tree-sitter-language-pack or increase CRG_PARSER_LOAD_TIMEOUT_SECONDS if the grammar loads slowly.
How do I fix orphaned nodes and edges in the SQLite database?
Orphaned records occur when transactions abort midway through store_file_nodes_edges. Query for nodes without matching edges and vice versa, then either delete the orphans or re-parse the affected files to restore referential integrity.
What causes bare call edges to remain unresolved after building?
Bare edges persist when _resolve_bare_endpoints cannot find a unique candidate for the target name. This happens if the target file lacks an import statement linking it to the call site, or if multiple candidates exist with ambiguous naming. Ensure proper imports exist or manually qualify the edge in the database.
How can I increase the parser timeout for slow CI environments?
Set the CRG_PARSER_LOAD_TIMEOUT_SECONDS environment variable to a value higher than the default 5 seconds before running the build. For example, export CRG_PARSER_LOAD_TIMEOUT_SECONDS=15 allows grammars 15 seconds to initialize, preventing premature timeouts on resource-constrained runners.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →