I need to preface this with the statement that I am not a developer. I've inherited an instance that contains some apex triggers that I'm trying to tighten.

I'm attempting to make a minor update to a trigger on the Opportunity object that does not apply a validation if the logged in user is a System Admin.

The current code in production reads:

  if (opp.StageName != 'Pursuit' && opp.StageName != 'Renewal Anticipated') {
                if (!noConRole.contains(opp.Id)) {
                    if (changeCount > 0) {
                        opp.addError('You must add a Contact Role -- convert a Lead and add to this Opportunity, or add an existing Contact to the Opportunity -- before updating the Opportunity.');

My revision in a sandbox, which solves the issue of allowing a Sys Admin to bypass the validation, is:

    if (opp.StageName != 'Pursuit' && opp.StageName != 'Renewal Anticipated'**&& UserInfo.getProfileId().subString(0,15) != '00e4W00000#####'**) {
                    if (!noConRole.contains(opp.Id)) {
                        if (changeCount > 0) {
                            opp.addError('You must add a Contact Role -- convert a Lead and add to this Opportunity, or add an existing Contact to the Opportunity -- before updating the Opportunity.');

When I validated the changeset in Production, I received the following error:

Class Name ConvertLeadsInvocableTest

Method Name test_convert_lead_no_opportunity

Error Message System.DmlException: ConvertLead failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, Converted objects can only be owned by users. If the lead is not owned by a user, you must specify a user for the Owner field.: [OwnerId] Stack Trace: Class.ConvertLeadsInvocable.convertLeads: line 108, column 1 Class.ConvertLeadsInvocableTest.test_convert_lead_no_opportunity: line 78, column 1

Lines 106 - 112 of ConvertLeadsInvocable look like this:

    **// convert leads, all or none
    // if any has error then exception is thrown automatically and changes rolled back
    List<Database.LeadConvertResult> convertResults = Database.convertLead( convertRequests, true );
    // transform the database convert results to invocable result
    List<LeadConvertResult> results = new List<LeadConvertResult>();
    for ( Database.LeadConvertResult convertResult : convertResults ) {
        results.add( transform( convertResult ) );**

We are experiencing no issues with our code in production. The issue only arises when I attempt to validate and deploy this exemption to the trigger on the Opportunity.

What do I need to provide in these classes to prevent the validation from attempting to convert a lead with no owner? And what other information can I provide to shed more light on what's going on?

1 Answer 1


This pattern:

UserInfo.getProfileId().subString(0,15) != '00e4W00000#####'

is generally unwise because it creates fragility in your code. For example, hard-coded Ids can differ between sandboxes and production depending on the specific processes you use to create and deploy components. That's not a real risk with the System Administrator profile, but it's a pattern to avoid in general.

This pattern also reduces your maintainability. Every time you want to alter the behavior, you must edit Apex and perform a deployment.

A safer and more maintainable pattern is to use a Custom Permission. Assign this permission to one or more Profiles or Permission Sets, then check for it in Apex:


Then, you can control where exactly this bypass is available based on how you apply the Custom Permission - including retaining the ability to have the check turned off for the users where you run tests. You'll probably want to apply the permission only to some subset of your (human) System Administrator users, excepting the user where you perform deployments.

As an aside, I generally believe it is a bad idea to allow anyone to bypass triggers, as you create situations where you no longer have clarity on which data invariants are being enforced in your org.

  • Thanks David. I agree with your perspective of not allowing exceptions. While I do want to learn how to solve basic issues like the one I've described, I'm going to push back in this instance and work with the sales team to appropriately close out these opps. Jan 18, 2022 at 2:10

You must log in to answer this question.

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