Reported via Enterprise Support:
Problem Statement
When push-publishing an archived HTML Page that has multiple language versions (e.g., English and Spanish), the entire push publishing bundle fails on the receiver with a DotDataException: Contentlet is currently marked as 'Archived'. This affects any customer who push-publishes content that includes archived multi-language HTML pages — a situation that commonly arises when push-publishing an entire Site, since all content (including archived pages) is bundled automatically.
The root cause is in ESContentletAPIImpl.updateTemplateInAllLanguageVersions. When multiple language versions of the same archived page are processed sequentially by ContentHandler, the first language version is successfully saved and then archived on the receiver. When the second language version is processed, updateTemplateInAllLanguageVersions searches for non-archived versions of that same identifier, finds none, then searches again with includeArchived=true, finds the first language version (now archived on the receiver), and throws a DotDataException — aborting the entire push.
Example Stack trace:
dotcms-receiver-1 | 17:46:12.106 INFO util.ActivityLogger - class com.dotcms.content.elasticsearch.business.ESContentletAPIImpl: demo.dotcms.com : Contentlet to be saved: , StartDate: N/D; EndDate: N/D; User:system; ContentIdentifier: 902f839a441232cd7e278788c098b42f
dotcms-receiver-1 | 17:46:12.108 WARN business.ESContentFactoryImpl - Contentlet with ID '902f839a441232cd7e278788c098b42f' exists, but is marked as 'Archived'.
dotcms-receiver-1 | 17:46:12.109 ERROR business.ESContentletAPIImpl - Contentlet is currently marked as 'Archived'.
dotcms-receiver-1 | com.dotmarketing.exception.DotDataException: Contentlet is currently marked as 'Archived'.
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.updateTemplateInAllLanguageVersions(ESContentletAPIImpl.java:6809) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.internalCheckin(ESContentletAPIImpl.java:5767) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.lambda$checkin$63(ESContentletAPIImpl.java:5301) ~[?:?]
dotcms-receiver-1 | at com.dotcms.concurrent.lock.StripedLockImpl.tryLock(StripedLockImpl.java:100) ~[?:?]
dotcms-receiver-1 | at com.dotcms.concurrent.lock.StripedLockImpl.tryLock(StripedLockImpl.java:55) ~[?:?]
dotcms-receiver-1 | at com.dotcms.concurrent.lock.IdentifierStripedLock.tryLock(IdentifierStripedLock.java:16) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.checkin(ESContentletAPIImpl.java:5300) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.checkin(ESContentletAPIImpl.java:10395) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.checkin(ESContentletAPIImpl.java:5142) ~[?:?]
dotcms-receiver-1 | at com.dotmarketing.portlets.contentlet.business.ContentletAPIInterceptor.checkin(ContentletAPIInterceptor.java:286) ~[?:?]
dotcms-receiver-1 | at com.dotcms.enterprise.publishing.remote.handler.ContentHandler.saveContent(ContentHandler.java:855) ~[?:?]
dotcms-receiver-1 | at com.dotcms.enterprise.publishing.remote.handler.ContentHandler.handleContents(ContentHandler.java:358) ~[?:?]
dotcms-receiver-1 | at com.dotcms.enterprise.publishing.remote.handler.ContentHandler.handle(ContentHandler.java:194) ~[?:?]
dotcms-receiver-1 | at com.dotcms.enterprise.publishing.remote.handler.ContentHandler.handle(ContentHandler.java:172) ~[?:?]
dotcms-receiver-1 | at com.dotcms.publisher.receiver.BundlePublisher.process(BundlePublisher.java:222) ~[?:?]
dotcms-receiver-1 | at com.dotcms.rest.PushPublisherJob.processBundle(PushPublisherJob.java:40) ~[?:?]
dotcms-receiver-1 | at com.dotcms.rest.PushPublisherJob.run(PushPublisherJob.java:67) ~[?:?]
dotcms-receiver-1 | at com.dotmarketing.quartz.DotJob.execute(DotJob.java:42) ~[?:?]
dotcms-receiver-1 | at org.quartz.core.JobRunShell.run(JobRunShell.java:223) ~[?:?]
dotcms-receiver-1 | at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549) ~[?:?]
dotcms-receiver-1 | 17:46:12.109 WARN business.ESContentletAPIImpl - Contentlet is currently marked as 'Archived'.
dotcms-receiver-1 | com.dotmarketing.exception.DotDataException: Contentlet is currently marked as 'Archived'.
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.updateTemplateInAllLanguageVersions(ESContentletAPIImpl.java:6809) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.internalCheckin(ESContentletAPIImpl.java:5767) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.lambda$checkin$63(ESContentletAPIImpl.java:5301) ~[?:?]
dotcms-receiver-1 | at com.dotcms.concurrent.lock.StripedLockImpl.tryLock(StripedLockImpl.java:100) ~[?:?]
dotcms-receiver-1 | at com.dotcms.concurrent.lock.StripedLockImpl.tryLock(StripedLockImpl.java:55) ~[?:?]
dotcms-receiver-1 | at com.dotcms.concurrent.lock.IdentifierStripedLock.tryLock(IdentifierStripedLock.java:16) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.checkin(ESContentletAPIImpl.java:5300) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.checkin(ESContentletAPIImpl.java:10395) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.checkin(ESContentletAPIImpl.java:5142) ~[?:?]
dotcms-receiver-1 | at com.dotmarketing.portlets.contentlet.business.ContentletAPIInterceptor.checkin(ContentletAPIInterceptor.java:286) ~[?:?]
dotcms-receiver-1 | at com.dotcms.enterprise.publishing.remote.handler.ContentHandler.saveContent(ContentHandler.java:855) ~[?:?]
dotcms-receiver-1 | at com.dotcms.enterprise.publishing.remote.handler.ContentHandler.handleContents(ContentHandler.java:358) ~[?:?]
dotcms-receiver-1 | at com.dotcms.enterprise.publishing.remote.handler.ContentHandler.handle(ContentHandler.java:194) ~[?:?]
dotcms-receiver-1 | at com.dotcms.enterprise.publishing.remote.handler.ContentHandler.handle(ContentHandler.java:172) ~[?:?]
dotcms-receiver-1 | at com.dotcms.publisher.receiver.BundlePublisher.process(BundlePublisher.java:222) ~[?:?]
dotcms-receiver-1 | at com.dotcms.rest.PushPublisherJob.processBundle(PushPublisherJob.java:40) ~[?:?]
dotcms-receiver-1 | at com.dotcms.rest.PushPublisherJob.run(PushPublisherJob.java:67) ~[?:?]
dotcms-receiver-1 | at com.dotmarketing.quartz.DotJob.execute(DotJob.java:42) ~[?:?]
dotcms-receiver-1 | at org.quartz.core.JobRunShell.run(JobRunShell.java:223) ~[?:?]
dotcms-receiver-1 | at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549) ~[?:?]
dotcms-receiver-1 | 17:46:12.109 ERROR handler.ContentHandler - An error occurred when processing Contentlet in '/data/shared/assets/bundles/01KTM5F29YXWE2V1FREEFW2TXK/working/demo.dotcms.com/2/0-test-page.content.xml' with ID '902f839a441232cd7e278788c098b42f': 'Contentlet is currently marked as 'Archived'.'
dotcms-receiver-1 | com.dotmarketing.exception.DotDataException: Contentlet is currently marked as 'Archived'.
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.updateTemplateInAllLanguageVersions(ESContentletAPIImpl.java:6809) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.internalCheckin(ESContentletAPIImpl.java:5767) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.lambda$checkin$63(ESContentletAPIImpl.java:5301) ~[?:?]
dotcms-receiver-1 | at com.dotcms.concurrent.lock.StripedLockImpl.tryLock(StripedLockImpl.java:100) ~[?:?]
dotcms-receiver-1 | at com.dotcms.concurrent.lock.StripedLockImpl.tryLock(StripedLockImpl.java:55) ~[?:?]
dotcms-receiver-1 | at com.dotcms.concurrent.lock.IdentifierStripedLock.tryLock(IdentifierStripedLock.java:16) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.checkin(ESContentletAPIImpl.java:5300) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.checkin(ESContentletAPIImpl.java:10395) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.checkin(ESContentletAPIImpl.java:5142) ~[?:?]
dotcms-receiver-1 | at com.dotmarketing.portlets.contentlet.business.ContentletAPIInterceptor.checkin(ContentletAPIInterceptor.java:286) ~[?:?]
dotcms-receiver-1 | at com.dotcms.enterprise.publishing.remote.handler.ContentHandler.saveContent(ContentHandler.java:855) ~[?:?]
dotcms-receiver-1 | at com.dotcms.enterprise.publishing.remote.handler.ContentHandler.handleContents(ContentHandler.java:358) ~[?:?]
dotcms-receiver-1 | at com.dotcms.enterprise.publishing.remote.handler.ContentHandler.handle(ContentHandler.java:194) ~[?:?]
dotcms-receiver-1 | at com.dotcms.enterprise.publishing.remote.handler.ContentHandler.handle(ContentHandler.java:172) ~[?:?]
dotcms-receiver-1 | at com.dotcms.publisher.receiver.BundlePublisher.process(BundlePublisher.java:222) ~[?:?]
dotcms-receiver-1 | at com.dotcms.rest.PushPublisherJob.processBundle(PushPublisherJob.java:40) ~[?:?]
dotcms-receiver-1 | at com.dotcms.rest.PushPublisherJob.run(PushPublisherJob.java:67) ~[?:?]
dotcms-receiver-1 | at com.dotmarketing.quartz.DotJob.execute(DotJob.java:42) ~[?:?]
dotcms-receiver-1 | at org.quartz.core.JobRunShell.run(JobRunShell.java:223) ~[?:?]
dotcms-receiver-1 | at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549) ~[?:?]
dotcms-receiver-1 | 17:46:12.111 ERROR receiver.BundlePublisher - Error publishing bundle with ID '01KTM5F29YXWE2V1FREEFW2TXK.tar.gz': An error occurred when processing Contentlet in '/data/shared/assets/bundles/01KTM5F29YXWE2V1FREEFW2TXK/working/demo.dotcms.com/2/0-test-page.content.xml' with ID '902f839a441232cd7e278788c098b42f': 'Contentlet is currently marked as 'Archived'.'
dotcms-receiver-1 | com.dotcms.publishing.DotPublishingException: An error occurred when processing Contentlet in '/data/shared/assets/bundles/01KTM5F29YXWE2V1FREEFW2TXK/working/demo.dotcms.com/2/0-test-page.content.xml' with ID '902f839a441232cd7e278788c098b42f': 'Contentlet is currently marked as 'Archived'.'
dotcms-receiver-1 | at com.dotcms.enterprise.publishing.remote.handler.ContentHandler.handleContents(ContentHandler.java:606) ~[?:?]
dotcms-receiver-1 | at com.dotcms.enterprise.publishing.remote.handler.ContentHandler.handle(ContentHandler.java:194) ~[?:?]
dotcms-receiver-1 | at com.dotcms.enterprise.publishing.remote.handler.ContentHandler.handle(ContentHandler.java:172) ~[?:?]
dotcms-receiver-1 | at com.dotcms.publisher.receiver.BundlePublisher.process(BundlePublisher.java:222) ~[?:?]
dotcms-receiver-1 | at com.dotcms.rest.PushPublisherJob.processBundle(PushPublisherJob.java:40) ~[?:?]
dotcms-receiver-1 | at com.dotcms.rest.PushPublisherJob.run(PushPublisherJob.java:67) ~[?:?]
dotcms-receiver-1 | at com.dotmarketing.quartz.DotJob.execute(DotJob.java:42) ~[?:?]
dotcms-receiver-1 | at org.quartz.core.JobRunShell.run(JobRunShell.java:223) ~[?:?]
dotcms-receiver-1 | at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549) ~[?:?]
dotcms-receiver-1 | Caused by: com.dotmarketing.exception.DotDataException: Contentlet is currently marked as 'Archived'.
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.updateTemplateInAllLanguageVersions(ESContentletAPIImpl.java:6809) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.internalCheckin(ESContentletAPIImpl.java:5767) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.lambda$checkin$63(ESContentletAPIImpl.java:5301) ~[?:?]
dotcms-receiver-1 | at com.dotcms.concurrent.lock.StripedLockImpl.tryLock(StripedLockImpl.java:100) ~[?:?]
dotcms-receiver-1 | at com.dotcms.concurrent.lock.StripedLockImpl.tryLock(StripedLockImpl.java:55) ~[?:?]
dotcms-receiver-1 | at com.dotcms.concurrent.lock.IdentifierStripedLock.tryLock(IdentifierStripedLock.java:16) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.checkin(ESContentletAPIImpl.java:5300) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.checkin(ESContentletAPIImpl.java:10395) ~[?:?]
dotcms-receiver-1 | at com.dotcms.content.elasticsearch.business.ESContentletAPIImpl.checkin(ESContentletAPIImpl.java:5142) ~[?:?]
dotcms-receiver-1 | at com.dotmarketing.portlets.contentlet.business.ContentletAPIInterceptor.checkin(ContentletAPIInterceptor.java:286) ~[?:?]
dotcms-receiver-1 | at com.dotcms.enterprise.publishing.remote.handler.ContentHandler.saveContent(ContentHandler.java:855) ~[?:?]
dotcms-receiver-1 | at com.dotcms.enterprise.publishing.remote.handler.ContentHandler.handleContents(ContentHandler.java:358) ~[?:?]
dotcms-receiver-1 | ... 8 more
dotcms-receiver-1 | 17:46:12.115 ERROR Failed to publish because an error occurred: - Error publishing bundle with ID '01KTM5F29YXWE2V1FREEFW2TXK.tar.gz': com.dotcms.publishing.DotPublishingException: An error occurred when processing Contentlet in '/data/shared/assets/bundles/01KTM5F29YXWE2V1FREEFW2TXK/working/demo.dotcms.com/2/0-test-page.content.xml' with ID '902f839a441232cd7e278788c098b42f': 'Contentlet is currently marked as 'Archived'.'
dotcms-receiver-1 | 17:46:12.115 INFO util.PushPublishLogger - class com.dotcms.rest.PushPublisherJob : [BundleID: 01KTM5F29YXWE2V1FREEFW2TXK.tar.gz] Finished bundle publish process
dotcms-receiver-1 | 17:46:12.115 INFO rest.PushPublisherJob - Finished bundle publish process
Steps to Reproduce
- Set up a dotCMS push publishing environment (sender + receiver).
- Make sure both the sender and receiver instances already have the same Site configured.
- In the sender, create an HTML Page and add content for both English and Spanish (i.e., two language versions of the same page).
- Un-publish and archive both language versions of the page on the sender.
- Push-publish either of the language versions to the receiver.
Expected: The push publishing process succeeds and the page is correctly archived on the receiver.
Actual: The push fails with DotDataException: Contentlet is currently marked as 'Archived'. and the entire bundle is marked as failed.
Acceptance Criteria
dotCMS Version
Latest from main branch. Also confirmed on production instances (see customer log from 01KTCYF028BWV1XE3JKXWQJ4AQ).
Severity
High — Major functionality broken. Push-publishing an entire Site reliably fails whenever that Site contains archived HTML pages with multiple language versions. There is no workaround other than permanently deleting (not archiving) those pages before pushing.
Proposed Fix
Location
ESContentletAPIImpl.java — updateTemplateInAllLanguageVersions (private method, ~line 6781).
What to change
1. Add an early return at the top of the method when the incoming contentlet is itself archived:
if (contentlet.getBoolProperty(DO_NOT_UPDATE_TEMPLATES)) {
return;
}
// Template propagation is irrelevant for archived pages. This guard prevents a
// DotDataException when pushing multiple language versions of an archived HTML page,
// where the first processed language is archived on the receiver before the second
// is checked in.
if (contentlet.isArchived()) {
return;
}
2. Change the else if branch that currently throws DotDataException to log a warning and return:
// Before (line ~6808):
} else if (contentletByIdentifierAnyLanguageArchived.isArchived()) {
throw new DotDataException(String.format(
"Contentlet with ID '%s' is currently marked as 'Archived'.",
contentlet.getIdentifier()));
}
// After:
} else if (contentletByIdentifierAnyLanguageArchived.isArchived()) {
Logger.warn(ESContentletAPIImpl.class, String.format(
"Skipping template propagation: all existing versions of Contentlet '%s' are archived.",
contentlet.getIdentifier()));
return;
}
Why this won't break existing functionality
updateTemplateInAllLanguageVersions is a private method. No code outside ESContentletAPIImpl can call it directly, so there is no external caller that could be relying on the DotDataException being thrown.
The only path into this method is through checkin → internalCheckin. The call site in internalCheckin (lines 5765–5770) already demonstrates the intended behavior: it wraps the call in a try/catch that silently swallows NotFoundInDbException (the "content is brand new" case). The DotDataException from the archived case was never caught there — it was an unintended gap that caused push publishing to explode.
Any code that calls checkin and catches DotDataException does so to handle generic data-layer failures. Removing this specific throw does not deprive those callers of any meaningful signal — if they need to know whether a contentlet is archived, the correct way is contentlet.isArchived(), not catching a side-effect exception from a template-propagation helper.
The UI is already protected separately. The dotCMS UI prevents editing archived pages before you reach checkin. The throw at line 6809 was a defensive guard for a state that the UI makes unreachable in normal interactive use. Push publishing is the only realistic path that legitimately triggers it, and the throw is wrong there.
The semantic change is correct. The purpose of updateTemplateInAllLanguageVersions is to propagate a template change across active language versions of the same HTML page. Archived pages are not served and do not need template synchronization. Returning early for archived content is the right behavior, not throwing.
Links
Reported via Enterprise Support:
Problem Statement
When push-publishing an archived HTML Page that has multiple language versions (e.g., English and Spanish), the entire push publishing bundle fails on the receiver with a
DotDataException: Contentlet is currently marked as 'Archived'.This affects any customer who push-publishes content that includes archived multi-language HTML pages — a situation that commonly arises when push-publishing an entire Site, since all content (including archived pages) is bundled automatically.The root cause is in
ESContentletAPIImpl.updateTemplateInAllLanguageVersions. When multiple language versions of the same archived page are processed sequentially byContentHandler, the first language version is successfully saved and then archived on the receiver. When the second language version is processed,updateTemplateInAllLanguageVersionssearches for non-archived versions of that same identifier, finds none, then searches again withincludeArchived=true, finds the first language version (now archived on the receiver), and throws aDotDataException— aborting the entire push.Example Stack trace:
Steps to Reproduce
Expected: The push publishing process succeeds and the page is correctly archived on the receiver.
Actual: The push fails with
DotDataException: Contentlet is currently marked as 'Archived'.and the entire bundle is marked as failed.Acceptance Criteria
dotCMS Version
Latest from
mainbranch. Also confirmed on production instances (see customer log from01KTCYF028BWV1XE3JKXWQJ4AQ).Severity
High — Major functionality broken. Push-publishing an entire Site reliably fails whenever that Site contains archived HTML pages with multiple language versions. There is no workaround other than permanently deleting (not archiving) those pages before pushing.
Proposed Fix
Location
ESContentletAPIImpl.java—updateTemplateInAllLanguageVersions(private method, ~line 6781).What to change
1. Add an early return at the top of the method when the incoming contentlet is itself archived:
2. Change the
else ifbranch that currently throwsDotDataExceptionto log a warning and return:Why this won't break existing functionality
updateTemplateInAllLanguageVersionsis aprivatemethod. No code outsideESContentletAPIImplcan call it directly, so there is no external caller that could be relying on theDotDataExceptionbeing thrown.The only path into this method is through
checkin→internalCheckin. The call site ininternalCheckin(lines 5765–5770) already demonstrates the intended behavior: it wraps the call in atry/catchthat silently swallowsNotFoundInDbException(the "content is brand new" case). TheDotDataExceptionfrom the archived case was never caught there — it was an unintended gap that caused push publishing to explode.Any code that calls
checkinand catchesDotDataExceptiondoes so to handle generic data-layer failures. Removing this specific throw does not deprive those callers of any meaningful signal — if they need to know whether a contentlet is archived, the correct way iscontentlet.isArchived(), not catching a side-effect exception from a template-propagation helper.The UI is already protected separately. The dotCMS UI prevents editing archived pages before you reach
checkin. The throw at line 6809 was a defensive guard for a state that the UI makes unreachable in normal interactive use. Push publishing is the only realistic path that legitimately triggers it, and the throw is wrong there.The semantic change is correct. The purpose of
updateTemplateInAllLanguageVersionsis to propagate a template change across active language versions of the same HTML page. Archived pages are not served and do not need template synchronization. Returning early for archived content is the right behavior, not throwing.Links