0

I had a trigger that fired from webhook, this trigger receive JSON that contain external Id for account object, inside the trigger I do an upsert on account object using the following code

Database.upsert(accountrecord, external_id__c)

but sometimes for unknown reason I got the following exception

System.DmlException: Upsert failed. First exception on row 0; first error: DUPLICATE_VALUE, duplicate value found: External_Id__c duplicates value on record with id: 0011x00000Gc4LI: [] 

I tried to add SOQL query to retrieve the account record with the external Id I have to testing purpose and I didn't get any records!

New Update:

I think it's related to this known issue, they said that it solved in Summer 18, but I'm still facing this issue.

https://success.salesforce.com/issues_view?id=a1p3A0000018BWdQAM&title=duplicate_value-exception-shows-unknown-for-duplicate-field-if-before-trigger-is-invoked-on-dml-and-contains-update-insert-on-any-object

5
  • Could is your JSON returning duplicates IDs? Did you check it?
    – m Peixoto
    Feb 28 '19 at 11:23
  • Yes sometimes it return the same external Id, but what's the purpose of upsert if it couldn't handle duplicate records Feb 28 '19 at 11:26
  • are you using a list in this line? Database.upsert(accountrecord, external_id__c) If yes, I suggest to use a Set. I am not sure, but I believe it could be your issue.
    – m Peixoto
    Feb 28 '19 at 11:30
  • It's one record only not list Feb 28 '19 at 11:32
  • There's no answer on this post, so that's why I post. Feb 28 '19 at 11:36
2

You say you are upserting only one record? That is odd. The way I can reproduce a DUPLICATE_VALUE error on upsert is to use a list of multiple records against an external ID, where several have the same External ID. This will always throw an exception because DML on a list is meant to be simultaneous not sequential. If you include two contradictory records it doesn't know which is supposed to be "final".

EDIT: Possibly a concurrency issue? Transaction B initiates the upsert before Transaction A is committed, so it commences as an insert. But by the time it commits, Transaction A has already committed and now there's a duplicate value.

I wouldn't suggest a blind retry. Maybe you could check the Database.UpsertResult for this specific DUPLICATE_ID error, and if you get it, query a second time and do an explicit Update instead? If not, re-throw the error so that you get an Apex exception e-mail.

9
  • Actually you are right when there's list of records, but in my case I'm handling one record, I think the problem because of the trigger, I created webhook that receive JSON from third party service, then the webhook create record on a custom object with name Log, and I have trigger on this object that read the JSON and parse it, so I found that same external Id sent to webhook at the same time but with with two different calls, when the trigger executed it couldn't find the record that created by the other one, that's weird, right! Feb 28 '19 at 14:14
  • 1
    Interesting. Possibly a concurrency issue? Transaction B initiates the upsert before Transaction A is committed, so it commences as an insert. But by the time it commits, Transaction A has already committed and now there's a duplicate value.
    – Charles T
    Feb 28 '19 at 19:10
  • Yeah that's what I'm thinking about, do you think using @future method will solve the issue? Mar 1 '19 at 7:42
  • I mean, it could, but it still doesn't offer any protection against conflict. And then you lose the ability to respond synchronously as to whether the transaction succeeded. Maybe you could check the Database.UpsertResult for this specific error, and if you get it, query a second time and do an explicit Update instead?
    – Charles T
    Mar 1 '19 at 12:21
  • I think your solution is similar to this blog post: sfdcdev.wordpress.com/2011/07/08/… Mar 1 '19 at 14:20

Not the answer you're looking for? Browse other questions tagged or ask your own question.