You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When DEFAULT_CONTENT_TO_DEFAULT_LANGUAGE=true, PageResource.render() uses language fallback to return default-language contentlets for entries that have no translation in the requested language.
When we edit the page in dotCMS we are sending the response of PageResource.render() so the editing receives this mixed-language content list and faithfully re-submits it to addContent() (e.g. editing in Spanish, but receiving content that only exists in English). This mixing language scenario causes an IllegalArgumentException.
Since saveContent() in PageResourceHelper is wrapped in @WrapInTransaction, this exception triggered a full transaction rollback. The rollback on a live transaction appeared to the client as an indefinite hang — the HTTP request never returned a response.
Steps to Reproduce
Set DEFAULT_CONTENT_TO_DEFAULT_LANGUAGE=true (env var)
Create a page in ENG (default language) and the ESP version of the same page (secondary language).
Add to the page ENG:
A contentlet that exists in both ENG and ESP
A contentlet that exists in ENG only
Switch to the page ESP and try to add or delete content
Observe that when you Delete nothing happens and when you Add content the page stays hanging for a response
Inspect the response in the network tab and notice that the resource to edit the page content have failed.
Acceptance Criteria
entity.containers.<containerId>.contentlets.<uuid> for an ENG render must not include contentlets that have no ENG (or default-language) version
entity.containers.<containerId>.contentlets.<uuid> for an ESP render correctly includes ESP-only contentlets
The content list in entity.containers.uuid is consistent with what the rendered HTML displays
No regression when DEFAULT_CONTENT_TO_DEFAULT_LANGUAGE=false (existing behavior unchanged)
Visual Summary
Bug-multilanguage-page.mp4
Root Cause
Inside overridesMultitreesByPersonalization(), a language-scoped DELETE was used to clean the multi_tree table before re-inserting. This DELETE only removed entries where the child contentlet had a version in the requested language. Because the fallback contentlet (English-only) had no Spanish version, its multi_tree row was not deleted.
When copyMultiTree() then tried to INSERT that same contentlet back, the duplicate check detected the existing row and threw an IllegalArgumentException. Since saveContent() in PageResourceHelper is wrapped in @WrapInTransaction, this exception triggered a full transaction rollback. The rollback on a live transaction appeared to the client as an indefinite hang — the HTTP request never returned a response.
Additional scenario
DEFAULT_CONTENT_TO_DEFAULT_LANGUAGE: entity.containers.uuid includes contentlets from wrong language in render() response
The rendered HTML is correct (content3 does not appear in the ENG page HTML), but the JSON metadata is inconsistent with it. This inconsistency can confuse API consumers (e.g. headless/EMA frontends) that rely on entity.containers.uuid to determine which contentlets belong to a page in a given language.
PageRenderUtil.getContentletOrFallback() in dotCMS/src/main/java/com/dotcms/rendering/velocity/services/PageRenderUtil.java.
After findContentletByIdentifierOrFallback() returns empty (content3 has no ENG version and ENG is the default), an additional fallback using findContentletByIdentifierAnyLanguage() returned the ESP version of content3 whenever the content type had languageFallback()=true. This "any language" fallback contradicts the DEFAULT_CONTENT_TO_DEFAULT_LANGUAGE contract (show requested language, or fall back to default language only) and caused the inconsistency between entity.containers.uuid and the rendered HTML.
Fix: Removed the findContentletByIdentifierAnyLanguage fallback from getContentletOrFallback(). When a contentlet has no version in the requested language or the default language, the method now returns null, correctly excluding it from entity.containers.uuid.
Problem Statement
When
DEFAULT_CONTENT_TO_DEFAULT_LANGUAGE=true, PageResource.render() uses language fallback to return default-language contentlets for entries that have no translation in the requested language.When we edit the page in dotCMS we are sending the response of
PageResource.render()so the editing receives this mixed-language content list and faithfully re-submits it to addContent() (e.g. editing in Spanish, but receiving content that only exists in English). This mixing language scenario causes anIllegalArgumentException.Since
saveContent()in PageResourceHelper is wrapped in@WrapInTransaction, this exception triggered a full transaction rollback. The rollback on a live transaction appeared to the client as an indefinite hang — the HTTP request never returned a response.Steps to Reproduce
DEFAULT_CONTENT_TO_DEFAULT_LANGUAGE=true(env var)Acceptance Criteria
entity.containers.<containerId>.contentlets.<uuid>for an ENG render must not include contentlets that have no ENG (or default-language) versionentity.containers.<containerId>.contentlets.<uuid>for an ESP render correctly includes ESP-only contentletsentity.containers.uuidis consistent with what the rendered HTML displaysDEFAULT_CONTENT_TO_DEFAULT_LANGUAGE=false(existing behavior unchanged)Visual Summary
Bug-multilanguage-page.mp4
Root Cause
Inside
overridesMultitreesByPersonalization(), a language-scoped DELETE was used to clean the multi_tree table before re-inserting. This DELETE only removed entries where the child contentlet had a version in the requested language. Because the fallback contentlet (English-only) had no Spanish version, its multi_tree row was not deleted.When
copyMultiTree()then tried to INSERT that same contentlet back, the duplicate check detected the existing row and threw anIllegalArgumentException. SincesaveContent()inPageResourceHelperis wrapped in@WrapInTransaction, this exception triggered a full transaction rollback. The rollback on a live transaction appeared to the client as an indefinite hang — the HTTP request never returned a response.Additional scenario
DEFAULT_CONTENT_TO_DEFAULT_LANGUAGE: entity.containers.uuid includes contentlets from wrong language in render() response
Scenario:
content1— ENG onlycontent2— ENG + ESPcontent3— ESP onlyExpected behavior:
entity.containers.uuidrender(ENG)render(ESP)Actual behavior:
entity.containers.uuidrender(ENG)render(ESP)The rendered HTML is correct (content3 does not appear in the ENG page HTML), but the JSON metadata is inconsistent with it. This inconsistency can confuse API consumers (e.g. headless/EMA frontends) that rely on
entity.containers.uuidto determine which contentlets belong to a page in a given language.PageRenderUtil.getContentletOrFallback()indotCMS/src/main/java/com/dotcms/rendering/velocity/services/PageRenderUtil.java.After
findContentletByIdentifierOrFallback()returns empty (content3 has no ENG version and ENG is the default), an additional fallback usingfindContentletByIdentifierAnyLanguage()returned the ESP version of content3 whenever the content type hadlanguageFallback()=true. This "any language" fallback contradicts theDEFAULT_CONTENT_TO_DEFAULT_LANGUAGEcontract (show requested language, or fall back to default language only) and caused the inconsistency betweenentity.containers.uuidand the rendered HTML.Fix: Removed the
findContentletByIdentifierAnyLanguagefallback fromgetContentletOrFallback(). When a contentlet has no version in the requested language or the default language, the method now returnsnull, correctly excluding it fromentity.containers.uuid.dotCMS Version
Latest from
mainbranchSeverity
Medium - Some functionality impacted
Links
NA