I am trying to expose a REST API so the field permission of permission set(s) can be updated. I am trying to use MetadataService as below:

global class UtilitiesAPI {
    global static String updateFieldPermission(List<FieldPermisionPutRequestWrapper> fieldPermisionPutRequestWrapperList){
            System.debug('Started updateFieldPermission');
            MetadataService.MetadataPort service = new MetadataService.MetadataPort();
            Map<String, FieldAccess> objectFieldToFieldAccessMap = new Map<String, FieldAccess>();
            service.SessionHeader = new MetadataService.SessionHeader_element();
            service.SessionHeader.sessionId = UserInfo.getSessionId();
            return null;
        catch(Exception exceptionObject){
            System.debug('Exception occurred. Error message=' + exceptionObject.getMessage());
            System.debug('Stack trace=' + exceptionObject.getStackTraceString());
            return null;

But getting error like this:

16:23:51.781 Starting SFDX: Deploy Source to Org

=== Deploy Errors
PROJECT PATH                                     ERRORS                                                     
───────────────────────────────────────────────  ───────────────────────────────────────────────────────────
force-app\main\default\classes\UtilitiesAPI.cls  Invalid type: MetadataService.MetadataPort (7:13)          
force-app\main\default\classes\UtilitiesAPI.cls  Invalid type: MetadataService.SessionHeader_element (9:37)
force-app\main\default\classes\UtilitiesAPI.cls  Variable does not exist: service.SessionHeader (10:13)     
force-app\main\default\classes\UtilitiesAPI.cls  Variable does not exist: service (9:13)                   

16:23:54.589 ended SFDX: Deploy Source to Org

Can someone please help me know what I am missing here or should try other approach?

  • What is the request body? Also as its an API, did you check if the required access is available? Commented Jan 3, 2023 at 11:23
  • The updateFieldPermission API access is there. But here issue is with MetadataService.MetadataPort. Even if we want to update the field permissions in permission sets via Apex(be it trigger or batch etc) then what should be the approach? Commented Jan 3, 2023 at 11:27
  • 1
    What is your requirement? YOu need to share an API to achieve what? Also share your request body too with which you are trying. Commented Jan 3, 2023 at 14:32
  • I need to update the field permissions via Apex. I will expose the method via REST so external entities can also use the same. But right now I am not even able to save the apex class. The REST part will come later. For now we just need to create a class which can update field permissions in the permission set. Commented Jan 4, 2023 at 7:10

1 Answer 1


I have two ways to resolve your problem -

  1. Via Metadata Api using the library from FinancialForce, your errors are showing that you haven't imported the library. you can get it at - https://github.com/financialforcedev/apex-mdapi/tree/master/apex-mdapi/src/classes

All you need to do is copy the MetadataService class and save it into your org.

once done add the below method to your UtilitiesAPI class-

    public static MetadataService.MetadataPort createService()
            MetadataService.MetadataPort service = new MetadataService.MetadataPort();
            service.SessionHeader = new MetadataService.SessionHeader_element();
            service.SessionHeader.sessionId = UserInfo.getSessionId();
            return service;     

Now, your errors will be resolved.

Get the profile and update custom permission -


       MetadataService.MetadataPort service = createService(); 
        MetadataService.Metadata[] records = readResult.getRecords();
        MetadataService.Profile prfile =  new MetadataService.Profile();
        prfile.fullName = 'profile name';
        prfile.custom = false;
       MetadataService.ProfileFieldLevelSecurity fieldSec = new MetadataService.ProfileFieldLevelSecurity();
            prfile.fieldPermissions  = new MetadataService.ProfileFieldLevelSecurity[] {fieldSec} ;
                List<MetadataService.SaveResult> results =
                    new MetadataService.Metadata[] { prfile });
    public static void handleSaveResults(MetadataService.SaveResult saveResult)
            // Nothing to see?
            if(saveResult==null || saveResult.success)
            // Construct error message and throw an exception
                List<String> messages = new List<String>();
                    (saveResult.errors.size()==1 ? 'Error ' : 'Errors ') +
                    'occured processing component ' + saveResult.fullName + '.');
                for(MetadataService.Error error : saveResult.errors)
                        error.message + ' (' + error.statusCode + ').' +
                        ( error.fields!=null && error.fields.size()>0 ?
                         ' Fields ' + String.join(error.fields, ',') + '.' : '' ) );
                    System.debug(' message '+messages);
                System.debug(' failure ');

  1. Via FieldPermission - I can't say this will be a perfect solution but it'll allow you to add and update the permission -

Add Permission -

FieldPermissions fp= new FieldPermissions();
fp.Field='Account.Phone';//the name of new field
fp.ParentId='0PS5g000009W5BH';// id of permission set 
Insert fp; 

Update Permission -

FieldPermissions fps = [SELECT SobjectType, Field, PermissionsRead, Parent.Name FROM FieldPermissions WHERE SobjectType='Account' AND Field='Account.Phone' AND ParentId='0PS5g000009W5BH' LIMIT 1];
fps.PermissionsEdit = false;
update fps;

To grant a user access to a field, associate a FieldPermissions record with a PermissionSet that’s assigned to a user. FieldPermissions records are only supported in PermissionSet, not in Profile.

You must log in to answer this question.

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