dotCMS / dotCMS/core

Static Push Publish (S3): StaticDependencyBundler/URLMapBundler resolve content by most-recent moddate instead of the language selected for push, with asymmetric duplication under DEFAULT_CONTENT_TO_DEFAULT_LANGUAGE=true

Open
#36,729 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

OKR : Customer Support Team : Maintenance
Dominant language
Java
Stars
970
Forks
486
Avg merge
3d 33m
Merged PRs (30d)
170

Description

Problem Statement

For URL-mapped Content Types with two LIVE language versions sharing the same identifier but different localized URLs, static (S3) push publishing does not push the language version the user selected. Instead, it resolves and bundles whichever language version was most recently modified, independent of:

which language row the user selected in the UI before clicking Push Publish
the configured default language
whether the selected version is itself live, unchanged, and correctly targeted

Additionally, when the most-recently-modified version happens to be the default-language version, URLMapBundler duplicates that default-language content into every configured language folder — even where a real, LIVE, correctly-URLed translation already exists — producing an asymmetric failure mode depending on which language was edited last.

Root Cause (per customer + internal analysis, both converge on the same mechanism):

The push-publish queue only tracks the content identifier; the language from which publishing was initiated is hardcoded/unused (PublisherAPIImpl documents language_id as unused).
During static bundle preparation, StaticDependencyBundler searches by identifier only, with no language filter and no explicit sort:

List cons = contentletAPI.search(
"+identifier:"" + asset.getAsset() + """,
0, 0, null, systemUser, false
);
final Contentlet contentlet = cons.get(0);

With no explicit sort, the underlying OpenSearch query defaults to moddate DESC — so cons.get(0) is simply whichever language version was modified most recently, not the version associated with the push action.

StaticDependencyBundler computes the URL Map from that single resolved version and adds only that one localized URL to the bundle's include patterns.
URLMapBundler then iterates the configured languages but keeps searching using that one already-selected localized URL. If, say, the Italian URL was locked in, the query for English (languageId=1 + Italian URL) finds nothing, so the English branch is skipped even though a live, correctly-URLed English version exists.
Separately, when DEFAULT_CONTENT_TO_DEFAULT_LANGUAGE=true and the resolved (most-recently-modified) contentlet happens to be the default-language version, URLMapBundler writes that same default-language content into every configured language folder without first checking whether a real LIVE translation exists for the target language:

if (DEFAULT_CONTENT_TO_DEFAULT_LANGUAGE
&& contentlet.getLanguageId() == defaultLanguageId) {
for (String languageId : config.getLanguages()) {
writeFileToDisk(..., contentlet, languageId, ...);
}
}

This combination explains the asymmetry: if the default language (e.g. Italian) is the most recently modified, it gets selected and replicated into every other language folder. If a non-default language (e.g. English) is the most recently modified, it gets selected but is not replicated back to the default language folder — so the default-language folder is simply left with stale/missing content instead.

Steps to Reproduce

Environment / Configuration to Reproduce:

DEFAULT_PAGE_TO_DEFAULT_LANGUAGE=true
DEFAULT_CONTENT_TO_DEFAULT_LANGUAGE=true
DEFAULT_FILE_TO_DEFAULT_LANGUAGE=true
DEFAULT_WIDGET_TO_DEFAULT_LANGUAGE=true
Default language: Italian (it-IT); second language: English (en-UK) Any two languagues
Static AWS S3 endpoint, aws_bucket_folder_prefix={hostname}/{languageIso}

https://drive.google.com/file/d/1FngBcHtKt_XwGZiCyfBRW2DCHoLZbMYs/view?usp=drive_link

Acceptance Criteria

Pushing the selected version should publish the content and URL to the bucket, regardless of which version was most recently edited.

dotCMS Version

26.07.06-02

Severity

High - Major functionality broken

Links

https://helpdesk.dotcms.com/a/tickets/38335

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with StaticDependencyBundler and URLMapBundler, then trace the push-publish queue and PublisherAPIImpl's language_id handling. Reproduce with the listed default-language settings and two live language versions, checking which content reaches each S3 language folder. Done means the selected version's content and URL are published regardless of which version was most recently modified, without overwriting an existing live translation.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, java
Domain
backend, cloud
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.