Problem/Motivation
In core/modules/content_moderation/src/Plugin/Field/FieldWidget/ModerationStateWidget.php, the formElement() method calls loadRevision() to retrieve the most recent saved revision of an existing entity, then immediately passes $original_entity to StateTransitionValidation::getValidTransitions() without first checking whether the revision load was successful.
If loadRevision() returns NULL (e.g. due to a missing, pruned, or otherwise unavailable revision), a fatal TypeError is thrown:
TypeError: Drupal\content_moderation\StateTransitionValidation::getValidTransitions(): Argument #1 ($entity) must be of type Drupal\Core\Entity\ContentEntityInterface, null given, called in core/modules/content_moderation/src/Plugin/Field/FieldWidget/ModerationStateWidget.php on line 144 in Drupal\content_moderation\StateTransitionValidation->getValidTransitions() (line 43 of core/modules/content_moderation/src/StateTransitionValidation.php).
The code additionally contains a null check on $entity (not $original_entity) on line 143, placed after $entity has already been dereferenced multiple times. This check is effectively unreachable and does not protect against the actual failure point.
Steps to reproduce
- Enable
content_moderationon a Drupal 11 site with a moderated content type. - Create content of that type so that a revision record exists.
- Delete or otherwise invalidate the revision record from the database (this can occur via revision pruning, a failed deployment, or corrupted data) while leaving the node record intact.
- Attempt to edit the affected node.
- Observe the
TypeError— the edit form cannot be rendered and the user sees a generic "temporary error" page.
Proposed resolution
Add a NULL check on $original_entity immediately after loadRevision() is called, before any further method calls or use as an argument. Return early with the unmodified $element if the revision cannot be loaded, consistent with how the method already handles non-moderated entities in form().
Additionally, remove the existing unreachable null check on $entity at line 143, which provides no defensive value and is misleading.
Remaining tasks
- Review and confirm patch approach.
- Add automated test coverage asserting that a node with an unloadable revision does not produce a fatal error when the edit form is rendered.
User interface changes
None.
Introduced terminology
None.
API changes
None.
Data model changes
None.
Release notes snippet
Fixed a fatal TypeError in ModerationStateWidget::formElement() that occurred when editing a moderated entity whose loaded revision ID could not be found in storage (e.g. after revision pruning or data corruption). The widget now returns gracefully instead of crashing with an unhandled exception.
Issue fork drupal-3578097
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 #2
chamilsanjeewa commentedComment #6
nord102Re-opening this
I ran into this issue on a Drupal 11.3.10 site after upgrading from D10. The TypeError fires during
rebuildFormafter the initial save of a new moderated node,getLoadedRevisionId()returns null on the form state entity during the rebuild, which gets passed directly to loadRevision()and then togetValidTransitions().I also found a second instance of the same root cause in
ModerationInformation::isFirstTimeModeration(), wheregetLatestRevisionId()can return null (when$entity->id()is null) and gets passed directly toloadRevision(), producing anarray_flip()warning inContentEntityStorageBase.The fix guards both
loadRevision()calls against null before invoking them. MR attached.Comment #7
smustgrave commentedFixes need to be against main so changing versions
But will need test coverage to show the issue. But not sure about the fix, is it correct that null could be returned? Is this masking a larger issue.