# Troubleshooting Use this page to map symptoms to status checks and recovery actions. ## Graph Not Built Symptom: ```text SQLSTATE PG003 Graph not built. Call graph.build() first. ``` Check: ```sql SELECT node_count, edge_count, schema_status, invalid_reason FROM graph.status(); ``` Fix: ```sql SELECT * FROM graph.build(); ``` ## Node Not Found Symptom: ```text SQLSTATE PG010 Node not found ``` Check: ```sql SELECT * FROM graph.search('id', 'expected_id', table_filter := 'public.my_table'::regclass, mode := 'exact'); SELECT * FROM graph.registered_tables(); ``` Likely causes: | Cause | Fix | |---|---| | Wrong table or ID string | Use exact source primary-key text | | Composite ID mismatch | Use JSON array text encoding from `graph.node_ref_string()` patterns | | Source row added after build | `graph.apply_sync()` or `graph.build()` | | Source row deleted/tombstoned | Rebuild or query another active node | ## Search Returns No Rows Check that the column is registered in `graph.add_table(..., columns := ...)`: ```sql SELECT * FROM graph.registered_tables() WHERE table_name = 'public.users'; ``` Then test exact mode and table filter: ```sql SELECT * FROM graph.search( 'name', 'Alice', table_filter := 'public.users'::regclass, mode := 'exact', hydrate := true ); ``` Search uses source-table SQL, so source table indexes matter. Add normal PostgreSQL indexes for high-volume searched columns. ## Traversal Returns Too Few Rows Check: ```sql SELECT * FROM graph.status(); SELECT * FROM graph.traverse( 'public.users'::regclass, 'u1', max_depth := 1, edge_types := NULL, direction := 'any', hydrate := false, max_nodes := 100000, max_frontier := 100000 ); ``` Likely causes: | Cause | Fix | |---|---| | `max_depth` too low | Increase `max_depth` | | `edge_types` filter excludes edges | Remove filter or inspect `edge_types` in `graph.status()` | | `direction` wrong for unidirectional edges | Use `out`, `in`, or register bidirectional edges | | `max_nodes` or `max_frontier` trips | Raise circuit breakers for trusted query | | Tenant scope excludes nodes | Pass correct `tenant` or session tenant | | Filter column not registered/rebuilt | Register filter column and rebuild | ## Unsupported Operation With Pending Overlays Symptom: ```text SQLSTATE PG018 Unsupported graph operation ``` Likely cause: | Cause | Fix | |---|---| | `graph.weighted_shortest_path()` ran while `edge_buffer_used > 0` | Run `graph.vacuum()` or `graph.maintenance()` to merge pending edge overlays, then retry | Unweighted traversal, unweighted shortest path, and connected components include pending edge overlays after `graph.apply_sync()`. Weighted shortest path fails closed while overlays are pending because pending edge mutations do not carry edge weights. ## Schema Invalid Or Needs Rebuild Symptoms: ```sql SELECT schema_status, needs_rebuild, invalid_reason FROM graph.status(); ``` Fix after catalog or source schema changes: ```sql SELECT * FROM graph.registered_tables(); SELECT * FROM graph.registered_edges(); SELECT * FROM graph.build(); ``` If a registered column no longer exists, remove or update the registration. ## Build Fails With Memory Error Symptom: `PG001`. Check: ```sql SELECT * FROM graph.estimate(); SHOW graph.memory_limit_mb; SHOW graph.oom_action; ``` Fix: ```sql ALTER SYSTEM SET graph.memory_limit_mb = 8192; SELECT pg_reload_conf(); ``` Or reduce registered graph scope. ## Build Or Vacuum Locked Symptom: `PG006`. Check: ```sql SELECT pid, state, query FROM pg_stat_activity WHERE query ILIKE '%graph.build%' OR query ILIKE '%graph.vacuum%' OR query ILIKE '%graph.maintenance%'; ``` Wait for the current operation or investigate the owning session. ## Corrupt Or Incompatible Artifact Symptoms: `PG009` or `PG011`. Fix: ```sql SELECT * FROM graph.build(); ``` If needed: ```sql SELECT graph.reset(); SELECT * FROM graph.build(); ``` ## Edge Buffer Full Symptom: `PG008`, `PG012`, `read_only = true`, or high `edge_buffer_used`. Check: ```sql SELECT edge_buffer_used, needs_vacuum, read_only, read_only_reason FROM graph.status(); ``` Fix: ```sql SELECT * FROM graph.maintenance(); ``` or: ```sql SELECT * FROM graph.vacuum(); ``` ## ACL Denied Symptom: `PG002`. Fix for read queries: ```sql GRANT SELECT ON public.source_table TO app_role; ``` Fix for admin operations: ```sql GRANT USAGE, CREATE ON SCHEMA graph TO graph_admin; ``` ## Operational Failure Matrix Use this matrix when diagnosing complex production failures relating to jobs, quotas, sync, or storage. | Failure | Stable state | SQLSTATE | Visible location | Recovery action | Read impact | |---|---|---|---|---|---| | **Sync falls behind** | `sync_status = 'syncing'`, `sync_lag > 0` | `PG018` if the lag surfaces as a read-only guard | `graph.status().sync_lag`, `graph.status().pending_sync_rows`, `graph.jobs()` | Run `graph.run_due_jobs()` or `graph.run_job(job_id)` after confirming the source tables are healthy. | Serves the last valid generation. | | **Artifacts are missing** | `graph.projection_status().artifact_validation_state = 'full_rebuild'` | `PG009` | `graph.status().schema_status`, `graph.projection_status().artifact_validation_state` | Run `graph.projection_repair()` or `graph.build()` to publish a fresh artifact. | Reads fail on affected paths until rebuilt. | | **Artifact validation fails** | `graph.projection_status().artifact_validation_state = 'targeted_chunk_repair'` | `PG009` | `graph.projection_status().artifact_validation_state` | Run `graph.projection_repair()`; if repair cannot salvage the files, rebuild. | Reads fail on affected paths until repaired. | | **Disk is full** | `read_only_reason` indicates storage pressure | `53100` | `graph.status().read_only_reason`, `graph.job_runs()` | Free space, then rerun `graph.run_due_jobs()` or `graph.projection_repair()`. | Serves the last valid generation. | | **Compaction fails** | `graph.projection_status().artifact_validation_state = 'targeted_chunk_repair'` after a failed compaction run | `PG018` | `graph.projection_status().last_compaction_unix_micros`, `graph.job_runs()` | Fix the underlying artifact problem and rerun `graph.projection_repair()` or `graph.maintenance()`. | Serves the last valid generation. | | **Projection ingest fails** | `pending_durable_rows > 0` and `repair_recommended = true` | `PG018` | `graph.projection_status().pending_durable_rows`, `graph.projection_status().repair_recommended` | Repair the projection artifact, then rerun the ingest path. | Serves the last valid generation. | | **A job repeatedly errors** | `graph.jobs().last_status = 'retryable_failed'` or `graph.jobs().last_status = 'permanent_failed'` | `XX000` or a more specific job SQLSTATE | `graph.jobs()`, `graph.job_runs()` | Inspect the most recent run error, correct the source issue, and rerun the job. | Depends on job type. | | **A graph exceeds quota** | `graph.graph_quota_usage().exceeded = true` | `PG019` | `graph.graph_quota_usage()` | Raise the quota or shrink graph scope/storage. | New writes, builds, or loads can be blocked. | | **Background workers unavailable** | `graph.jobs().last_status = 'queued'` | N/A | `graph.jobs()`, `graph.job_runs()` | Restore worker capacity, then run `graph.run_due_jobs()` manually. | Serves the last valid generation. | | **Schema/catalog drift** | `schema_status = 'invalid'` and `needs_rebuild = true` | `PG018` | `graph.status().schema_status`, `graph.status().needs_rebuild` | Run `graph.build()` for the selected graph. | Reads fail on affected paths until rebuilt. | ## Heavy Validation Commands Run focused external checks when debugging release-class issues: ```bash cd graph PG_VERSION_FEATURE=pg17 DBNAME=pggraph_boundary ./tests/heavy/run_sqlstate_acl_boundary.sh PG_VERSION_FEATURE=pg17 DBNAME=pggraph_concurrency CLIENTS=3 ROUNDS=3 ./tests/heavy/concurrency_stress.sh PG_VERSION_FEATURE=pg17 DBNAME=pggraph_install ./tests/heavy/fresh_install_smoke.sh ```