Budibase/budibase · error · HTTPError

Can't bulk import relationship fields for internal databases

Error message

Can't bulk import relationship fields for internal databases, found value in field "${fieldName}"

What it means

Bulk row import (CSV/JSON into a table) cannot populate relationship (link) fields when the table lives in the internal CouchDB database; links must be created through the link APIs after rows exist. importToRows throws HTTP 400 if any imported row has a non-empty value in a FieldType.LINK column.

Source

Thrown at packages/server/src/api/controllers/table/utils.ts:151

  const keepCouchId = !!opts?.keepCouchId
  for (let i = 0; i < data.length; i++) {
    let row = data[i]
    row._id = (keepCouchId && row._id) || generateRowID(table._id!)
    row.type = "row"
    row.tableId = table._id

    // We use a reference to table here and update it after input processing,
    // so that we can auto increment auto IDs in imported data properly
    row = await inputProcessing(userId, table, row, {
      noAutoRelationships: true,
    })

    // However here we must reference the original table, as we want to mutate
    // the real schema of the table passed in, not the clone used for
    // incrementing auto IDs
    for (const [fieldName, schema] of Object.entries(originalTable.schema)) {
      if (schema.type === FieldType.LINK && data.find(row => row[fieldName])) {
        throw new HTTPError(
          `Can't bulk import relationship fields for internal databases, found value in field "${fieldName}"`,
          400
        )
      }

      if (
        (schema.type === FieldType.OPTIONS ||
          schema.type === FieldType.ARRAY) &&
        row[fieldName]
      ) {
        const isArray = Array.isArray(row[fieldName])

        // Add option to inclusion constraints
        const rowVal = isArray ? row[fieldName] : [row[fieldName]]
        let merged = [...schema.constraints!.inclusion!, ...rowVal]
        let superSet = new Set(merged)
        schema.constraints!.inclusion = Array.from(superSet)
        schema.constraints!.inclusion.sort()

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Remove the link columns from the CSV/JSON before import, then create relationships via the link API or relationship UI afterwards
  2. Import into a SQL (external) datasource if relationship data must be bulk-loaded
  3. Split the workflow: import scalar fields first, then run a script mapping natural keys to row IDs to build links

Example fix

// before
csv = "name,tags\nrow1,tag1"
await api.import(tableId, csv) // tags is a link field
// after
csv = "name\nrow1"
await api.import(tableId, csv)
await api.createLink(tableId, rowId, 'tags', tagRowIds)
Defensive patterns

Strategy: validation

Validate before calling

function assertNoLinkData(table, rows) {
  for (const [name, schema] of Object.entries(table.schema || {})) {
    if (schema.type === "link" && rows.some(r => r[name])) {
      throw new Error(`remove link column ${name} before bulk import`)
    }
  }
}

Try / catch

try {
  await api.importRows(tableId, rows)
} catch (e) {
  if (e?.status === 400 && /relationship fields/.test(e.message)) {
    const field = e.message.match(/field \"(.+?)\"/)?.[1]
    // strip that column from rows, import, then build links via API
  } else throw e
}

Prevention

When it happens

Trigger: Uploading a CSV/JSON bulk import where any row contains a truthy value under a column whose schema type is "link" in the original table's schema.

Common situations: Exporting rows from another app including link columns and re-importing them as-is; templates/migrations that assumed relationships import like scalar fields (true for SQL datasources, not internal).

Related errors


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