function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Ali MeyerAli Meyer 

Trigger works in sandbox but not in production

I wrote a trigger that works perfectly in sandbox and has 100% test coverage and deployed it to production; now that it's in the production instance, it doesn't work. I don't get any error messages, but the thing that it's supposed to do (create a contact if a specific field is filled in) just doesn't happen. In production, it also has 100% coverage. Any ideas what's going on?


Here's the code:

trigger SpouseTrigger on Contact (before insert) {
 2	      List<Contact> cons = new List<Contact>();
 3	      List<Contact> consToInsert = new List<Contact>();
 5	      for(Contact{
 6	          if(c.Sig_Other_First_Name__c != null && c.Sig_Other_Last_Name__c != null){
 7	              cons.add(c);
 8	          }
 9	      }
 11	      for(Contact c: cons){
 12	          Contact newCon = new Contact();
 13	          newCon.FirstName = c.Sig_Other_First_Name__c;
 14	          newCon.LastName = c.Sig_Other_Last_Name__c;
 15	          newCon.AccountId = c.AccountId;
 16	          consToInsert.add(newCon);
 17	      }
 19	      insert consToInsert;
 20	  }

 Thanks for your help!

Ali MeyerAli Meyer

Also, in case it matters, I deployed the trigger by using the Change Sets inside the Setup panel (under Deploy). Maybe I didn't transfer the trigger correctly?


Some thoughts:


  1. Is the trigger status Active and Is Valid checked? Not sure if the tests would still run successfully (with full coverage) if they weren't.
  2. The trigger is only invoked when a new Contact is created (before insert). Is it possible existing Contacts are being changed? (even if not, isn't this a valid use case)?
  3. Personally I'd be inclined to have the trigger invoked after insert (and after update if appropriate). I'm not saying this is your issue, but to me it makes more sense to create the spouse Contacts after the initial Contact is created (or updated). With an after trigger you're basically saying, ok - the Contact has been created/updated, now I can go ahead and create the spouse record.

Hope this helps, if even just a little.

Jia HuJia Hu
Yes, I also think that you should check if the Trigger is Active first.

Then use debug log to check the logic.

best practice - 'before' triggers should not do DML; always do in 'after' triggers




Problem with your trigger is that it is getting stuck in recursive loop.


When you try to insert a contact this trigger will get executed. In this trigger you again insert contact and for that insert

it again calls itself. so do no put dml statement in before trigger. It would be better if you can use after insert.


Ali MeyerAli Meyer

Thanks for your input.


The trigger is active and valid, so that's probably not the cause. 


In the future I can see why an "after insert" might be better than a before, but I'm really trying to figure out why this doesn't work now but worked in the sandbox. If I can't figure it out I'll change the DML, but for now I'm hoping to keep it as is.


@Amitd: I'm not sure I understand what you're saying. The trigger code to me looks like (and should look like) it's inserting the contact and then when the trigger runs inserting an additional contact (based on Spouse fields), that doesn't have the (spouse) fields that would enable a loop. Where do you see the loop originating?


Thank you for your help! And if you have any more ideas please let me know!


Are your validation rules the same between Sandbox and PROD?


Perhaps the spouse contact fails insert due to validation rules (like no email address) that you have enabled in PROD but not sandbox; or, some workflow field update occurs in PROD that doesn't in Sandbox that also causes a validation rule failure on the spouse insertion


Another best practice:


Wrap your DML on Contact insertion with try catch (or use Database.insert and examine the result SaveResult[] array for errors. 


Because triggers should be bulkified (as you have done), the error reporting / error action should also be bulkified -  you will need to execute addError() on only the Contact's in the trigger set whose spousal contact failed insertion.


Hello Guys,


Has anyone figured out what the problem was? I am facing the same issue in an after update trigger?


Any help would be grately appreciated..

Ali MeyerAli Meyer

I ended up changing the trigger to after--as usual, the guys on here were right! Once I redeployed with the "after" it worked fine in production.


I am already using an after trigger to udpate yet it's not working in production. Could you please have a look to see what I am doing wrong??




trigger LeadSourceUpdate on Lead_Source__c (after insert, after update) {

                List<Lead_Source__c> leadupdatetrigger =;   

    //Calling Lead Source Fetcher Class

    //LeadSourceFetcher lsf = new LeadSourceFetcher();






Class Method:


 public static void LeadUpdateFromSource(List<Lead_Source__c> leadupdatetrigger){       

        List<Lead> temp = [Select id, where_hear_about_us__c, Referring_Domain__c,

                                    Search_Cookie_source__c,LeadSource from Lead where Leadsource = null limit 200];

        List<Lead> recordupdate = new List<Lead>{};

        for(Lead_Source__c ls:leadupdatetrigger){

            for(Lead l:temp){

                if((l.where_hear_about_us__c == ls.where_hear_about_us__c)&&

                   (l.Referring_Domain__c == ls.Referring_Domain__c)&&

                   (l.Search_Cookie_source__c == ls.Search_Cookie_source__c)&&

                    l.LeadSource == null){


                    l.LeadSource = ls.Lead_Source__c;

                    l.lead_source_reference__c =;





    update recordupdate;



I have solved the problem. It was my update DML operation on after update trigger. A static boolean flag helped me to break out from recursive loop. 


global Class recursionPrevent{

                Global static boolean preventflag = false;

                                Public recursionPrevent(){




inside my trigger changed the value of preventflag:


recursionPrevent.preventflag = true;


And that worked. Thanks