MetricSign
Start free
Medium severityresource

SQL Server Error:
3960

What does this error mean?

Error 3960 fires when two concurrent transactions under SNAPSHOT isolation both read the same row and then try to update it. SQL Server detects the write-write conflict and aborts the second transaction immediately — the first committer wins. In a data-pipeline context (ADF, Synapse, or a custom ETL), this typically surfaces as a failed activity with error code 3960 in the pipeline run output. The engineer sees the pipeline activity turn red, and downstream Copy or Dataflow activities that depend on the failed step are skipped. On the SQL Server side, the aborted session receives Msg 3960 and the transaction is rolled back entirely — no partial writes land in the target table.

Common causes

  • 1Two transactions using SNAPSHOT isolation both read the same row and then attempt to update it — SQL Server aborts the second committer with error 3960
  • 2Long-running snapshot transactions (e.g. a large MERGE in ADF) that overlap with frequent writes to the same staging or dimension tables
  • 3ADF pipeline activity using snapshot isolation conflicts with a concurrent user query or another ETL job writing to the same target table
  • 4Concurrent ADF pipeline runs triggered by overlapping tumbling-window or schedule triggers that both update the same partition or key range
  • 5Stored procedures called from multiple sessions that SET TRANSACTION ISOLATION LEVEL SNAPSHOT and then perform conditional UPDATEs on a shared lookup table

How to fix it

  1. 1Step 1: Add retry logic — error 3960 is inherently transient. In ADF, set the activity retry count to 2 and retry interval to 30 seconds in the activity JSON: "policy": { "retry": 2, "retryIntervalInSeconds": 30 }. In application code, catch SqlException where Number == 3960 and retry.
  2. 2Step 2: Identify which rows cause the conflict. Run: SELECT * FROM sys.dm_tran_version_store_space_usage; and check sys.dm_exec_requests for sessions with isolation_level = 5 (snapshot). Cross-reference the blocking session_id with the object being updated.
  3. 3Step 3: Shorten the snapshot transaction scope. Break large MERGE statements into batches of 5,000–10,000 rows using a TOP + WHILE loop so each snapshot window is smaller and less likely to overlap with concurrent writes.
  4. 4Step 4: Switch read-heavy workloads from SNAPSHOT to READ COMMITTED SNAPSHOT (RCSI) — this avoids error 3960 for readers entirely: ALTER DATABASE [YourDB] SET READ_COMMITTED_SNAPSHOT ON; This requires a moment of exclusive DB access (no other connections).
  5. 5Step 5: Serialize conflicting writes by adding a staging-table pattern. Write ADF output to a staging table first (no contention), then run a single MERGE from staging → target in one short transaction. This eliminates the overlap window.
  6. 6Step 6: If using concurrent ADF triggers, stagger the schedule so pipeline runs don't overlap. Change the tumbling window from every 15 min to every 15 min offset by pipeline (pipeline A at :00, pipeline B at :05).
  7. 7Step 7: Monitor tempdb version store usage — snapshot isolation stores row versions in tempdb. If tempdb grows aggressively, check: SELECT * FROM sys.dm_tran_version_store_space_usage; Large version stores correlate with long-running snapshot transactions that increase 3960 risk.

Example log output

Msg 3960, Level 16, State 2, Line 14
Snapshot isolation transaction aborted due to update conflict. You cannot use snapshot isolation to access table 'dbo.dim_customer' directly or indirectly in database 'DW_Production' to update, delete, or insert the row that has been modified or deleted by another transaction. Retry the transaction or change the isolation level for the update/delete statement.

Frequently asked questions

Is error 3960 similar to a deadlock?

No. A deadlock (error 1205) is a circular lock wait between two sessions — SQL Server picks a victim and kills it. Error 3960 is a write-write version conflict under snapshot isolation: the first committer wins, the second is aborted immediately. No circular wait is involved, and the resolution is deterministic (first writer wins).

Does RCSI (Read Committed Snapshot Isolation) also cause error 3960?

No. RCSI uses row versioning for reads but still takes update locks for writes, so it resolves write conflicts the traditional way (blocking, not aborting). Only explicit SNAPSHOT isolation (SET TRANSACTION ISOLATION LEVEL SNAPSHOT or BEGIN TRANSACTION WITH SNAPSHOT) can trigger error 3960.

How do I retry error 3960 in Azure Data Factory?

In the ADF activity settings, set the retry policy: "policy": { "retry": 2, "retryIntervalInSeconds": 30 }. ADF will re-execute the activity up to 2 times after a failure. For Stored Procedure activities, ensure the SP itself is idempotent so retries don't produce duplicate data.

Can I prevent error 3960 completely?

Not if you use SNAPSHOT isolation with concurrent writes to the same rows — it is by design. You can minimize it by shortening transactions, batching writes, staggering pipeline schedules, or switching to RCSI for workloads that only need read consistency. If you need full snapshot semantics and concurrent writes, retries are the correct approach.

Source · learn.microsoft.com/en-us/sql/relational-databases/errors-events/mssqlserver-3960-database-engine-error

Other resource errors