Budibase/budibase · error

Failed to generate a unique name for the row action

Error message

Failed to generate a unique name for the row action

What it means

When creating a row action, the store tries a provided name or generates a sequential name (e.g. 'New row action 2'). If after both attempts no name is available, it throws rather than calling the API with an empty name. This is a defensive guard against getSequentialName failing (e.g. returning null/undefined via the non-null assertion).

Source

Thrown at packages/builder/src/stores/builder/rowActions.ts:63

      [tableId]: actions,
    }))
  }

  createRowAction = async (tableId: string, viewId?: string, name?: string) => {
    if (!tableId) {
      return
    }

    // Get a unique name for this action
    if (!name) {
      const existingRowActions = get(this)[tableId] || []
      name = getSequentialName(existingRowActions, "New row action ", {
        getName: x => x.name,
      })!
    }

    if (!name) {
      throw new Error("Failed to generate a unique name for the row action")
    }

    // Create the action
    const res = await API.rowActions.create(tableId, name)

    // Enable action on this view if adding via a view
    if (viewId) {
      await Promise.all([
        this.enableView(tableId, res.id, viewId),
        automationStore.actions.fetch(),
      ])
    } else {
      await Promise.all([
        this.refreshRowActions(tableId),
        automationStore.actions.fetch(),
      ])
    }

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Pass an explicit unique name when creating the row action
  2. Ensure existing row actions all have valid name fields so getSequentialName can increment correctly
  3. Check for an empty-string name — falsy strings hit this throw too
  4. Retry creation; transient state inconsistency may have caused the generator to fail

Example fix

// before
await rowActions.create(tableId, "")
// after
await rowActions.create(tableId, "My custom action")
Defensive patterns

Strategy: validation

Validate before calling

if (!name?.trim()) {
  name = `New row action ${Date.now()}`
}

Type guard

const hasName = (n: string | undefined | null): n is string =>
  typeof n === "string" && n.trim().length > 0

Try / catch

try {
  await rowActions.create(tableId, name)
} catch (e) {
  if (e.message.includes("unique name for the row action")) {
    await rowActions.create(tableId, `New row action ${Date.now()}`)
  } else throw e
}

Prevention

When it happens

Trigger: Calling RowActionStore.create without a name while getSequentialName fails to produce a unique sequential name (its result coerced to null), e.g. if existingRowActions is malformed or the name-extractor getName returns undefined for entries.

Common situations: Creating row actions in bulk with race conditions; corrupted table metadata where existing actions lack name fields; passing an empty string name which is falsy and triggers the throw.

Related errors


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