{"record":{"id":"7c914e7114946bce","repo":"Budibase/budibase","slug":"err-message-rethrown-as-httperror","errorCode":null,"errorMessage":"err.message (rethrown as HTTPError)","messagePattern":"err\\.message \\(rethrown as HTTPError\\)","errorType":"http","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/server/src/sdk/workspace/tables/external/index.ts","lineNumber":116,"sourceCode":"  if (table.sourceId) {\n    return table.sourceId\n  }\n  if (!table._id) {\n    throw new Error(\"No table ID supplied\")\n  }\n  return breakExternalTableId(table._id).datasourceId\n}\n\nexport async function create(table: WithoutDocMetadata<Table>) {\n  const datasourceId = getDatasourceId(table)\n\n  const tableToCreate = { ...table, created: true }\n  try {\n    const result = await save(datasourceId!, tableToCreate)\n    return result.table\n  } catch (err: any) {\n    if (err instanceof Error) {\n      throw new HTTPError(err.message, 400)\n    } else {\n      throw new HTTPError(err?.message || err, err.status || 500)\n    }\n  }\n}\n\nexport async function save(\n  datasourceId: string,\n  update: Table,\n  opts?: { tableId?: string; renaming?: RenameColumn }\n) {\n  let tableToSave: TableRequest = {\n    ...update,\n    type: \"table\",\n    _id: buildExternalTableId(datasourceId, update.name),\n    sourceId: datasourceId,\n  }\n","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/tables/external/index.ts#L98-L134","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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)"],"exampleFix":"// before\nawait tables.external.create(badTable) // HTTPError 400: SQL error...\n// after\ntry {\n  await tables.external.create(badTable)\n} catch (err) {\n  // err.status === 400, err.message holds the connector error\n  console.error(\"Table creation failed:\", err.message)\n}","handlingStrategy":"try-catch","validationCode":"if (!table.sourceId && !table._id) return rejectEarly()\nif (!Object.keys(table.schema || {}).length) return rejectEarly()","typeGuard":"function isHTTPError(err: unknown): err is HTTPError {\n  return err instanceof HTTPError\n}","tryCatchPattern":"try {\n  await tables.external.create(table)\n} catch (err) {\n  if (err instanceof HTTPError && err.status === 400) {\n    console.error(\"External table save failed:\", err.message)\n  } else {\n    throw err\n  }\n}","preventionTips":["Test the datasource connection before schema writes","Validate column names/types against connector limits","Check DB user permissions for CREATE TABLE"],"tags":["http-error","external-datasource","error-wrapping"],"backgroundTag":"sql-execution-failed","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}