DUPLICATE_VALUE:duplicate value found: External_Id__c duplicates value on record with id: 001Hs00001ABcDeIAJ:--
The short answer: a field with the Unique attribute refuses to hold the same value twice, and this load is trying to write a value that is already taken. There are two completely different reasons for that. Either the duplicate is inside your file — two rows carrying the same key — or the record already exists in Salesforce and you are inserting where you needed an upsert. Work out which one before you change anything: the fixes do not overlap.
Read the error before you touch the file
The message hands you the diagnosis: the field carrying the unique constraint, and the Id of the record that already holds your value. Open that record and look at Created Date.
| The record named in the error was… | What actually happened | The fix |
|---|---|---|
| Created moments ago, by you, in this same job | Your file holds that key twice. The first row was written; the second collided with it. | De-duplicate the file — situation A |
| Created weeks or months ago, possibly by someone else | The record already exists. You are inserting something that should be an update. | Upsert on an External ID — situation B |
| Created earlier today, by you, in a previous run | A partially successful load. A Bulk API job is not rolled back when records fail — the successful rows stay committed, so re-submitting the whole file re-inserts them. | Upsert, or load only the rows that failed |
Situation A — duplicates inside your file
The first row to be processed takes the value, and every later row carrying it is rejected against that row. So the error log names the repeats, and the Id it points at is a record your own job created moments earlier — the tell for situation A. Note what that means for your error file: the rows listed are the ones that did not load, so deleting them from the file does not undo the copy that did.
An upsert does not rescue you either. Salesforce's API documentation is explicit: when the same external ID value appears for two or more records in the same batch call, those records are marked as errors in the upsert results. The Data Import Wizard says the same thing in its own words — multiple records sharing an External ID within one file are not uploaded. A repeated key is a problem in the file, whichever operation you run.
Find every duplicate in Excel
-
Add a helper column beside your key column and fill it down. If the key is in column B:
Filter that column to values greater than 1 and you have every offending row, not just the ones the error log mentioned.=COUNTIF($B$2:$B$100000, B2) - To collapse them: Data → Remove Duplicates, ticking only the key column. Tick every column and Excel removes only rows identical across all of them — which leaves your actual duplicates in place.
The trap: which row survives
Remove Duplicates keeps the first occurrence it meets and silently discards the rest.
It does not ask which row is correct, and it does not merge. If your two rows for ACME-001
disagree — one carries a phone number, the other the billing address — you lose whichever sat lower in
the sheet.
- Sort first, then de-duplicate. Put the row you want on top — most recently modified, most complete — and Excel keeps it.
- Merge rather than discard when the rows are complementary. A "duplicate" with a different Owner or Amount is often two real records sharing a bad key, not one record typed twice.
Situation B — the record already exists in Salesforce
An insert has no opinion about what is already in the org: it creates. An upsert does. You nominate a field as the key, and Salesforce looks for a record whose key matches. Per the API documentation, three cases:
- No match → a new record is created.
- Exactly one match → that record is updated.
- More than one match → an error (
DUPLICATE_EXTERNAL_ID, which Salesforce defines as a user-specified external ID matching more than one record during an upsert).
Set up the External ID field
Setup → Object Manager → your object → Fields & Relationships → New. The key is a custom text, number, or email field — those are the types that can carry both attributes you need. Tick both checkboxes; they are not the same thing:
- External ID — makes the field usable as an upsert key and indexes it. On its own it does not stop duplicates; Salesforce documents that records may share an External ID value.
- Unique — the constraint that actually enforces it, and the one that produced your error. It also makes the upsert safe: without it, your key can match two records and the upsert fails.
The default limit is 25 External ID fields per object; going beyond it means asking Salesforce Support for an increase.
Run the load as an upsert
| Tool | What to do |
|---|---|
| Data Loader | Choose the Upsert operation, then select your External ID field when prompted. |
| Bulk API 2.0 | Create the job with operation set to upsert and externalIdFieldName set to the field's API name. The column must be present in the file. |
| Data Import Wizard | For Accounts, Contacts, and Leads, set Match by to your External ID field — it must be marked External ID and Unique to appear there. The Wizard has other limits worth knowing first. |
The payoff: re-running the same file updates the same records instead of duplicating them. The catch: upsert writes. A wrong or blank value in your file overwrites the good value in the org. An upsert is not a safer insert — it is an insert and an update at once.
No External ID at all? Then you cannot upsert. Add one and backfill it, or export the Ids of the existing records — a report, or Data Loader's Export — VLOOKUP them into your file on some natural key, and split it: rows without a match become an insert, rows with one an update by Id. That is the manual version of upsert, and it is as fragile as it sounds.
The error that looks identical but is not
If your error says DUPLICATES_DETECTED, or Data Loader shows
"Use one of these records?", that is a different feature: Duplicate Rules
and Matching Rules, configured by an admin in Setup. They evaluate records created
through the API and Data Loader, not only through the UI.
DUPLICATE_VALUE |
DUPLICATES_DETECTED | |
|---|---|---|
| Source | A unique index on one field | A duplicate rule an admin wrote |
| Comparison | Exact match on that field | Fuzzy matching across names, emails, addresses |
| Tells you | The field, and the Id of the colliding record | That your row resembles existing records |
| Fix | De-duplicate the file, or upsert | Review the rule; correct, merge, or accept the record |
Be clear-eyed here: no file-side tool can predict a duplicate rule. The rule lives in your org, the matching is fuzzy, and it compares every row against every record already in Salesforce. The same goes for validation rules, triggers, and Flows — anything reading only your file and your org's field metadata cannot know what your org's automation will decide at save time.
Stop producing the error in the first place
Two habits retire it: make the key unique in the file before you load, and load with an upsert so that running the same file twice is harmless rather than destructive.
INQUA's import tool is built around both. Its
row-selection rules collapse a group before anything is written — keep the first row per group, or
one row per group chosen by a condition — so three rows for ACME-001 become the one row
you meant, and the typed preview shows exactly which rows will be sent, and how many the rule
dropped. When you connect Salesforce, the load can run as a Bulk API 2.0
External-ID upsert rather than an insert — reviewed, then confirmed in a second
step — so a re-run updates the record it matched instead of colliding with it. It never deletes,
never updates by record Id, and refuses a byte-identical repeat upload unless you tell it to go
ahead.
What it will not do is guess at your org's duplicate rules, validation rules, or triggers — see above. It flags what it can genuinely see: per-cell type errors and values a restricted picklist would reject, and it refuses the Salesforce upload outright while any cell error remains. It also works with no Salesforce connection, writing the cleaned rows into your own .xlsx load template. Free during early access.
After the fix
Re-run and reconcile the counts: rows in the file, records created, records updated. If new errors appear, check they are actually the same error — a duplicate key often masks missing required fields and type-conversion failures that surface only once rows get far enough to be validated. Still choosing how to load? See the mapping and row-rule options and the full error index.