Problem/Motivation

The update hook user_update_10000 "Remove[s] non-existent permissions created by migrations" by loading all "user.role.*" configurations and then using array_diff() to compare each role's permissions against an array of existing permissions. However, if a role's configuration is lacking a "permissions" key, $role_config->get('permissions') returns NULL instead of an empty array, which is then passed as the first parameter to array_diff(). This results in an error that halts the processing of updates:

[error] array_diff(): Argument #1 ($array) must be of type array, null given

Presumably, all role configurations should have a "permissions" key, so the above scenario should never occur. One response to this issue could be that the update hook "works as designed" and that if you are experiencing the above problem, it's your own configuration's fault. In that case, this issue will at least serve to help others with this problem to figure out their own solution.

If we want to help site admins smooth out the Drupal 10 upgrade process, then we can add some extra input checks, and perhaps also some helpful log output.

Steps to reproduce

This is somewhat tricky because I don't know exactly how to replicate our current situation. I work on Drupal sites that are hosted by others in a large multisite configuration, where a base set of modules are managed by others, and I only deal with additional modules in our site repository. The errant role appears to be the result of an incomplete or improperly executed config update by those managing the base platform. The malconfigured role is present and impacting Drupal 10 upgrades for multiple sites that I manage, as well as sites managed by others on the same platform. Other sites with complex configuration histories may find themselves in the same situation.

You can manually replicate the problem by adding a row to the "config" table with a "name" of "user.role.my_test_role" and "data" set to "a:0:{}". This is an empty configuration, missing (among other things) a "properties" key. Run the user_update_10000 update hook, and you should get the above array_diff() error.

Proposed resolution

At a minimum, we can add a check that get('permissions') is not returning a NULL value, and if it is, instead pass an empty array to array_diff. So, instead of the current:
$removed_permissions = array_diff($role_config->get('permissions'), $existing_permissions);
you could simply add a null coalescing operator:
$removed_permissions = array_diff($role_config->get('permissions') ?? [], $existing_permissions);

This ensures array_diff() is happy, but it doesn't do anything about the errant configuration in the first place. If we wanted to be really helpful, we could add some test logic on whether $role_config->get('permissions') returns NULL and if so, provide the user with helpful information for cleanup purposes.

In my case, this errant misconfigured role doesn't seem to have been causing any problems and has gone unnoticed until this update. The role does not appear in the list of roles (/admin/people/roles). If you enable devel and use the config editor, the errant role configuration DOES appear, HOWEVER if you click on the associated "edit" button you get an error message that "Config user.role.badly_configured_role does not exist in the system." And while the role exists in the database config table, it does not get exported to config files, so there is no way to manage it with config import/export. There may be other config editing tools available, but short of that, you have to either manually edit the database or write your own update hook to clean it out.

Remaining tasks

Decide whether this warrants a fix, and if so, how much work to put into it. The proposed quick and dirty fix with the null coalescing operator would solve the problem silently, leaving the errant role in place.

Addition of error/warning output would at least alert the site administrators to problems worthy of further investigation and cleanup.

You could also remove as malformed any role missing a "permissions" key as part of the update, but that seems like a potentially hazardous road to go down unless you're absolutely certain this would have no unforeseen negative impacts.

User interface changes

None

API changes

None

Data model changes

None

Release notes snippet

Not needed?

Issue fork drupal-3380334

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

DaleTrexel created an issue. See original summary.

fabienscotto made their first commit to this issue’s fork.

fabienscotto’s picture

The hook user_update_10000 seems to be related to Drupal 10, can you update the Drupal version of this issue to 11.x?

cilefen’s picture

Version: 11.x-dev » 10.3.x-dev

This is specifically a Drupal 10 issue.

quietone’s picture

Version: 10.3.x-dev » 10.6.x-dev
Assigned: Unassigned » quietone

Assigning to myself to create an MR for this. Although, if someone wants to do that, go right ahead, and I will review it.

quietone’s picture

Assigned: quietone » Unassigned
Status: Active » Needs review
Issue tags: +10.0 update

Change the hook to test for NULL and updated the test as needed. That all works fine and without the fix, the error is the same as in the issue summary. A message is logged when this happens.

quietone’s picture

Title: User update #10000 fails on NULL passed to array_diff() » user_update_10000 fails on role with no data
quietone’s picture

Issue tags: -10.0 update +10.0.0 update
smustgrave’s picture

Status: Needs review » Needs work

Shouldn't we have test coverage for this?

thidd made their first commit to this issue’s fork.

thidd’s picture

Status: Needs work » Needs review
smustgrave’s picture

Status: Needs review » Needs work

Please update the MR to main

danielveza’s picture

Just added one small code review question about the wording for the new log messages.

quietone’s picture

Status: Needs work » Needs review
danielveza’s picture

Status: Needs review » Reviewed & tested by the community

Reviewed the last changes and given the whole thing a last check, I think this is good to go.

godotislate made their first commit to this issue’s fork.

  • godotislate committed 4fc16796 on 10.6.x
    fix: #3380334 user_update_10000 fails on role with no data
    
    By:...
godotislate’s picture

Status: Reviewed & tested by the community » Fixed

Since 10.6 is effectively security-only at this point, consulted with @xjm about whether we should still do this. Since we do want to encourage and remove any blockers for sites still on Drupal 9 or earlier to upgrade, it makes to harden the update hooks here.

Committed 4fc1679 and pushed to 10.6.x. Thanks!

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.