Try Serpent Free

How to fix DUPLICATE_EXTERNAL_ID in Salesforce deployments

An upsert matches more than one existing record on the same external ID value, so Salesforce can't tell which one to update.

Surfaces during: upsert DML in data loads, integrations, and Apex

What it means

DUPLICATE_EXTERNAL_ID means an upsert call found more than one record in the target org sharing the same value in the external ID field being matched on. Upsert relies on that field being genuinely unique per record; when duplicates exist, Salesforce has no way to decide which record the incoming data should update, so it rejects the operation instead of guessing.

This is purely a data-state problem in the target org, not something wrong with the incoming payload itself; the same upsert call would succeed the moment the target org's duplicate values are resolved.

Diagnosis

Common causes

External ID field was never marked unique
The field's "Unique" attribute was left off when it was created, so nothing stopped duplicate values from being inserted over time.
Migration ran before deduping the source data
A data load inserted duplicate external ID values before anyone checked the target org already held records with those same values.
Merged systems assigned the same key twice
Two source systems independently generated the same external ID value for different records, and both landed in the same org.

The fix

  1. Dedupe records sharing the external ID first
    Query the target org for the offending value, decide which record is authoritative, and merge or delete the rest before retrying.
    SELECT External_Id__c, COUNT(Id)
    FROM Account
    GROUP BY External_Id__c
    HAVING COUNT(Id) > 1
  2. Turn on the Unique attribute on the field
    Edit the external ID field definition so Salesforce enforces uniqueness going forward and blocks new duplicates at insert time.
  3. Use a more specific composite key
    If two legitimately different records can share the base value, combine it with a second field so the match is unambiguous.
In practice

How Serpent prevents this

Serpent keeps every sandbox and scratch org synced from the same source, so duplicate external ID values from stale, hand-loaded data are far less likely to build up between environments. See the Salesforce deployment error library.

Metadata and data in one deployment flow in Serpent

Prevention

Always mark integration-facing ID fields Unique and External ID
Set both attributes the moment the field is created, before any data load has a chance to insert an unenforced duplicate.
Dedupe at the source system, not after the load
Enforce uniqueness on the external key in the system generating it, so Salesforce receives a clean value stream instead of catching the problem downstream.
Run a periodic duplicate scan on external ID fields
Schedule a recurring report or query that flags any external ID value shared by more than one record, so drift is caught before the next integration sync fails.
Common questions

DUPLICATE_EXTERNAL_ID, answered

Does DUPLICATE_EXTERNAL_ID mean my data is corrupted?
Not necessarily. It usually just means the same external ID value reached the org twice from separate loads or systems, not that anything else is wrong with the records.
Will marking the field Unique after the fact retroactively fix existing duplicates?
No. Salesforce won't let you turn on the Unique attribute while duplicate values already exist; you have to resolve the duplicates first, then apply the constraint.
Does this happen with standard upsert as well as Bulk API upsert jobs?
Yes. Both the standard upsert() DML call and Bulk API upsert jobs enforce the same uniqueness requirement on the external ID field being matched.

Start free. No credit card, no install, no commitment.

Set up in under 15 minutes. No DevOps hire needed.

Curious about faster shipping before you dive in? Let's talk

Commitment free!