Problem/Motivation
On Drupal 11.4+, uninstalling Domain fails with a fatal error:
TypeError: Drupal\Core\Field\FieldPurger::purgeBatch(): Argument #1 ($batch_size) must be of type int, null given, called in core/modules/field/field.purge.inc on line 34 #0 core/modules/field/field.purge.inc(34): Drupal\Core\Field\FieldPurger->purgeBatch() #1 modules/contrib/domain/domain/domain.install(43): field_purge_batch() #2 core/lib/Drupal/Core/Extension/ModuleInstaller.php(815): domain_uninstall()
domain_uninstall() reads the batch size from field.settings:purge_batch_size. Core 11.4 deprecated that config object and moved the value to $settings['field_purge_batch_size'] (see the change record). The post-update hook field_post_update_clear_purge_batch_size() deletes the config object on sites that had the default value, so the lookup now returns NULL and the typed int parameter rejects it.
The post-update is not the only way to end up without the config object: core 11.4 also removed field/config/install/field.settings.yml, so a site freshly installed on 11.4 has no field.settings either and hits the same TypeError with no update involved.
This affects 3.x, 3.0.x and 4.x. 4.x already calls FieldPurger::purgeBatch() directly instead of the deprecated field_purge_batch(), but it still passes the NULL config value.
Steps to reproduce
- Install Drupal 11.4 or later with Domain and Domain Access enabled, and run database updates so
field_post_update_clear_purge_batch_size()has run. - Confirm the config object is gone:
drush cget field.settingsreports it does not exist. drush pmu domain_access domain- The uninstall aborts with the TypeError above.
Proposed resolution
Resolve the batch size in this order, on all three branches: field.field_settings:purge_batch_size, then field.settings:purge_batch_size, then Settings::get('field_purge_batch_size', 50). The first lookup mirrors core's SystemHooks::cron() and ConfigImporterFieldPurger, but field.field_settings is not a config object and never resolves; it is kept only to follow core if that name is ever corrected. field.settings is still read because field_post_update_clear_purge_batch_size() leaves it in place when it holds a non-default value, and core supports setting the batch size that way until 13.0.0.
Issue fork domain-3624218
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
Comment #5
pfrenssenProvided MRs for the 3 actively maintained branches: 4.x, 3.x, 3.0.x.
Comment #6
mably commentedHi @pfrenssen, thanks for the quick fix. Four points before these go in.
field.field_settingsis not a config object, so the first lookup in all three MRs can never resolve. Core definesfield.field_settings.*in core.data_types.schema.yml only as the schema type for the per-field-type settings stored inside field.field.*.*.* entities; there is no config_object schema under that bare name, and nothing in core writes one.\Drupal::config('field.field_settings')->get('purge_batch_size')is therefore NULL on every site, and both SystemHooks::cron() and ConfigImporterFieldPurger::initializeSandbox() always fall through to Settings::get(). Keeping the lookup for parity with core is reasonable, but the comment above it should say that it tracks core rather than that it resolves anything.That makes !468 a behaviour change on 4.x. field_post_update_clear_purge_batch_size() only deletes field.settings when it holds the default value; a site with a non-default one keeps it, and core's own message there says setting it through configuration stays supported until 13.0.0. As 4.x supports ^11.4 || ^12, dropping the field.settings read means those sites silently get 50 instead of their configured value. Could 4.x keep the same chain as !469 and !470?
One correction to the summary: this is not limited to sites that ran the post-update. Core 11.4 also removed field/config/install/field.settings.yml, so a freshly installed 11.4 site has no field.settings object either, and hits the same TypeError with no update path involved.
Lastly, hook_uninstall() is not covered by any test in the module, which is why this went unnoticed. A kernel test that installs and uninstalls domain would catch this one, and the next core change to that call. On 3.x and 3.0.x it will also surface the field_purge_batch() deprecation from 11.4, so those branches may need a FieldPurger guard for the ^10.2 end.
AI-Generated: Yes (Claude Code was used to analyse the merge requests and to draft this comment. I reviewed it before posting.)
Comment #7
mably commentedPushed to all three branches: the test, the missing fallback on 4.x, and the wording of the comment above the lookup.
DomainUninstallTest is a kernel test that enables the module and then runs module_installer->uninstall(), which is what invokes hook_uninstall(); nothing in the suite reached that hook before. It fails on each branch's parent commit with the reported TypeError, through FieldPurger::purgeBatch() on 4.x and through field_purge_batch() on 3.x and 3.0.x, and passes with the fix on all three.
On 4.x, field.settings is now consulted between the field.field_settings lookup and the setting's default, so all three branches share the same chain. Without that step a site which kept a non-default batch size, which field_post_update_clear_purge_batch_size() deliberately leaves in place, would quietly purge 50 records at a time instead of the number it configured.
The comment above the lookup now says, on all three branches, that field.field_settings never resolves and is kept only to follow core if that name is corrected, rather than reading as though it returns something.
One thing from my previous comment is still outstanding, and it belongs in the summary rather than in a branch: this is not limited to sites that ran the post-update. Core 11.4 also removed field/config/install/field.settings.yml, so a freshly installed 11.4 site has no field.settings object either and hits the same TypeError with no update path involved.
The next major lane on these pipelines is unrelated to this issue. It was red on two test classes for reasons of its own, fixed in #3624244, and has been green here since that landed on 4.x.
AI-Generated: Yes (Claude Code was used to write the test and the change, and to draft this comment. I ran the test on all three branches, against the parent commit as well as against the fix, and reviewed the code before pushing it.)
Comment #11
mably commentedComment #13
mably commentedComment #14
mably commentedComment #15
pfrenssenThanks for the quick review and follow up!