{"record":{"id":"c17a0a83c847c96c","repo":"Budibase/budibase","slug":"column-newcolumnname-already-exists","errorCode":null,"errorMessage":"Column \"${newColumnName}\" already exists","messagePattern":"Column \"(.+?)\" already exists","errorType":"validation","errorClass":"BadRequestError","httpStatus":400,"severity":"error","filePath":"packages/server/src/sdk/workspace/tables/migration.ts","lineNumber":33,"sourceCode":"  Row,\n  Table,\n} from \"@budibase/types\"\nimport { cloneDeep } from \"lodash\"\nimport sdk from \"../..\"\nimport { EventType, updateLinks } from \"../../../db/linkedRows\"\nimport { isExternalTableID } from \"../../../integrations/utils\"\n\nexport interface MigrationResult {\n  tablesUpdated: Table[]\n}\n\nexport async function migrate(\n  table: Table,\n  oldColumnName: string,\n  newColumnName: string\n): Promise<MigrationResult> {\n  if (newColumnName in table.schema) {\n    throw new BadRequestError(`Column \"${newColumnName}\" already exists`)\n  }\n\n  if (newColumnName === \"\") {\n    throw new BadRequestError(`Column name cannot be empty`)\n  }\n\n  if (isInternalColumnName(newColumnName)) {\n    throw new BadRequestError(`Column name cannot be a reserved column name`)\n  }\n\n  const oldColumn = table.schema[oldColumnName]\n\n  if (!oldColumn) {\n    throw new BadRequestError(\n      `Column \"${oldColumnName}\" does not exist on table \"${table.name}\"`\n    )\n  }\n","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/tables/migration.ts#L15-L51","documentation":"migrate() (user relationship column migration) first checks that the target column name is not already present in table.schema; if it is, the migration would overwrite an existing column, so a BadRequestError is thrown.","triggerScenarios":"Calling sdk.tables.migration.migrate(table, oldColumnName, newColumnName) where newColumnName already exists as a key in the table's schema (case-sensitive check).","commonSituations":"Retrying a partially-completed migration that already added the new column; picking a name that collides with another field; UI letting users type an existing field name.","solutions":["Choose a different newColumnName that doesn't exist in the schema","Check `newColumnName in table.schema` before calling and handle gracefully","If the migration partially ran, clean up or resume from the already-created column rather than re-running","Verify the table document is current (re-fetch) — stale table objects may miss a recently added column"],"exampleFix":"// before\nawait sdk.tables.migration.migrate(table, 'user', 'owner')\n// after\nif (!('owner' in table.schema)) {\n  await sdk.tables.migration.migrate(table, 'user', 'owner')\n}","handlingStrategy":"validation","validationCode":"if (newColumnName in table.schema) {\n  throw new Error(`Pick a different name; \"${newColumnName}\" exists`)\n}","typeGuard":null,"tryCatchPattern":"try {\n  await sdk.tables.migration.migrate(table, oldName, newName)\n} catch (e) {\n  if (e.message.includes('already exists')) {\n    // choose another name or resume the partial migration\n  }\n}","preventionTips":["Check schema keys before calling migrate","Re-fetch the table to avoid stale schema snapshots","Handle retries idempotently — the first run may have added the column already","Validate user-supplied names against existing fields in the UI"],"tags":["validation","migration","columns"],"backgroundTag":"column-name-already-exists","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}