faz
Troubleshooting

Query Blocked

Why a query was rejected by the safety pipeline and how to unblock it. One section per stage with the exact error text.

When the safety pipeline blocks a query, the response has shape:

{
  "request_id": "req_a1b2c3d4e5f6",
  "status": "blocked",
  "error": {
    "stage": "RBAC_GATE",
    "reason": "Access denied: <database>.<sensitive-table> requires permission for SELECT; policy grants none",
    "suggestion": null
  }
}

The stage field is the diagnosis. Find it below for the fix. For the conceptual model behind each stage, see How faz protects you.

Blocked at PROMPT_GUARD

Destructive intent detected: '<matched text>'

The Prompt Guard saw destructive natural-language intent in the query body — phrases like "wipe all the records", "drop the database", "delete all customers". This stage runs before parsing, so it catches free-text destructive instructions that wouldn't match valid SQL/MQL/Cypher syntax.

Why this fires

Three pattern families trigger it:

  • wipe | destroy | erase | purge | nuke followed by a table-shaped noun (table, database, collection, data, records, nodes).
  • remove | delete all | every followed by records, rows, documents, entries, nodes, or data.
  • drop the | drop all followed by database, tables, collections, or schemas.

Read-context phrases at the start of the prompt — show, list, find, get, fetch, retrieve, search, query, display, count, how many, select — preempt the destructive match. So "show me deleted records" passes, but "delete all records" doesn't.

How to unblock

If you legitimately want to delete data, use the database's native query language directly: DELETE FROM customers WHERE ... (gated by RBAC + AST checks, not the Prompt Guard) instead of natural-language "delete all customers". The Prompt Guard is for catching agents that paste destructive instructions in free text; it doesn't see your actual SQL.

If you're sending a SQL string and it's still being flagged, your query body contains free-text that matches a pattern. Rephrase the comment or string literal:

-- Wrong — "delete all" + "rows" matches
SELECT * FROM logs WHERE message LIKE '%delete all rows%'

-- Right — same query, harmless wording
SELECT * FROM logs WHERE message LIKE '%clear table contents%'

Blocked at RBAC_GATE

Access denied: <database>.<table> requires permission for <OPERATION>; policy grants <LEVEL>

The query touched a table whose policy doesn't permit the operation it requires. The most common version:

Access denied: <database>.<sensitive-table> requires permission for SELECT; policy grants none

This means the agent tried to read <database>.<sensitive-table>, the lookup found no policy entry that grants SELECT, and the request was denied.

How to unblock

Edit faz.yaml to grant the appropriate access. If the agent should be able to read the table:

permissions:
  - database: <database>
    access: R                       # baseline allows reads on every table
    tables:
      <audit-table>: W              # except this one
      # remove the <sensitive-table> override if it exists

Restart faz serve (or your MCP client) to apply. faz policy confirms what's loaded.

For DDL specifically, the message is more specific:

DDL is not permitted: <database>.<table> (CREATE / DROP / ALTER / TRUNCATE / schema mutation); policy grants RW. Only AccessMode.A allows DDL.

If the agent legitimately needs DDL, raise the database's access to A. Use sparinglyA is the only level that lets DDL through. See the warning on Permissions.

For the conceptual model and the implicit-R fallback, see Permissions.

Blocked at AST_CHECKER

DDL is not permitted: <database>.<table> (CREATE / DROP / ALTER / TRUNCATE / schema mutation / etc.)

The AST Checker is a defense-in-depth backstop for DDL. RBAC normally rejects DDL when the policy isn't A; this stage re-checks after parsing the query.

How to unblock

Same as RBAC: raise the database's access to A if DDL is intended. If you didn't intend to run DDL, the most common cause is an inadvertent CREATE, ALTER, or DROP keyword in your query — check for typos and statement structure.

Less common: parser failure

Failed to parse query on <database>.<table>

The per-language access extractor crashed trying to parse the query. faz fail-closes — the request blocks. Two paths:

  • Fix the query syntax. Try running it directly against the database with the native CLI; if the database parses it, file an issue with the offending query. If the database doesn't parse it either, fix the query.
  • Workaround for known-good queries: simplify the structure (split a complex CTE into separate steps in a federated query, for instance).

Blocked at INJECTION_ANALYSER

The Injection Analyser dispatches to per-language scanners. The block message varies by language. Common ones:

Tautology injection detected in <source>

Your query contains WHERE 1=1, OR 'a'='a', or similar always-true clauses. These are the canonical SQL injection signature. Rewrite without the tautology.

SQL comment sequence detected in <source>

Your query contains --, /*, or # . Comments at this position are a common injection-bypass vector. Either remove the comment, or escape it (depends on the database).

Stacked statement detected in <source>

Multiple statements separated by ;, with the second one being write-shaped (DROP, DELETE, INSERT, UPDATE, ALTER, TRUNCATE, CREATE, EXEC, GRANT, REVOKE). Submit one statement per call.

Blind boolean/time-based probing detected

Your query uses SLEEP(), WAITFOR DELAY, BENCHMARK(), PG_SLEEP(). These are timing-attack signatures. If you legitimately need a sleep (rare), your only option is to run it outside faz.

Out-of-band exfiltration attempt detected

Your query uses LOAD_FILE, INTO OUTFILE, INTO DUMPFILE, UTL_HTTP, or DBMS_PIPE. These access local files or make outbound requests. Rejected unconditionally.

Stored procedure abuse detected

Your query calls xp_cmdshell, EXEC sp_*, or CALL <procname>. These can run shell commands or unrelated procedures. Rejected.

Dangerous MQL operator '<key>' detected

Your MongoDB query uses $where, $function, or $accumulator — server-side JavaScript. Rewrite without server-side code. For complex aggregations, use the standard pipeline operators.

Write pipeline stage '<key>' detected

Your MongoDB query uses $out or $merge — these write data, even on a read pipeline. Use a separate insertOne / insertMany call instead.

JavaScript injection pattern detected in MQL

A string value in your MongoDB query looks like JavaScript (function(, this., sleep(, while(, for(). If the value is legitimate user data that happens to look like code, you'll need to sanitize at the agent layer before submitting.

APOC procedure abuse detected in Cypher

Your Cypher query calls apoc.load.*, apoc.cypher.run, apoc.cypher.runMany, apoc.periodic.*, or apoc.export.*. These can read filesystems, run arbitrary Cypher, and exfiltrate data. Rejected unconditionally.

LOAD CSV file access detected in Cypher

LOAD CSV FROM accesses files. Rejected.

Stacked Cypher statement detected

Multi-statement Cypher with semicolons followed by write keywords. Submit one statement per call.

Script execution key '<key>' detected in ES query

Your Elasticsearch body contains script, scripted_field, script_fields, or runtime_mappings. Painless and other scripted queries can execute arbitrary code. Use standard query DSL instead.

Diagnosing partial denial

If you ran a federated query and got fewer rows than expected, one or more steps may have been silently stripped under DenyPolicy.PARTIAL. Check the audit log:

faz logs | jq 'select(.rbac.outcome == "PARTIAL") | {trace_id, stripped: .rbac.stripped}'

The stripped array names the sources that were dropped. To make these queries hard-fail instead of partial, use DenyPolicy.BLOCK (not yet exposed via faz.yaml; on the roadmap).

On this page