{"record":{"id":"223abae10d0560e1","repo":"Budibase/budibase","slug":"err-message-rethrown-as-httperror-223aba","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/internal/index.ts","lineNumber":61,"sourceCode":"  }\n\n  const isImport = !!rows\n\n  if (!tableToSave.views) {\n    tableToSave.views = {}\n  }\n\n  try {\n    const { table } = await save(tableToSave, {\n      userId,\n      rowsToImport: rows,\n      isImport,\n    })\n\n    return 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  table: Table,\n  opts?: {\n    userId?: string\n    tableId?: string\n    rowsToImport?: Row[]\n    renaming?: RenameColumn\n    isImport?: boolean\n  }\n) {\n  const db = context.getWorkspaceDB()\n","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/tables/internal/index.ts#L43-L79","documentation":"The internal table create path wraps table persistence: any Error thrown while saving the table document (validation, dupes, DB errors) is rethrown as HTTPError(err.message, 400); non-Error throwables get status 500. This normalizes internal table save failures into API errors.","triggerScenarios":"Calling tables.internal.create() (table save on internal Budibase DB) when the underlying save throws — invalid schema, name conflicts, CouchDB write failures — surfaced as HTTPError 400 (or 500 for non-Error throws).","commonSituations":"Duplicate table names or column name conflicts; invalid column type definitions; CouchDB connectivity/write failures; automation or import code constructing malformed table payloads.","solutions":["Read err.message on the HTTPError to identify the underlying save failure","Validate the table payload (unique name, valid column types, primary field) before create","Check CouchDB/DB health if writes are failing infrastructure-side","Log and fix the source that throws non-Error values if you see 500s"],"exampleFix":"// before\nawait tables.internal.create(malformedTable) // HTTPError 400\n// after\ntry {\n  await tables.internal.create(malformedTable)\n} catch (err) {\n  // err.status === 400, err.message describes the save failure\n  console.error(\"Internal table create failed:\", err.message)\n}","handlingStrategy":"try-catch","validationCode":"if (!table.name) throw new Error(\"Table name required\")\nfor (const col of Object.keys(table.schema || {})) {\n  if (!table.schema[col].type) throw new Error(`Column ${col} missing type`)\n}","typeGuard":"function isHTTPError(err: unknown): err is HTTPError {\n  return err instanceof HTTPError\n}","tryCatchPattern":"try {\n  await tables.internal.create(table)\n} catch (err) {\n  if (err instanceof HTTPError && err.status === 400) {\n    console.error(\"Internal table save failed:\", err.message)\n  } else {\n    throw err\n  }\n}","preventionTips":["Validate table payload (name uniqueness, column types) before create","Check CouchDB health when writes fail repeatedly","Use SDK builders/utilities to construct well-formed table objects"],"tags":["internal-table","http-error","error-wrapping"],"backgroundTag":"table-save-failed","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}