Budibase/budibase · error · Error
${readableMessage}
Error message
${readableMessage} What it means
internalQuery() runs SQL against SQL Server and maps driver errors to human-readable messages via getReadableErrorMessage(SourceName.SQL_SERVER, err.number). When the error's number matches a known SQL Server error code, it throws a new Error with that readable message, chaining the original error as cause.
Source
Thrown at packages/server/src/integrations/microsoftSqlServer.ts:388
for (let binding of query.bindings) {
request.input(`p${count++}`, binding)
}
}
// this is a hack to get the inserted ID back,
// no way to do this with Knex nicely
const sql =
operation === Operation.CREATE
? `${query.sql}; SELECT SCOPE_IDENTITY() AS id;`
: query.sql
this.log(sql, query.bindings)
return await request.query(sql)
} catch (err: any) {
let readableMessage = getReadableErrorMessage(
SourceName.SQL_SERVER,
err.number
)
if (readableMessage) {
throw new Error(readableMessage, { cause: err })
} else {
throw new Error(err.message as string, { cause: err })
}
}
}
getDefinitionSQL(tableName: string, schemaName: string): SqlQuery {
return {
sql: `select *
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME=@p0 AND TABLE_SCHEMA=@p1`,
bindings: [tableName, schemaName],
}
}
getConstraintsSQL(tableName: string, schemaName: string): SqlQuery {
return {
sql: `SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS TCView on GitHub (pinned to a81a902e9a)
Solutions
- Read the readableMessage — it is the mapped SQL Server error — and fix the SQL or data it describes
- For duplicate-key errors, deduplicate rows or change the conflicting key values
- For permission errors, grant the SQL user the required privileges
- If the message is unhelpful, inspect error.cause for the original tedious error with full details
Example fix
// before: duplicate key from re-running an insert INSERT INTO users (id, email) VALUES (1, 'a@example.com') // after: make it idempotent IF NOT EXISTS (SELECT 1 FROM users WHERE id = 1) INSERT INTO users (id, email) VALUES (1, 'a@example.com')
Defensive patterns
Strategy: try-catch
Validate before calling
// validate before executing: check the target object exists
const exists = await internalQuery({ sql: "SELECT 1 FROM sys.tables WHERE name = @tableName", bindings: [tableName] })
if (!exists.length) throw new Error(`Table ${tableName} does not exist in SQL Server`) Type guard
function hasSqlNumber(err: unknown): err is { number: number; message: string } {
return typeof err === "object" && err !== null && typeof (err as any).number === "number"
} Try / catch
try {
return await ds.query(sqlQuery)
} catch (err) {
// message is the mapped readable message; original tedious error is on cause
if (/duplicate key/i.test(err.message)) {
// handle conflict: retry with new key or upsert
}
console.error("SQL Server error:", (err as any).cause)
throw err
} Prevention
- Design keys/constraints so duplicate-key violations are unlikely; handle them explicitly
- Check object names and permissions before deploying queries
- Always inspect err.cause for the underlying SQL Server error number
- Use parameterized queries to avoid syntax errors from interpolated values
When it happens
Trigger: Any SQL Server error raised during query execution whose err.number is in the readable-message mapping — most commonly constraint violations (duplicate key), syntax errors, permission denials, or missing object errors returned by tedious.
Common situations: Running a query that inserts a duplicate primary key or violates a foreign key; referencing a nonexistent table/column; a user without SELECT/INSERT permissions; malformed SQL generated by the query builder.
Related errors
- ${err.message}
- ${readableMessage}
- Invalid import url
- Only HTTP(S) URLs are allowed for query import
- Import url must not contain credentials
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/435b09600677e8b7.
Report an issue: GitHub.