Loading

Error 'Exception.getStackTraceString does not expose' seen in async context

Дата публикации: Jun 26, 2023
Описание

There is a Managed package in which Exception.getStackTraceString() is being used. When the code is called in a synchronous manner, the exception is being thrown by a non-managed class which is being called from managed package class which was initially invoked from a non-managed context. In this context, the complete error message is thrown.

However, if the same managed class is schedule for asynchronous operation, the only thing that is seen under error details is parenthesis () and no error message as the async operation begins under the managed package context.

Below is the code for reference:

Apex Class Thrower (Part of Managed Package) :
 
global class Thrower implements Queueable {
    
    String namespacePrefix;
    String className;
    
    global Thrower(String namespacePrefix, String className) {
        this.namespacePrefix = namespacePrefix;
        this.className = className;
    }
    
    global void execute(QueueableContext context) {
        try {
            Type reflector = Type.forName(this.namespacePrefix, this.className);
            Object impl = reflector.newInstance();
        } catch (Exception e) {
            throw new StringException(e.getStackTraceString());
        }
    }
    
}

Apex Class ThrowerTest (part of Managed Package) :
 
@IsTest class ThrowerTest {
    
    public class Impl {
        public Impl() {
            throw new StringException('got here');
        }
    }
    
    static testmethod void testGood() {
        
        
        String namespacePrefix = '';
        String className = Impl.class.getName();
        
        try {
           
            Test.startTest();
            Queueable job = new Thrower(namespacePrefix, className);
            System.enqueueJob(job);
            Test.stopTest();
        } catch (Exception e) {
           
            System.assertNotEquals('()', e.getMessage(), 'wrong message');
        }
    }
    
}

Apex Class ThrowerService (Outside the Managed Package) :
 
global class ThrowerService { 
global ThrowerService() { 
throw new StringException('got here'); 
} 
}

 
Решение

This behavior is working as designed. The main factor here is invoking user execution context. The differences for sync and async executions producing different results are as follows:

SYNCHRONOUS:
  • In this example we are instantiating the managed package object via the execute anonymous entry point: new MANAGED_NAMESPACE.Thrower('', 'ThrowerService').execute(null); 
  • The executing user is You via execute anonymous. Please note that your namespace is blank or empty.
  • The execute method is fired as specified (again invoking user is You) and it attempts to go and instantiate the local class type.
  • So far the namespace stack for execution looks like: <blank> -> MANAGED_NAMESPACE -> <blank>
  • In this example, the non-managed class is the one throwing the exception. Note that the exception has been thrown in the <blank> namespace umbrella.
  • The only way this exception stack trace will execute is, if the invoking user context is allowed to log the Namespace. In this case, it WILL, because the exception was thrown within the <blank> namespace.

ASYNCHRONOUS:
  • In an async operation, the invoking user is again YOU via anonymous but only up to the point of enqueuing the queueable class *from the* Managed Package.
  • When the async job starts to execute, the invoking user context of that separate and new operation is coming from within the managed package.
  • Namespace execution stack now looks like: MANAGED_NAMESPACE -> <blank>
  • When evaluating if we are to expose the stack to the end user (in this case the Apex Jobs log available to the subscriber of the package), we are checking to see who started this transaction. In this case, the transaction was kicked-off from within the managed namespace. So, if the managed namespace sees any issues, it will be exposed only within the umbrella of the managed package namespace even if the exception was generated/thrown in the <blank> namespace.

Notes: 
  • When the managed package debug Logs are enabled, you can see the complete stack trace in results.
  • In all, the obfuscation, or hiding of the stack trace is to protect the Partner from exposing any proprietary implementation details.
  • Any sort of exception handling and resolution would need to happen within their managed package if the managed package was the one that began the transaction instead of re-throwing information back up to the subscribing user.
  • The other alternate solution would be to have us enable logging within a subscriber org temporarily if any troubleshooting is required.
Номер статьи базы знаний

000383964

 
Загрузка
Salesforce Help | Article