DUPLICATES_DETECTED: Use one of these records?
Salesforce's Duplicate Rules engine flagged your record as a fuzzy match for an existing one. Different from `DUPLICATE_VALUE`, which is a hard unique-field constraint. The fix is either to skip the duplicate, merge with the existing record, or pass `allowSave=true` if you legitimately want to keep both.
Also seen asDUPLICATES_DETECTED·Use one of these records·duplicates detected api·duplicate rule blocked save
Duplicate Rules are configured in Setup → Duplicate Rules. They run on save and use Matching Rules to identify near-duplicates by fuzzy-matching on selected fields (Name + Email + Phone, etc.). When a rule's action is "Block", your save is rejected with this error.
How to read the response
The API returns a structured response, not just an error string:
{
"errors": [{
"statusCode": "DUPLICATES_DETECTED",
"message": "Use one of these records?",
"fields": [],
"duplicateResult": {
"allowSave": true,
"duplicateRule": "Standard_Account_Duplicate_Rule",
"duplicateRuleEntityType": "Account",
"errorMessage": "...",
"matchResults": [{
"entityType": "Account",
"rule": "Standard_Account_Match_Rule_v1_0",
"matchRecords": [{
"record": { "Id": "0016xxx", "Name": "Acme Corp" },
"matchConfidence": 0.95
}]
}]
}
}]
}
The duplicateResult.matchResults array tells you which records were flagged as duplicates and how confident the engine is.
Fix 1: skip and log
If your integration's job is "ingest new records, skip duplicates," catch the response and log:
Database.SaveResult[] results = Database.insert(records, false);
for (Database.SaveResult r : results) {
if (!r.isSuccess()) {
for (Database.Error e : r.getErrors()) {
if (e.getStatusCode() == StatusCode.DUPLICATES_DETECTED) {
// Log + skip
System.debug('Duplicate detected: ' + e.getMessage());
}
}
}
}
For REST: catch the 400 status with DUPLICATES_DETECTED and skip.
Fix 2: allowSave=true to override
If you're sure both records should exist (e.g., one is a customer, the other is a vendor that happens to share a name), pass DuplicateRuleHeader.allowSave=true:
Database.DMLOptions opts = new Database.DMLOptions();
opts.duplicateRuleHeader.allowSave = true;
opts.duplicateRuleHeader.runAsCurrentUser = true;
Database.SaveResult r = Database.insert(record, opts);
For REST, the equivalent is the Sforce-Duplicate-Rule-Header: allowSave=true HTTP header.
Fix 3: merge into the existing record
If the dupe is genuine and you'd rather merge:
// Find the matched record
List<Database.MatchRecord> matches = ...; // from the duplicateResult
Id existingId = matches[0].getRecord().Id;
// Update the existing record with new data instead of creating
Account existing = [SELECT Id FROM Account WHERE Id = :existingId];
existing.Description = newRecord.Description; // merge in
update existing;
For Contacts and Leads, Salesforce has a built-in merge DML operation that consolidates two records and reparents children. Apex merge is the formal way:
Lead master = ...; Lead duplicate = ...;
merge master duplicate; // duplicate gets soft-deleted, its children move to master
Tuning the rules
If your team is getting too many false positives, the Matching Rule is too lenient. Tune by changing matching algorithms:
- Exact match on Email + Fuzzy on Name → more permissive, fewer false positives
- Fuzzy on Email → more matches, more false positives
Setup → Matching Rules lets you adjust per-field. Test changes on a sample dataset before activating.
A common surprise: Matching Rules don't fire by default
A Duplicate Rule needs an active Matching Rule. Both must be active for the rule to fire. If you created both but only activated the Duplicate Rule, no errors fire — the engine has nothing to match against.
