FlowiseAI/Flowise · error · Error
Invalid SQL statement: statement is required and must be a s
Error message
Invalid SQL statement: statement is required and must be a string
What it means
Thrown by assertReadOnlySqlStatement (packages/components/src/validator.ts:381) when the SQL argument is falsy or not a string. The guard is applied to LLM-generated SQL in the Sql Database Chain so only read-only SELECT/WITH can run; a non-string input fails the type check before any SQL parsing.
Source
Thrown at packages/components/src/validator.ts:381
* single read-only SELECT/WITH statement.
*
* The Sql Database Chain hands LLM-generated SQL directly to TypeORM's raw query
* executor with no statement-type filtering. Without this guard, a compromised or
* malicious LLM response can run `ATTACH DATABASE`/`VACUUM INTO`/bare `PRAGMA` to write
* arbitrary files anywhere the process can write, bypassing validateSQLitePath (which
* only constrains the initial connection path, not queries run afterward).
*
* All legitimate queries issued against sqlite by this chain (including langchain's own
* schema introspection, which uses `pragma_table_info()` as a table-valued function
* inside a SELECT) are single SELECT/WITH statements, so this restriction does not
* affect normal operation.
*
* @param {string} sql The SQL statement to validate
* @throws {Error} If the statement is not a single read-only SELECT/WITH statement
*/
export const assertReadOnlySqlStatement = (sql: string): void => {
if (!sql || typeof sql !== 'string') {
throw new Error('Invalid SQL statement: statement is required and must be a string')
}
let trimmed = sql.trim()
// Strip at most one trailing semicolon (+ trailing whitespace)
trimmed = trimmed.replace(/;\s*$/, '')
if (trimmed.includes(';')) {
throw new Error('Invalid SQL statement: multiple statements are not allowed')
}
if (!/^(SELECT|WITH)\b/i.test(trimmed)) {
throw new Error('Invalid SQL statement: only read-only SELECT/WITH statements are allowed')
}
if (/load_extension\s*\(/i.test(trimmed)) {
throw new Error('Invalid SQL statement: load_extension is not allowed')
}
}View on GitHub (pinned to abe4a8601a)
Solutions
- Extract the SQL string from the LLM/tool response before calling the validator (e.g. response.text or response.sql).
- Default to a safe no-op query like 'SELECT 1' when the LLM returns nothing.
- Add a typeof sql === 'string' && sql.trim() guard upstream.
Example fix
// before
assertReadOnlySqlStatement(llmResponse) // llmResponse is { sql: '...' }
// after
assertReadOnlySqlStatement(llmResponse?.sql ?? 'SELECT 1') Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof sql !== 'string' || sql.trim() === '') throw new Error('SQL statement missing');
assertReadOnlySqlStatement(sql); Type guard
const isSqlString = (s: unknown): s is string => typeof s === 'string' && s.trim() !== '';
Try / catch
try { assertReadOnlySqlStatement(sql) } catch (e) { if (e instanceof Error && /statement is required/.test(e.message)) { sql = 'SELECT 1' } else throw e } Prevention
- Extract the .sql/.text field from LLM/tool responses before validation.
- Default to 'SELECT 1' when the LLM returns nothing.
- Type-narrow upstream with typeof sql === 'string'.
When it happens
Trigger: assertReadOnlySqlStatement is called with undefined, null, '', a number, or an object — e.g. the LLM returned no SQL, a tool returned a parsed object instead of text, or a caller forgot to extract the .sql field.
Common situations: LLM hallucinated an empty/structured response; chattool forwarded a JSON object instead of the SQL string; refactored code changed the value passed to the validator.
Related errors
- Invalid SQL statement: multiple statements are not allowed
- Invalid SQL statement: only read-only SELECT/WITH statements
- Invalid SQL statement: load_extension is not allowed
- Invalid SQLite path: path traversal attempt detected
- Invalid SQLite path: encoded path traversal attempt detected
AI-assisted analysis of FlowiseAI/Flowise@abe4a8601a (2026-08-12).
Data as JSON: /api/errors/341ba2f4c0ae4a2a.
Report an issue: GitHub.