Budibase/budibase · error · HTTPError

Row not found

Error message

Row not found

What it means

Thrown by run in packages/server/src/sdk/workspace/rowActions/crud.ts when a sourceId view is supplied and a row search on that view (query equal _id = rowId, limit 1) returns no rows. This guards execution so a row action only runs for rows actually visible through the given (non-calculation) view.

Source

Thrown at packages/server/src/sdk/workspace/rowActions/crud.ts:260

  rowActionId: any,
  rowId: string,
  user: User,
  sourceId?: string
) {
  const table = await sdk.tables.getTable(tableId)
  if (!table) {
    throw new HTTPError("Table not found", 404)
  }

  if (sourceId && isViewId(sourceId)) {
    const result = await sdk.rows.search({
      tableId,
      viewId: sourceId,
      query: { equal: { _id: rowId } },
      limit: 1,
    })
    if (!result.rows.length) {
      throw new HTTPError("Row not found", 404)
    }
  }

  const { automationId } = await get(tableId, rowActionId)
  const automation = await sdk.automations.get(automationId)

  const row = await sdk.rows.find(tableId, rowId)
  await triggers.externalTrigger(
    automation,
    {
      fields: {
        id: row._id,
        revision: row._rev,
        row,
        table,
      },
      user,
      appId: context.getWorkspaceId(),

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Verify the rowId exists and satisfies the view's filters, or run the action with the table's base source (omit sourceId) if the view filter is excluding it legitimately.
  2. Confirm the rowId belongs to the same tableId as the row action.
  3. Re-fetch the row before running the action to handle deletion races.

Example fix

// before
await rowActions.run(tableId, rowActionId, rowId, user, viewId) // row filtered out of view
// after
const visible = await sdk.rows.search({ tableId, viewId, query: { equal: { _id: rowId } }, limit: 1 })
if (visible.rows.length) await rowActions.run(tableId, rowActionId, rowId, user, viewId)
Defensive patterns

Strategy: validation

Validate before calling

const result = await sdk.rows.search({
  tableId,
  viewId: sourceViewId,
  query: { equal: { _id: rowId } },
  limit: 1,
})
if (!result.rows.length) throw new Error(`Row ${rowId} is not visible through view ${sourceViewId}`)

Try / catch

try {
  await rowActions.run(tableId, rowActionId, rowId, user, viewId)
} catch (e) {
  if (e instanceof HTTPError && e.status === 404 && e.message === "Row not found") {
    // retry with table-level source (omit sourceId) or skip — row filtered/deleted
  } else throw e
}

Prevention

When it happens

Trigger: Calling run(tableId, rowActionId, rowId, user, viewSourceId) where the row does not exist, exists but is filtered out by the view's query/filters, or belongs to a different table.

Common situations: Running actions against rows hidden by view filters — the row exists in the table but not in the view; passing a rowId from another table; the row was deleted between listing and running the action.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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