windmill-labs/windmill · warning
SQL_PREPARATION_ERROR
SQL_PREPARATION_ERROR
Error message
Failed to prepare query: db error: ERROR: <db error text> (prefix stripped; messageText is the prepared-query error, surfaced as a Monaco diagnostic)
What it means
In the SQL language worker for Monaco (frontend/src/lib/monaco_workers/sqlTypePlugin.worker.js), _createSqlErrorDiagnostics converts a database-side prepared-query failure into an editor diagnostic. The raw backend message has the shape 'Failed to prepare query: db error: ERROR: <db error text>'; the worker strips that prefix and surfaces only the underlying DB messageText as a red squiggle under the offending template-literal query, tagged with code SQL_PREPARATION_ERROR.
Source
Thrown at frontend/src/lib/monaco_workers/sqlTypePlugin.worker.js:700
const originalCode = cached?.originalText ?? ''
if (!originalCode) {
// Fallback if no cached result
const originalSnapshot = super.getScriptSnapshot(fileName)
if (!originalSnapshot) {
return []
}
}
const sqlDiagnostics = []
for (const query of queries) {
let messageText = query?.prepared?.error
if (typeof messageText === 'string') {
let queryStartIdx = originalCode.indexOf('`', (query.span?.[0] || 1) - 1) + 1
// Create a diagnostic error for this query
let prefix = 'Failed to prepare query: db error: ERROR: '
if (messageText.startsWith(prefix)) messageText = messageText.substring(prefix.length)
const diagnostic = {
code: 'SQL_PREPARATION_ERROR',
category: ts.typescript.DiagnosticCategory.Error,
messageText,
file: fileName,
start: queryStartIdx,
length: query.span?.[1] ? query.span[1] - queryStartIdx - 2 : 0,
source: 'sql'
}
sqlDiagnostics.push(diagnostic)
}
}
return sqlDiagnostics
}
async getSyntacticDiagnostics(fileName) {
const diagnostics = await super.getSyntacticDiagnostics(fileName)
return this._mapDiagnostics(diagnostics, fileName)
}View on GitHub (pinned to e474e8803c)
Solutions
- Read the diagnostic message — after prefix stripping it is the raw DB error (e.g. 'column "foo" does not exist'); fix the SQL accordingly.
- Hover over the squiggle: start/length map to the failing backtick query span in the editor.
- Verify the connection's target database/dialect actually supports the SQL you wrote.
- Check that placeholder count ($1…) matches your args if using parameterized queries.
- If the diagnostic looks stale, retrigger analysis by editing the query — the worker only reports errors from the last prepare round.
Example fix
// before const q = `SELECT usernmae FROM users WHERE id = $1` // after (fixing the unknown column reported by the diagnostic) const q = `SELECT username FROM users WHERE id = $1`
Defensive patterns
Strategy: type-guard
Type guard
function isSqlPreparationDiagnostic(d: ts.typescript.Diagnostic): boolean {
return (d as { code?: number | string }).code === 'SQL_PREPARATION_ERROR' || d.source === 'sql'
} Try / catch
// Monaco language-service context: consume diagnostics, don't catch
monaco.editor.onDidChangeMarkers => {
const diags = monaco.editor.getModelMarkers({ owner: 'sql' })
for (const d of diags.filter(isSqlPreparationDiagnostic)) {
console.log(`SQL error at ${d.startLineNumber}: ${d.message}`)
}
} Prevention
- Validate SQL against the same database/dialect the worker prepares against.
- Keep placeholder ($1, $2) counts consistent with provided parameters.
- Check table/column names against the connected schema before saving.
- Reconnect the preview database if diagnostics suddenly report connection errors.
- Reopen the editor after dependency/schema changes to force a fresh prepare round.
When it happens
Trigger: Editing a script/app that contains a backtick-quoted SQL query; the language service sends the query to the database to prepare it; the DB rejects it (syntax error, unknown table/column, wrong placeholder count, permission denied) and the worker builds a diagnostic from the returned messageText.
Common situations: Typo in SQL syntax; referencing a table or column that does not exist in the connected database; using $1/$2 placeholders inconsistent with provided args; dialect mismatch (Postgres-only syntax on MySQL connection); the preview database being unreachable or the user lacking permissions.
Related errors
- Invalid group
- [SqlTypeService] Worker initialization timeout for ${uri.toS
- [SqlTypeService] Worker initialization failed for ${uri.toSt
- Error executing query: {:?}
- result.substring(__RESULT_ERR_PREFIX.length)
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/cdfc90b9af39852a.
Report an issue: GitHub.