Permission set is deployed with unlocked package, but is missing permission. What could be the reason?

The link from @xedshot (https://help.salesforce.com/articleView?id=distribution_perm_sets_profile_settings.htm&type=5) is correct and relevant, but I feel that it's worth quoting and explaining the relevant section:

The following list is given under the title "What permissions and settings are included?" for Permission Sets:

  • Assigned custom apps
  • Custom object permissions
  • External object permissions
  • Custom field permissions
  • Custom metadata types permissions
  • Custom permissions
  • Custom settings permissions
  • Custom tab visibility settings
  • Apex class access
  • Visualforce page access
  • External data source access
  • Record types

The consequence is that you can build a Permission Set in a package which contains some things on the list, and some things not on the list. This will build with no errors or warnings. However, on package install, only the items from the list will be created/updated in the target org.

So, suppose I have a permission set which includes the system permissions for "API Enabled" and "Apex REST Services", plus Apex class access for my Apex REST class.

When I install this into an org that has never had my package before, the Permission Set is created, but it only enables the Apex class. It does not also set "API Enabled" and "Apex REST Services".

If I set those extra permissions after install, subsequent upgrades will keep my changes.

So, it is a bit of a gotcha for working with unlocked packaging.