Situation is I have simple mechanism, which sends messages from apex trigger to our processing server. My trigger framework creates object for every change and save it to the WorkflowQueue__c. There is job running which periodically withdraws items from WorkflowQueue__c table and sends them asynchronously outside SF.

Issue: When change on User object occurs, there is supposed to be inserted new object to the given table, but I get such message:

System.DmlException: Insert failed. First exception on row 0; first error: MIXED_DML_OPERATION, DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa): WorkflowQueue__c, original object: User: []

Why is this happening? WorkflowQueue__c contains only some string and original User object is not edited/update. I cannot see why apex prevents me from inserting such unrelated object. I would by grateful for explanation. Thank you

  • If user record not changed and you are not updating that changed then why you are defecting changes? – Santanu Boral Jul 27 '18 at 13:09

Setup objects are objects that are used to interact with the metadata. One common example is the User object. Take a look at this for more information: Setup Objects (https://developer.salesforce.com/docs/atlas.en-us.api_tooling.meta/api_tooling/reference_objects_setup.htm). Every other objects like those which are native(Standard Objects) and Custom Objects fall into the category of Non-Setup Objects.

Now it is not that you cannot perform CRUD operations on Setup Object records. You can definitely do DMLs on the Setup Objects but not in the same transaction where you're peforming DMLs on Setup and Non-Setup Objects simultaneously. So in other words in a piece of Apex Code you cannot use INSERT / UPDATE / DELETE commands on one set of Setup Objects and one set of Non-Setup Objects together.

You'll have to forcefully perform the DMLs on the Setup Objects in a seperate transaction. One way to handle this(to put them in a different transaction) is to wrap the code(to process Setup objects) in a different Apex Class and in it's own @future annotated method. This would run the code in a different transaction.

Other options includes spawning Batch Apex etc. all of which has an advantage of = "they run in a different transaction" unit.

| improve this answer | |
  • 1
    Ah, you beat me to the answer. I'd probably suggest using a queueable class over an @future method, but either could be made to work. – Derek F Jul 27 '18 at 13:09

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