Querion / Guides
Troubleshooting
Fix common Querion problems: config errors, Claude Code CLI failures, refused queries, allowlist refusals, missing charts and the daily cap.
On this page
- Where problems come from
- Config and environment
- error: Config not found at 'querion.yaml'
- got an unexpected keyword argument or missing 1 required positional argument
- A ${VAR} value is empty or wrong
- The Claude Code CLI
- querion check reports the claude CLI as NOT FOUND
- claude CLI not found
- claude CLI failed (exit N): ... or claude returned an error: ...
- claude CLI timed out after 200s
- Database
- querion check reports database as ERROR
- querion check says ok (read-only), but is the role read-only?
- The model uses table or column names that do not exist
- A harmless query keeps being refused
- Queries are cancelled for taking too long
- HTTP sources
- Refused: '/path' is not on the 'NAME' safe-read allowlist...
- unknown source 'NAME'. Configured: ...
- The API answers HTTP 401 or HTTP 403
- NAME GET failed: ...
- The answer seems to use only part of a response
- Answers and charts
- The answer is (no answer)
- The answer starts with Something broke while analysing:
- The answer stops early or looks partial
- Charts do not show in the terminal
- The SQL in a terminal answer is not exactly what ran
- Web server
- No module named 'uvicorn' or fastapi and uvicorn are required
- Daily limit reached. Resets in ... (00:00 UTC). (HTTP 429)
- The page loads but is blank, or charts are missing
- Polling returns {"error": "unknown run"} (HTTP 404)
- Several questions at once slow the host
- Limits you will hit
Each entry starts with the message or symptom you see, taken from the code, then the cause and the fix.
Where problems come from
A question passes through four things, in order: the config file, the Claude Code command-line interface (CLI), the database connection, and the read-only checks. Most problems sit in one of them.
querion check tests the first three. It loads the config, looks for the claude binary and runs SELECT 1 on the database. Run it first. It does not test the CLI login, and it exits with code 0 even when a line reports a problem, so read its output.
When a querion command cannot run, it usually prints error: ... on standard error and exits with code 1. Errors that happen while a question runs are different: Structured Query Language (SQL) errors, refused paths and failed Hypertext Transfer Protocol (HTTP) requests to your application programming interfaces (APIs) go back to the model as the directive’s result, so you see them only if the model mentions them in its answer.
Config and environment
error: Config not found at 'querion.yaml'
Querion looks for the -c PATH flag, then the QUERION_CONFIG environment variable, then querion.yaml in the current directory. Copy the example, or point at your file. The flag goes before the subcommand:
cp querion.example.yaml querion.yaml
querion -c path/to/querion.yaml check
got an unexpected keyword argument or missing 1 required positional argument
A key inside database, limits, trove or a source block is misspelled or unknown, or a source is missing name or base_url. Those blocks map to fixed fields, so an unknown key is an error. Unknown keys at the top level are ignored without a warning. The valid keys are in the configuration reference.
A ${VAR} value is empty or wrong
- A variable that is not set becomes an empty string, with no warning. An unset
QUERION_DATABASE_DSNshows up later asno database DSN configured (database.dsn in querion.yaml). - Names may contain only uppercase letters, digits and underscores.
${my_key}is not replaced; it stays in the value as typed. - The CLI loads a
.envfile only whenpython-dotenvis installed (thedotenvorallextra). Without it, export the variables in your shell. - Interpolation always produces text. Write numbers and booleans literally in the file.
enabled: ${TROVE_ON}withTROVE_ON=falsebecomes the text"false", which Python treats as true, and a number such asrow_cap: ${ROWS}breaks every query.
The Claude Code CLI
querion check reports the claude CLI as NOT FOUND
Querion cannot find the claude binary. Install Claude Code and run claude once to log in, or set claude_bin in querion.yaml to the full path.
claude CLI not found
The same cause, reported while a question runs. The full message also says to install Claude Code and run claude once to log in, or to set claude_bin. The question ends with status error, and the answer reads Something broke while analysing: followed by this message.
claude CLI failed (exit N): ... or claude returned an error: ...
The CLI started but failed. Up to 500 characters of its error output follow the colon. Authentication lives in the home directory of the user that runs Querion, so run claude as that same user to check that it is logged in. Also check that model in querion.yaml is an alias the CLI accepts.
claude CLI timed out after 200s
Each model call has a fixed 200-second limit. The whole knowledge block is sent on every call, so a very large schema makes every call slower. A curated schema_doc that lists only the tables that matter keeps it small.
Database
querion check reports database as ERROR
The SELECT 1 test failed. The error text from the Postgres driver follows. The connection timeout is 5 seconds. Check the host, port, database name, user and password in the connection string, and that the host can reach the server.
querion check says ok (read-only), but is the role read-only?
That label is printed whenever SELECT 1 succeeds. It does not inspect the role’s privileges. Check the role yourself, connected as that role:
SHOW default_transaction_read_only; -- expect: on
The model uses table or column names that do not exist
- Live introspection reads only the
publicschema. - The server builds its knowledge once at startup. Restart
querion serveafter a schema change. - If introspection failed at startup, the model received
(schema introspection failed: ...)instead of a schema. Fix the connection, then restart. - For a large or unusual schema, generate a file, edit it, and set
database.schema_doc:
querion introspect -o docs/schema.md
A harmless query keeps being refused
The model receives SQL error: and the reason, and it can rewrite the query in the next turn. When it keeps failing, the reason is one of these:
query contains a forbidden (write/DDL) keyword: a denylisted word appears as a whole word somewhere in the query, including inside a string or as a column name (comment,set,do,analyzeand others). A query cannot name a column called exactly one of those words, so it cannot select, filter or group by it. Expose it through a view that renames the column, grant the view to the read-only role, and describe the view inschema_doc.only SELECT/WITH queries are allowed (got '...'): the first word is notselectorwith. A leading comment, an opening parenthesis,EXPLAIN, or no space after the keyword (select*from) all cause this.multiple statements are not allowed: a semicolon appears inside the query, even inside a string literal.
The full list of denylisted words is in the safety model.
Queries are cancelled for taking too long
Querion sets statement_timeout to database.statement_timeout_ms (default 15000) on every connection, and Postgres cancels any query that runs longer. Raise the value in querion.yaml, or index the columns your questions filter on. Querion’s setting replaces any statement_timeout default on the role for its own sessions.
HTTP sources
Refused: '/path' is not on the 'NAME' safe-read allowlist...
The source has safe_get set and the path matches none of its patterns. If the endpoint is a safe read, add a pattern for it. Patterns match from the start of the path, ignore case, and ignore the query string. See Connecting data sources.
unknown source 'NAME'. Configured: ...
The model named a source that is not in the registry. A common cause is the source name itself. Querion lowercases the name it reads from a source:NAME block before looking it up, and it reads only letters, digits, _ and -. A source configured as Stripe or my.api can never be reached. Use names such as stripe or billing-api.
The API answers HTTP 401 or HTTP 403
A response with an error status is not raised as an error. It goes back to the model as HTTP <status> followed by the body. Check that the secret is set in the environment, and that auth_header has the form "Header-Name: value". Without a colon, no header is sent at all, and nothing warns you.
NAME GET failed: ...
The request was refused or raised an error. The text after the colon says which: a path refused by safe_get, a write verb such as POST, a network failure, or a timeout. The per-source timeout is timeout (default 25 seconds).
The answer seems to use only part of a response
Only the first 6000 characters of each response reach the model. Describe filters and page-size parameters in the source’s docs file so the model asks for less.
Answers and charts
The answer is (no answer)
The final reply was empty once stray directive blocks were removed. Ask again, or rephrase the question.
The answer starts with Something broke while analysing:
An error stopped the loop. The message after the colon names it. CLI failures and timeouts are the usual source; see above.
The answer stops early or looks partial
The question reached limits.max_steps (default 7) and Querion asked for a final answer. Raise max_steps, or split the question.
Charts do not show in the terminal
querion ask prints only [N chart(s) generated]. Each image is written to the system temporary directory as querion_chart_*.png and is not deleted. The model is told the file path and may include it in the answer. Without matplotlib, the model receives a text bar chart of the first series instead, which it can include in its answer.
The SQL in a terminal answer is not exactly what ran
In the terminal, the SQL you see is the plain sql block the model writes for display. The code does not compare it with what ran. In the web user interface (UI), “Show SQL” lists the exact statements that ran successfully, collected by the runner.
Web server
No module named 'uvicorn' or fastapi and uvicorn are required
querion serve needs the web packages. Install the web or all extra.
Daily limit reached. Resets in ... (00:00 UTC). (HTTP 429)
The caller used up limits.daily_per_user questions for the day. Raise the limit, or set it to 0 for no limit. Counts are kept in memory and saved to .querion_usage.json next to the config file, so a restart keeps them.
Behind a reverse proxy, Querion may see every request as coming from the proxy’s address, so all users share one counter. Have the proxy set the X-Querion-User header to the signed-in user, replacing any value the client sent.
The page loads but is blank, or charts are missing
The page loads Alpine.js and Chart.js from cdn.jsdelivr.net. The browser needs access to that host.
Polling returns {"error": "unknown run"} (HTTP 404)
Runs live in memory. The server restarted, or the run was more than an hour old and was removed when a later question was accepted.
Several questions at once slow the host
Each accepted question starts its own thread, and each model call starts its own claude process. There is no queue. The daily cap limits how many questions each caller asks per day, not how many run at once.
Limits you will hit
These values are fixed in the code unless a key is named:
- Rows shown to the model: the first 30 per query, cells cut at 40 characters. Rows fetched:
database.row_cap(default 500). - API response shown to the model: 6000 characters.
- One model call: 200 seconds. Postgres connection: 5 seconds.
- Model calls per question: up to
limits.max_steps + 1. - Directives run per reply:
limits.max_directives_per_step(default 4). The prompt always tells the model “up to 4”. - Introspection: the
publicschema only. - Web runs: kept in memory, removed after one hour. One server process only.
The project status page lists the known limits of the current release.