Skip to content

Troubleshooting & FAQ

The API exits with “Set DATABASE_URL and QUERYPILOT_ENCRYPTION_KEY”

Section titled “The API exits with “Set DATABASE_URL and QUERYPILOT_ENCRYPTION_KEY””

Both are required. With Docker Compose, DATABASE_URL is assembled for you; set QUERYPILOT_ENCRYPTION_KEY in .env (openssl rand -base64 32). The key must decode to 32 bytes from base64 or hex.

“Invalid environment configuration” or “Invalid QueryPilot configuration”

Section titled ““Invalid environment configuration” or “Invalid QueryPilot configuration””

A variable could not be parsed (for example API_PORT=eighty) or a value is out of range. The message lists every offending setting. Booleans accept true/false, 1/0, yes/no and on/off.

NEXT_PUBLIC_API_URL must be the API URL as reachable from your browser, and the web app’s origin must be listed in QUERYPILOT_CORS_ORIGINS.

The extension must be preloaded (requires a restart) and created in the observed database:

CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

With the bundled Compose PostgreSQL, the extension is created only when the data volume is first initialized. An older volume needs the CREATE EXTENSION by hand.

pg_stat_statements is installed but not readable

Section titled “pg_stat_statements is installed but not readable”

The role can see that the extension exists but is not allowed to read it. Grant pg_read_all_stats.

Only the monitoring role’s own queries appear

Section titled “Only the monitoring role’s own queries appear”

Also pg_read_all_stats: without it, other roles’ statements are hidden.

“Multiple projects exist, so projectId is required.”

Section titled ““Multiple projects exist, so projectId is required.””

QueryPilot attaches new databases to the only project when there is exactly one. If several exist, pass projectId when registering the database through the API.

Check its readiness endpoint, which states exactly what is wrong:

Terminal window
curl -s http://<agent-host>:8082/health/ready
Check Value Fix
configuration a list of problems Set QUERYPILOT_API_URL, QUERYPILOT_AGENT_TOKEN, QUERYPILOT_TARGET_DATABASE_URL.
database unreachable Check the connection string, network path and the role’s CONNECT privilege.
api not registered The API cannot be reached yet; check QUERYPILOT_API_URL and egress rules.
api token rejected The token is wrong, rotated or revoked. Rotate it in the UI and update the agent.

No heartbeat has arrived for three heartbeat intervals (90 seconds by default). The agent process is down, or it can no longer reach the API.

The agent is DEGRADED, or the Agents panel lists collector errors

Section titled “The agent is DEGRADED, or the Agents panel lists collector errors”

One or more collectors are failing, usually because of a missing privilege for one system view. The other collectors keep running. Run Test connection on the database for a remediation.

“Waiting for telemetry — start the agent to begin collecting.”

Section titled ““Waiting for telemetry — start the agent to begin collecting.””

Nothing has been collected for this database yet. Create and start an agent.

Telemetry exists, but the selected time range contains no executions. Pick a longer range.

A gap means nothing was collected (or nothing executed) in that bucket. QueryPilot deliberately never draws those buckets as zero.

pg_stat_statements counters were reset (for example by pg_stat_statements_reset() or a server restart). QueryPilot detects the reset and does not count it as a negative delta.

pg_stat_statements does not record individual executions, so p50/p95/p99 are estimated from each interval’s exact mean and variance. The mean is exact.

“Plan capture is not supported for this database”

Section titled ““Plan capture is not supported for this database””

Plan capture needs PostgreSQL 16 or newer (for EXPLAIN (GENERIC_PLAN)) and a readable pg_stat_statements. You can still upload plans.

The reason is shown on the request. Common ones:

Message Meaning
Only SELECT statements are planned by the agent. Capture is limited to single SELECT statements.
The text contains more than one statement. Refused for safety.
This is a monitoring query, not application workload. Queries against statistics views are skipped.
No PostgreSQL queryid is recorded for this query yet. Wait for the next query-stats collection.
The query is no longer in pg_stat_statements. The entry was evicted or reset.
canceling statement due to lock timeout A stronger lock (such as a migration) held a table; the agent gave up after 100 ms rather than queue.
permission denied for table … The monitoring role cannot read a table the query uses.

A request stays EXPIRED when no agent picks it up in time. Check that an agent is online for the database.

Does QueryPilot write to my database? No. Sessions are read-only at the PostgreSQL level, and plan capture runs in a read-only transaction that is rolled back.

Does it need a superuser? No. pg_read_all_stats plus CONNECT is enough for everything except planning queries against tables the role cannot read.

Does it run EXPLAIN ANALYZE? Never automatically. You can upload EXPLAIN ANALYZE output you produced yourself.

How much load does the agent add? Two connections at most, collector queries capped in rows and time, and default intervals of 5 s to 60 s. The agent measures its own collection time and exposes it on /metrics.

Which PostgreSQL versions are supported? 12 and newer; plan capture needs 16+.

Does any data leave my infrastructure? No. There is no phone-home telemetry, and every optional integration is off by default.

Is there authentication? Not yet; it is on the roadmap. Deploy on a trusted network.

Does it support MySQL or other databases? No, QueryPilot is PostgreSQL-only.