Budibase/budibase · error · Error

Failed to copy ${failed.length} row(s) after ${ROW_WRITE_RET

Error message

Failed to copy ${failed.length} row(s) after ${ROW_WRITE_RETRIES} attempts.

What it means

A plain Error thrown by bulkInsertRows when, after the maximum ROW_WRITE_RETRIES attempts with exponential backoff, some rows still failed to write to the destination table during a row-copy/duplication operation. `failed.length` rows could not be persisted.

Source

Thrown at packages/server/src/sdk/workspace/resources/index.ts:662

    let attempts = 0
    while (pending.length && attempts < ROW_WRITE_RETRIES) {
      attempts++
      const response = (await destinationDb.bulkDocs(pending)) as Array<{
        error?: unknown
      }>
      const failed: AnyDocument[] = []
      response.forEach((result, idx) => {
        if (result.error) {
          failed.push(pending[idx])
        }
      })

      if (!failed.length) {
        break
      }

      if (attempts >= ROW_WRITE_RETRIES) {
        throw new Error(
          `Failed to copy ${failed.length} row(s) after ${ROW_WRITE_RETRIES} attempts.`
        )
      }

      await delay(attempts * 250)
      pending = failed
    }
  }
}

async function duplicateInternalTableRows(
  tables: WithDocMetadata<Table>[],
  destinationDb: ReturnType<typeof db.getDB>,
  fromWorkspace: string,
  toWorkspace: string
) {
  if (!tables.length) {
    return

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Inspect the logged failed row batch to find the per-row write error and fix the offending data (schema mismatch, invalid types)
  2. Retry the copy operation once transient DB pressure has passed
  3. Reduce batch size or copy rows in smaller chunks to avoid timeouts/conflicts
  4. Verify CouchDB health (disk space, cluster status) before re-running large copies

Example fix

// before
await duplicateInternalTableRows(table) // bulk, all rows at once
// after
// catch and re-run only the failed subset, or pre-validate rows
try {
  await duplicateInternalTableRows(table)
} catch (e) {
  // inspect failed rows log, repair schema/data, retry
}
Defensive patterns

Strategy: retry

Validate before calling

// pre-validate rows against the destination table schema before bulk insert
const valid = rows.every(r => Object.keys(r).every(k => k in table.schema))

Type guard

function matchesSchema(row: Record<string, unknown>, table: Table): boolean
  return Object.keys(row).every(k => k in table.schema)

Try / catch

try {
  await duplicateInternalTableRows(table)
} catch (e) {
  if (/Failed to copy .* row\(s\)/.test(e.message)) {
    // inspect failed-row logs, fix schema/data, then retry the operation
  }
  throw e
}

Prevention

When it happens

Trigger: bulkInsertRows repeatedly failing a subset of rows across all retry rounds — persistent CouchDB write errors, validation rejections (invalid row data for the target table schema), quota/disk issues, or rows conflicting with unique constraints in the destination table.

Common situations: Copying rows into a table whose schema changed (columns removed/renamed since the copy started); CouchDB instability or replication conflicts during large copies; destination DB read-only or out of disk; very large bulk copies timing out against a loaded cluster.

Related errors


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