I implemented user preferences for a Visualforce tool using custom metadata type record to save the preferences. Although the VF controller is a "with sharing" class, it calls the (metadata api based) record update method in a separate "without sharing" class. I used custom metadata type instead of custom settings due to Salesforce's "strong recommendation" to do so.

Although it works for system administrator, for a standard user I am getting this error in deployment status: "insufficient access rights on cross-reference id". There error disappears if I assign that profile the "Modify Metadata Through Metadata API Functions" permission (which requires "View Setup and Configuration").

I thought that abstracting out to a class without sharing (which only allows specific custom metadata types) would let me do this, but unfortunately it is not working. I may have to try to reimplement using custom settings instead of custom metadata types, but still don't know if the same issue will arise. I guess I could use a custom object.

Is there any way to get this to work for standard user? If not with custom metadata types, then should it work with custom settings? Or should I just use a custom object?

p.s. This page shows someone using a proxy class to resolve a similar issue for using custom settings from Visualforce it seems. But the answer is from 2014 and it seems silly that it would work so I am not going to depend on it as a guide to using custom settings. At this point guessing a simple custom object is the only solution..

global with sharing class MyVFCustomController {
 public void savesettings() {
  public UserSettingsMetadata meta = new publicUserSettingsMetadata();

public without sharing class publicUserSettingsMetadata {
    Allow a user to set his own user preferences using metadata api
    even if the user does not have metadata api / modify all permissions,
    but limit the custom metadata types accessible in this way.
    Used by Visualforce User Settings pages.
    private static Set<String> allowedPublicSettingTypes = new Set<String>{
    };// list of custom metadata types allowed public access
    public publicUserSettingsMetadata() {
    public void upsertMetadataRecord(String objname, String label, Map<String, Object> fieldWithValuesMap) {
        // Insert or overwrite user settings record based on unique metadata fullname
        // Usage: upsertMetadataRecord(fullname,label,prefsmap);//fullname = label = 'GlobalMtgReportUser_' + userid
        // fullname example: 
        // Global_Meeting_Report_User_Setting__mdt.GlobalMtgReportUser_0056F0000072VjyQAE
        if ((String.isBlank(objname)) || String.isBlank(label)) {return;}
        if (allowedPublicSettingTypes.contains(objname) == false) {return;}
        Metadata.CustomMetadata customMetadata = new Metadata.CustomMetadata();
        customMetadata.fullName = objname + '.' + label;
        customMetadata.label = label;
        for (String key: fieldWithValuesMap.keySet()) {
            Metadata.CustomMetadataValue customField = new Metadata.CustomMetadataValue();
            customField.field = key;
            customField.value = fieldWithValuesMap.get(key);
        Metadata.DeployContainer mdContainer = new Metadata.DeployContainer();
        PublicSettingsCallback callback = new PublicSettingsCallback();
        if (Test.isRunningTest() == false) {
            Id jobId = Metadata.Operations.enqueueDeployment(mdContainer, callback);
            System.debug('Metadata enqueued jobId: '+jobId);

public class PublicSettingsCallback implements Metadata.DeployCallback {
    public PublicSettingsCallback() {}
    public void handleResult(Metadata.DeployResult result,
    Metadata.DeployCallbackContext context) {
        Id jobId = context.getCallbackJobId();
  • Due to time constraint I decided to just use a custom object. But if anyone knows would like to hear.
    – skycafe
    Jun 2, 2022 at 6:49

1 Answer 1


Okay, no answers yet. As far as I can tell it isn't directly possible, at least with VisualForce. The only way I can see is to create a decoupled mechanism such as a REST service and separate client. I solved the issue by reimplementing using a custom Settings object.

You must log in to answer this question.

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