# Common Debugging Approaches for Graph Build Failures and Parsing Errors in Code-Review-Graph

> Fix code-review-graph build failures. Learn common debugging approaches for parsing errors, graph issues, and malformed objects. Diagnose with parser probes and SQLite.

- Repository: [Tirth Kanani/code-review-graph](https://github.com/tirth8205/code-review-graph)
- Tags: how-to-guide
- Published: 2026-07-20

---

**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`](https://github.com/tirth8205/code-review-graph/blob/main/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:

```python
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:

```python
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:

```bash
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:

```bash
rm -rf ~/.code-review-graph/*.db

```

## Inspect SQLite Schema and Intermediate Rows

When `GraphStore.store_file_nodes_edges` in [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/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:

```bash
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:

```sql
-- 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:

```sql
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:

```sql
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:

```bash
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`](https://github.com/tirth8205/code-review-graph/blob/main/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`](https://github.com/tirth8205/code-review-graph/blob/main/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:

```python
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:

```sql
-- 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`](https://github.com/tirth8205/code-review-graph/blob/main/main.py) includes a debug mechanism for parsing failures. Run with minimal detail for a concise report:

```bash
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:

```bash

# 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`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/config_keys.py).

## Summary

- **Probe Tree-sitter availability** using `_PARSER_PROBE_RESULTS` and `_run_parser_load_probe` to identify missing or incompatible grammars.
- **Inspect SQLite integrity** by checking for orphaned nodes, duplicate qualified names, and invalid JSON in the `extra` column.
- **Test individual files** with `parse_file()` to isolate syntax errors and extractor bugs.
- **Resolve bare edges** by verifying import statements or manually updating the `edges` table when automatic resolution fails.
- **Use diagnostic tools** like `detect_changes_tool` to 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.