Loading

2GP Managed Package Patch Version Creation Fails: Apex Tests Assert Incorrect FLS EDIT Access Due to Dependency Package Installation Behavior

Publish Date: Jun 4, 2026
Description
Symptom:
During sf package version create, Apex tests that assert isUpdateable() returns false for a custom field (e.g., custom_field__c) fail with an error similar to:

System.AssertException: Assertion Failed: custom_field should be false. Profile: Standard User. FLS EDIT sources: PermSet: X00ex00000018ozq_128_09_04_12_10 | IsOwnedByProfile: true | Profile: Standard User

The same tests pass successfully when run locally or in a scratch org.
 
Root Cause:
This is expected platform behavior in the 2GP package version creation build org.

When sf package version create runs, the dependency package (e.g., a Base package) is installed into the build org with Security Type = Full. This means the package is installed for all users, and its field permissions are applied broadly — including to profile-backed Permission Sets (system-generated PermSets prefixed with X00e...) associated with standard profiles such as Standard User, System Administrator, etc.

As a result:
  • The test user's profile-backed Permission Set ends up having EDIT access to custom fields defined in the dependency package
  • isUpdateable() evaluates the user's effective permissions (Profile + all assigned Permission Sets, including profile-backed ones)
  • The assertion that the user does NOT have EDIT access fails, even though no explicitly assigned Permission Set grants EDIT access
Resolution

Option 1: Replace isUpdateable() with a direct FieldPermissions query (Recommended)

Instead of relying on isUpdateable(), query FieldPermissions to evaluate only explicitly assigned (non-profile-backed) Permission Sets:

private static Boolean hasExplicitEditPermission(String sobjectType, String field) {
    List<FieldPermissions> fp = [
        SELECT PermissionsEdit
        FROM FieldPermissions
        WHERE SobjectType = :sobjectType
        AND Field = :field
        AND PermissionsEdit = true
        AND ParentId IN (
            SELECT PermissionSetId
            FROM PermissionSetAssignment
            WHERE AssigneeId = :UserInfo.getUserId()
            AND PermissionSet.IsOwnedByProfile = false
        )
        LIMIT 1
    ];
    return !fp.isEmpty();
}

Replace the isUpdateable() checks in your production Apex class with this helper. To minimize SOQL usage, query the required field permissions once at the start of the transaction and cache results in a Map for reuse across multiple methods.

 

Option 2: Use unpackagedMetadata to separate strict FLS tests
Place FLS-specific test classes that rely on a controlled permission model in the unpackagedMetadata directory of your project:

"unpackagedMetadata": {
    "path": "unpackaged"
}

 

Key behavior:
  • Test classes in unpackagedMetadata are deployed into the build org but NOT executed during sf package version create
  • Only test classes from the packaged source directory (e.g., force-app) are executed during package version creation validation

This allows you to:
  • Keep specific FLS tests in unpackagedMetadata and run them locally
  • Keep tests in force-app more generic to handle the build org's effective permission model

 

Reference: https://developer.salesforce.com/docs/atlas.en-us.pkg2_dev.meta/pkg2_dev/sfdx_dev_dev2gp_unpackaged_md.htm

 

Option 3: Update test assertions to be agnostic to build-org profile behavior
Modify test logic to assert based on the business outcome (e.g., whether a field value was overridden) rather than asserting a specific FLS state. Since the effective permission model in the build org differs from a scratch org, tests that depend on isUpdateable() returning a specific value may be unreliable in this context.

Knowledge Article Number

005385922

 
Loading
Salesforce Help | Article