1

I have a field on Contact object that is called Test__c. It is Text(18), unique & external Id. I'm trying to upsert a list of Contacts by the Test__c field. The last Contact on the list has the same value on Test__c as the first one. When I'm trying to upsert list of 199 Contacts the error is thrown: System.DmlException: Upsert failed. First exception on row 0; first error: DUPLICATE_VALUE, Duplicate external id specified: 1: [Test__c] When I change number of Contacts to 201, error is not thrown. 200 records are inserted and 1 is updated.

Here is my sample code:

List<Contact> contacts = new List<Contact>();
for(Integer i = 1; i<=199; i++){
    contacts.add(
        new Contact(
            LastName = 'TestName' + i,
            Test__c = String.valueOf(i)
        )
    );
}

contacts.add(
    new Contact(
        LastName = 'Updated name',
        Test__c = '1'
    )
);

upsert contacts Test__c;

It looks like 'upsert' processes list by 200 records and then treat another 200 records as another bulk for upsert. Can someone confirm this? I cannot find anything about it in documentation.

(In my project I will be provided a list from integration with another system and I thougt about catching errors during upsert to show it to customer that they have duplicates in their database, but it looks its not possible this way).

1 Answer 1

2

It isn't specifically "upsert" that is doing this, but rather the DML infrastructure. Bulk updates are processed in chunks, so when triggers are invoked they only receive up to 200 SObjects at a time:

Beyond the Basics

Triggers execute on batches of 200 records at a time. So if 400 records cause a trigger to fire, the trigger fires twice, once for each 200 records.

You are seeing that the duplicate external ID checks are applied to the set of objects that would be passed to a trigger invocation together.

NB: With some extra searching I found reference to where Platform Event trigger-based consumers are given up to 2000 platform events. This isn't relevant in your case, of course.

4
  • I guess it's true, but it's pretty misleading when documentation states that: "If the key is matched multiple times, then an error is generated and the object record is neither inserted or updated." Feb 27, 2020 at 11:53
  • Perhaps you could raise this question with Salesforce support?
    – Phil W
    Feb 27, 2020 at 13:05
  • 1
    Sorry about being pedantic, but not all triggers have a max of 200. Certain triggers can have as many as 2000. A little clarification might help avoid future problems.
    – sfdcfox
    Feb 27, 2020 at 15:27
  • It's OK to be pedantic though it would be better if you could explain the cases where a trigger can receive more than 200 rather than leaving it hanging in the air. AFAIK it is only batches that can increase to 2000 as a scope size but even then the trigger is invoked with 200 objects at a time. I'm happy to learn when this isn't the case!
    – Phil W
    Feb 27, 2020 at 22:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .