Budibase/budibase · warning · HTTPError

Cannot duplicate external tables

Error message

Cannot duplicate external tables

What it means

Table duplication is only supported for internal (CouchDB) tables. The duplicate endpoint explicitly rejects external tables (backed by SQL/REST datasources) with HTTP 422 because rows cannot be cloned through the external connector in the same way.

Source

Thrown at packages/server/src/api/controllers/table/index.ts:326

  let tableId = ctx.params.tableId as string
  const table = await sdk.tables.getTable(tableId)
  let result = await sdk.tables.migrate(table, oldColumn, newColumn)

  for (let table of result.tablesUpdated) {
    builderSocket?.emitTableUpdate(ctx, table, {
      includeOriginator: true,
    })
  }

  ctx.body = { message: `Column ${oldColumn} migrated.` }
}

export async function duplicate(ctx: UserCtx<void, SaveTableResponse>) {
  const tableId = ctx.params.tableId as string
  const table = await sdk.tables.getTable(tableId)

  if (isExternalTable(table)) {
    throw new HTTPError("Cannot duplicate external tables", 422)
  }

  const duplicatedTable = await sdk.tables.duplicate(table, ctx.user._id)

  ctx.message = `Table ${table.name} duplicated successfully.`
  ctx.body = duplicatedTable

  const processedTable = await processTable(duplicatedTable)
  builderSocket?.emitTableUpdate(ctx, cloneDeep(processedTable))
}

export async function publish(
  ctx: UserCtx<PublishTableRequest, PublishTableResponse>
) {
  const tableId = ctx.params.tableId as string
  const table = await sdk.tables.getTable(tableId)

  if (!table) {

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Duplicate the table inside the source database directly and re-sync the datasource in Budibase
  2. Create a new internal table and copy data via a Budibase automation/script
  3. Use a query against the external datasource that performs the copy (e.g. SQL CREATE TABLE ... AS SELECT)
Defensive patterns

Strategy: type-guard

Validate before calling

async function canDuplicate(tableId, api) {
  const table = await api.getTable(tableId)
  return table && table.source !== "external" && table.type !== "external"
}

Type guard

const isInternalTable = (t) => Boolean(t) && !t.sourceId && t.source !== "external"

Try / catch

try {
  await api.duplicateTable(tableId)
} catch (e) {
  if (e?.status === 422 && /Cannot duplicate external tables/.test(e.message)) {
    // fall back to copying data into a new internal table via script/automation
  } else throw e
}

Prevention

When it happens

Trigger: POST to the table duplicate endpoint (/tables/:tableId/duplicate) where tableId resolves to a table whose datasource is external (isExternalTable true), e.g. a PostgreSQL/MySQL/REST datasource table.

Common situations: Users attempting to duplicate SQL-backed tables from the Builder data section; scripts iterating all tables and duplicating each without filtering by datasource type.

Related errors


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