Budibase/budibase · error · Error

Unable to generate link schema, no primary keys

Error message

Unable to generate link schema, no primary keys

What it means

generateLinkSchema creates one-to-many/many-to-one link columns, which requires a primary key on at least one side to anchor the foreign key. If neither table defines primary keys, it throws this generic message.

Source

Thrown at packages/server/src/sdk/workspace/tables/external/utils.ts:132

    },
  }
  column.through = junctionTable._id
  column.throughFrom = relatedPrimary
  column.throughTo = primary
  column.fieldName = relatedPrimary
  return junctionTable
}

export function generateLinkSchema(
  column:
    | OneToManyRelationshipFieldMetadata
    | ManyToOneRelationshipFieldMetadata,
  table: Table,
  relatedTable: Table,
  type: RelationshipType.ONE_TO_MANY | RelationshipType.MANY_TO_ONE
) {
  if (!table.primary || !relatedTable.primary) {
    throw new Error("Unable to generate link schema, no primary keys")
  }
  const isOneSide = type === RelationshipType.ONE_TO_MANY
  const primary = isOneSide ? relatedTable.primary[0] : table.primary[0]
  // generate a foreign key
  const foreignKey = generateForeignKey(column, relatedTable)
  column.relationshipType = type
  column.foreignKey = isOneSide ? foreignKey : primary
  column.fieldName = isOneSide ? primary : foreignKey
  return foreignKey
}

export function generateRelatedSchema(
  linkColumn: RelationshipFieldMetadata,
  table: Table,
  relatedTable: Table,
  columnName: string
) {
  // generate column for other table

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Define a primary key on the related table in the source database and re-sync
  2. Set table.primary (e.g. ["id"]) on the Budibase table before creating the link
  3. Pick a keyed table for the relationship
  4. Refresh the datasource to re-run table metadata detection

Example fix

// before
// neither table has primary defined
await tables.external.save(datasourceId, tableWithLinkColumn)
// after
table.primary = ["id"]
relatedTable.primary = ["id"]
await tables.external.save(datasourceId, tableWithLinkColumn)
Defensive patterns

Strategy: validation

Validate before calling

if (!table.primary?.length && !relatedTable.primary?.length) {
  throw new Error("Link requires a primary key on at least one table")
}

Type guard

function linkable(t: Table, related: Table): boolean {
  return (t.primary?.length ?? 0) > 0 || (related.primary?.length ?? 0) > 0
}

Try / catch

try {
  await tables.external.save(datasourceId, table)
} catch (err) {
  if (err.message === "Unable to generate link schema, no primary keys") {
    // define table.primary or fix PKs in source DB and re-sync
  }
}

Prevention

When it happens

Trigger: Saving a ONE_TO_MANY or MANY_TO_ONE relationship where both table.primary and relatedTable.primary are missing/empty.

Common situations: External SQL tables synced without detected primary keys; legacy tables imported before PK detection; database tables altered to drop PKs after initial sync.

Related errors


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