Problem
Starting with Drupal 10.2+/11.x, core enforces that an existing default revision cannot be saved as a non-default revision without creating a new revision (see #3499181). This causes an EntityStorageException when saving host
entities (nodes, taxonomy terms, etc.) with composite entities as drafts.
This affects all composite entity types using Entity Reference Revisions, including but not limited to:
- Paragraphs
- Cohesion Layout (Site Studio)
- Any custom composite entity type
The error message is:
Drupal\Core\Entity\EntityStorageException: An existing default revision of the '[entity_type]' entity type can not be changed to a non-default revision.
Root cause
There are two locations in EntityReferenceRevisionsItem where composite entities are saved, and both need to handle this case:
1. In preSave() (line ~331)
When the composite entity content changes, preSave() saves the entity:
$this->entity->save();
A fix was partially implemented (line ~327) but may not cover all scenarios depending on execution order.
2. In postSave() (line ~405-406) — NOT FIXED
When metadata needs to be updated (parent_id, parent_type, field_name), the code explicitly forces setNewRevision(FALSE):
if ($needs_save) {
$entity->setNewRevision(FALSE); // ← Problem: ignores revision state
$entity->save();
} This causes the exception when:
1. The composite entity was loaded as the default revision (wasDefaultRevision() === TRUE)
2. The host entity is being saved as a non-default revision (draft)
3. The composite entity's isDefaultRevision has been synced to FALSE
Steps to reproduce
1. Create a content type with a composite entity reference field (paragraph, cohesion_layout, etc.)
2. Create and publish a node with a composite entity
3. Edit the node and save as draft
4. Edit again and save as draft → EntityStorageException is thrown
The bug is intermittent because it depends on whether $needs_save is TRUE in postSave(), which happens when parent metadata changes.
Proposed resolution
Apply the same defensive check in both preSave() and postSave(): before saving, check if the entity was a default revision and is becoming non-default. If so, create a new revision instead of forcing setNewRevision(FALSE).
Impact
This bug affects any site using:
- Content Moderation with drafts/workflows
- Any composite entity type (Paragraphs, Cohesion Layout, custom types)
- Drupal 10.2+ or 11.x
Without this fix, editors cannot reliably save drafts on content with composite entities.
| Comment | File | Size | Author |
|---|---|---|---|
| #12 | fix_default_revision_sync-3571637-12.patch | 2.43 KB | anton4uk |
| entity_reference_revisions-fix-default-revision-sync.patch | 1.78 KB | egruel |
Issue fork entity_reference_revisions-3571637
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
dtfabio commentedI had to solve this same problem for one of our customers: a page with paragraphs could no longer be saved after editing one of the paragraphs. This problem occurred after rolling out the D11 updates, and the patch in this issue solved the problem.
Core version 11.3.2
PHP version 8.3.27
MySQL version 8.4.5
Entity reference revisions module version 1.13.0
Before applying the patch, the site displays the following message to the user:
"The content could not be saved. Contact the site administrator if the problem persists."
And throws the following error in the logs:
After adding the patch, the error has disappeared and it is possible to save the node again.
So, as far as I'm concerned, this ticket can be moved to RTBC and hopefully the fix can be included in the module.
Comment #3
yonailoI am able to reproduce this issue too.
In my case it is enough to revert to and old revision and trying to make edits afterwards. I've got this in the drupal logs :
Comment #4
uri_frazierEDIT: I can save now, but looks like I need to add an issue for the
diffmodule as changes to entity reference field values are not appearing when trying to "Compare selected revisions"I ran into the same error, and the patch works great. In my case, it was encountered by doing the following:
The affected node was still misbehaving, (I would save changes, but they would never persist and it would essentially fail silently) so I needed to save changes in a draft version and then publish in order to get revisions, etc. to work correctly again for that node.
Drupal 11.3.3
PHP: 8.3.30
DB: 10.6.22-MariaDB
Comment #5
uri_frazierI'm having trouble with reverting, it currently doesn't do anything when making changes on an entity reference field.
No error, but changes aren't reverted. No error messages in the logs.
Comment #6
uri_frazierI can save, but reverting to a previous revision isn't working or causing any errors to be logged.
My apologies if I incorrectly changed the status on this issue. It may just be Paragraphs specific (?) - I will do more testing and update here if needed.
Comment #7
uri_frazierOkay, after some further testing (on a blank/test D11.3.3 site) I found that this patch (entity_reference_revisions-fix-default-revision-sync.patch) is working correctly.
I also found that the error doesn't appear with basic content on a fresh D11 site, but here is how to replicate it:
Again, using Paragraphs on its own did not cause the error, instead it was only when enabling "Users may translate this field" on the paragraphs field, did the error message appear: "The content could not be saved. Contact the site administrator if the problem persists"
Additionally (again) in order to ensure the error appears, a second language had to be added to the site.
While reverting (the revert feature) still doesn't work for the site I'm trying to fix despite having this patch applied, it does work on a basic D11 test site that doesn't have custom code or other complicated modules running (e.g. paragraphs_asymmetric_translation_widgets).
Setting this back to "Reviewed & tested by the community"
Comment #10
joevagyok commentedI opened an MR with a test coverage in the first commit that fails. The second commit is with the fix where postSave() change was creating extra revisions during normal parent field metadata updates, which broke the orphan removal test's expected revision counts, especially on Drupal 11.3 where wasDefaultRevision() tracking may have become stricter.
Third commit is passing: the preSave() fix at line 322 remains and is the correct, targeted fix for the bug.
Comment #11
gpietrzakI checked it in few local scenarios, it works good!
Comment #12
anton4uk commentedIn some cases, when a new revision is created in this way, the "target_revision_id" needs to be updated. A new revision is created, but "target_revision_id" points to the previous one because $is_affected fired before the new revision was created.
I hope I explained it well, because we have such a problem on one of the projects. Revision is created, but nothing is changed. For more context, paragraphs are translatable, but without draft moderation.
It should be checked how it works with Content Moderation.
Comment #13
flyke commentedI have a project where, as admin user, I have no problems unpublishing a node (that contains paragraphs).
However, the client contacted me that when he (logged in with different user role, that does have sufficient permissions) tries to unpublish a node, he gets the error
The content could not be saved. Contact the site administrator if the problem persists..In watchdog, that is the error:
Drupal\Core\Entity\EntityStorageException saving node form: An existing default revision of the 'paragraph' entity type can not be changed to a non-default revision. in Drupal\Core\Entity\Sql\SqlContentEntityStorage->save() (line 815 of /var/www/html/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php)At time of writing, MR 90 did NOT fix the issue.
Patch #12 did fix the issue, thanks @anton4uk !
Sidenote, MR146 of inline_entity_form issue #3532374 also did not fix the issue.
Comment #14
djdevinSimilar to @flyke, project uses Workspaces, LB + Inline blocks + Paragraphs + Inline entity form
#12 fixed, #3532374 did not
edit: LOL - a little more to the story, the issue happens when updating a text field to a value that is current. So the workaround was to enter some garbage and save, then go back and edit again.
So it's not seeing a change in the entity, so it does not create a new revision, but sets the non-default flag.
Specifically with Workspaces but maybe this issue pops up in other circumstances.
Comment #16
benstallings commentedAfter rebase, Claude Code said,
2 files changed, 3 logical changes. All focused on the issue.
---
1. preSave() — Default-revision demotion guard (lines 320–331)
Assessment: Correct. The three-part condition is precise:
- !isNewRevision() — a new revision wasn't already requested (avoids double-setting)
- wasDefaultRevision() — the entity was loaded as the default
- !isDefaultRevision() — it's now being saved as non-default (synced from host)
The $set_new_revision flag ensures target_revision_id is updated on line 336 even when $is_affected is false. This is necessary because forcing a new revision changes the revision ID regardless of translation-affectedness.
The placement is good — it sits inside the if ($needs_save) block, so it only fires when the entity is actually about to be saved. The comments and @see references are helpful.
---
2. postSave() — Same guard for parent-tracking saves (lines 404–415)
Assessment: Correct. Same Drupal 11 enforcement in the postSave() path, where the entity is saved to update parent tracking fields. Note this guard doesn't need the !isNewRevision() check because the original code unconditionally called setNewRevision(FALSE), so we know a new revision was never requested in this path.
Minor nit: Line 414 has 7-space indentation (·······$entity->setNewRevision(FALSE);) instead of the 8 spaces used everywhere else. Should be fixed for Drupal coding standards.
---
3. Test: testDefaultRevisionDemotionWithNewHost()
Assessment: Well-constructed. The test reproduces the exact scenario:
1. Creates a composite + node (both default revisions)
2. Reloads the composite fresh (so wasDefaultRevision() is true)
3. Marks it non-default with needsSave, places it in a new host composite
4. Saves the node as a non-default (draft) revision
5. Asserts no exception, verifies the new non-default revision exists, and confirms the original default revision is preserved
The nested composite setup (adding nested_composite field) accurately models the real-world trigger where a new container entity causes preSave() to skip the !$host->isNew() block.
---
Summary
This is a clean, focused fix. The only actionable item is the 1-space indentation discrepancy on line 414. Otherwise this looks ready.
Comment #17
sir_squall commentedI tested the patch #12 and it's working well! Thanks a lot #anton4uk for that !
Comment #18
benstallings commented^ I rebased and fixed the indentation; that's all.
Comment #19
emixaam commentedTested the patch #12 / MR 90 successfully with Drupal 11.3.8, Paragraphs 1.20 and Entity Reference Revisions 1.14. We also have the modules Workflows and Content Moderation enabled with some workflows.
Before applying the patch, we had the error
Drupal\Core\Entity\EntityStorageException saving node form: An existing default revision of the 'paragraph' entity type can not be changed to a non-default revision. in Drupal\Core\Entity\Sql\SqlContentEntityStorage->save()while attempting to save some content/pages.With the patch, saving and restoring previous revisions now work correctly for our content/pages that had the error.
Comment #20
alphex commentedThis solved an error i was getting while updating RABBIT_HOLE to its latest version (as of time of this comment), which was reporting
during `drush updb`.