## TL;DR

Shrink the batches, stop concurrent jobs from touching overlapping records, and retry the failed batches with exponential backoff. Row locks are contention, not corruption - the fix is less parallelism against the same rows, not a different API.

```text
salesforce Bulk API 2.0 'job failed: row lock contention' on agent mass update
```

## Steps

1. Reduce the batch size so fewer records - and fewer shared parents - are processed per batch. Expected: lock failures drop; more batches succeed on the first attempt.

2. Group records by parent (account, opportunity) so one batch does not contain rows fighting over the same parent lock. Expected: batches touching the same parent are serialized instead of colliding.

3. Retry failed batches with exponential backoff plus jitter, a few attempts before giving up. Expected: transient contention clears on retry and the job completes.

4. Do not run two mass-update jobs against overlapping record sets at the same time. Expected: no two active jobs compete for the same rows.

## Use this when

- a Bulk API 2.0 job fails with row lock contention
- mass updates fail intermittently and succeed on retry
- parallel jobs update records under the same accounts

## Not for this skill when

- rows rejected for validation errors - fix the data, not the batching
- jobs failing at submit time for auth or permission reasons
- malformed input files - those fail before any locking happens

## Variant phrasings

### row lock contention on mass update

Same root cause: concurrent transactions locking the same parent rows.

### Bulk API job failed with locking errors

Same fix: smaller batches, serialized parents, backoff retries.

### UNABLE_TO_LOCK_ROW in bulk results

Same fix: contention handling, not data fixes.

## Why it happens

Salesforce locks parent rows while child records update - when two transactions touch children of the same account, the second waits for the first's lock, and if it waits too long it fails instead of queueing forever. Bulk batches that mix records across shared parents, or two jobs running concurrently over the same accounts, manufacture this collision. It is timing-dependent, which is why the same job sometimes passes and sometimes fails.

## Edge cases

- Triggers and flows can lock additional rows beyond the obvious parents - contention may persist until the automation is considered.
- Highly-shared parents (a single account owning thousands of contacts) may need single-threaded batches for that parent.
- Serial mode on the bulk job trades speed for safety - use it for the contentious object, keep parallel for the rest.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_BM_harcbHe3g_3qAI89SkA
