Budibase/budibase · error · HTTPError

err?.message || err (rethrown as HTTPError)

Error message

err?.message || err (rethrown as HTTPError)

What it means

The same create() catch block handles non-Error throwables (or Errors without message): it rethrows HTTPError(err?.message || err, err.status || 500). This branch fires when the thrown value is not an Error instance (e.g. a string thrown by a connector) or when err.message is undefined, defaulting to status 500.

Source

Thrown at packages/server/src/sdk/workspace/tables/external/index.ts:118

  }
  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,
  }

  const tableId = opts?.tableId || update._id
  let oldTable: Table | undefined

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Inspect err.message in the resulting HTTPError for the raw thrown value
  2. Fix the connector/driver that throws non-Error values (throw new Error(...) instead)
  3. Check err.status on the HTTPError to distinguish 400 (client) from 500 (internal) responses
  4. Test the datasource connection directly to isolate driver misbehavior

Example fix

// before (in a connector)
throw "connection timed out"
// after
throw new Error("connection timed out")
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure connector calls only throw Error instances
if (typeof result === "undefined") throw new Error("Connector returned undefined")

Type guard

function isErrorWithMessage(err: unknown): err is Error {
  return err instanceof Error && typeof err.message === "string"
}

Try / catch

try {
  await tables.external.create(table)
} catch (err) {
  const status = err instanceof HTTPError ? err.status : 500
  const msg = err instanceof Error ? err.message : String(err)
  console.error(`Table create failed (${status}):`, msg)
}

Prevention

When it happens

Trigger: A connector or plugin throws a non-Error value (string/object) during external table save, or an Error subclass lacking a message — caught at the same wrapper and converted to a 500 HTTPError.

Common situations: Custom SQL connectors throwing plain strings; undefined err.message from third-party datasource drivers; proxy/fetch failures throwing non-Error objects.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/d9abd53f3f5245a8. Report an issue: GitHub.