Budibase/budibase · error · HTTPError
err.message (rethrown as HTTPError)
Error message
err.message (rethrown as HTTPError)
What it means
The external table create/save path wraps the underlying save() call: any Error thrown during datasource table persistence (SQL connector failure, schema error) is rethrown as an HTTPError with status 400 and the original message. This normalizes internal errors into client-facing 400 responses.
Source
Thrown at packages/server/src/sdk/workspace/tables/external/index.ts:116
if (table.sourceId) {
return table.sourceId
}
if (!table._id) {
throw new Error("No table ID supplied")
}
return breakExternalTableId(table._id).datasourceId
}
export async function create(table: WithoutDocMetadata<Table>) {
const datasourceId = getDatasourceId(table)
const tableToCreate = { ...table, created: true }
try {
const result = await save(datasourceId!, tableToCreate)
return result.table
} catch (err: any) {
if (err instanceof Error) {
throw new HTTPError(err.message, 400)
} else {
throw new HTTPError(err?.message || err, err.status || 500)
}
}
}
export async function save(
datasourceId: string,
update: Table,
opts?: { tableId?: string; renaming?: RenameColumn }
) {
let tableToSave: TableRequest = {
...update,
type: "table",
_id: buildExternalTableId(datasourceId, update.name),
sourceId: datasourceId,
}
View on GitHub (pinned to a81a902e9a)
Solutions
- Read the embedded err.message to identify the underlying connector/SQL failure
- Verify the external database connection and credentials are valid
- Validate table schema (column names, types) before calling create
- Fix the root cause in the connected datasource (permissions, reserved names, constraints)
Example fix
// before
await tables.external.create(badTable) // HTTPError 400: SQL error...
// after
try {
await tables.external.create(badTable)
} catch (err) {
// err.status === 400, err.message holds the connector error
console.error("Table creation failed:", err.message)
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!table.sourceId && !table._id) return rejectEarly()
if (!Object.keys(table.schema || {}).length) return rejectEarly() Type guard
function isHTTPError(err: unknown): err is HTTPError {
return err instanceof HTTPError
} Try / catch
try {
await tables.external.create(table)
} catch (err) {
if (err instanceof HTTPError && err.status === 400) {
console.error("External table save failed:", err.message)
} else {
throw err
}
} Prevention
- Test the datasource connection before schema writes
- Validate column names/types against connector limits
- Check DB user permissions for CREATE TABLE
When it happens
Trigger: Any Error thrown inside save(datasourceId, tableToCreate) during external table creation — SQL execution failures, connector errors, relationship generation errors — surfaces as HTTPError(err.message, 400).
Common situations: SQL syntax/permission errors in the underlying database when creating tables; invalid column definitions sent to the connector; relationship constraints failing at the database level.
Related errors
- err?.message || err (rethrown as HTTPError)
- err.message (rethrown as HTTPError)
- Invalid license key
- License key has already been activated
- Error activating license key: ${message}
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/7c914e7114946bce.
Report an issue: GitHub.