SCSS stylesheet 404s when any unrelated file under its parent folder lacks a default-language version
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Problem Statement
A SCSS stylesheet returns 404 when any unrelated file asset anywhere beneath its parent folder is missing a version in the instance's default language — even when the SASS compilation itself succeeded and produced valid CSS.
The cause is a contract mismatch between two code paths:
-
DotCSSCompiler.createCompileDir()ends with a catch-all sweep, commented// copy any files that did not make it, that collects file assets to stage into the compile workspace. Its query is:select cvi.{live|working}_inode as inode from contentlet_version_info cvi, identifier id where id.parent_path like ? and id.host_inode = ? and cvi.identifier = id.idwith
parent_pathbound to<parentPathOfCompiledFile>%.This sweep has no language filter and no file-type filter. The only constraints are
BaseContentType.FILEASSETand not-archived. Because of the trailing%, it is recursive to any depth. Every file it collects is then registered as a dependency of the stylesheet viagetAllImportedURI().add(assetUri)— despite nothing having imported it. -
CSSPreProcessServletthen iterates that same dependency set and requires each entry to resolve in the default language only:final Optional<ContentletVersionInfo> impInfo = APILocator.getVersionableAPI() .getContentletVersionInfo(importUriIdentifier.getId(), defLang); if (impInfo.isEmpty()) { Logger.error(this, "VersionInfo for imported URI '%s' in language '%s' was not found"); sendError(resp, HttpStatus.SC_NOT_FOUND); return; }One unresolvable entry fails the entire request. There is no skip, no warn-and-continue.
So a sweep that is deliberately language-agnostic feeds a validator that is default-language-only. Any file the sweep picks up in a non-default language is guaranteed to fail it.
Three aggravating details:
- The CSS was already built.
compiler.compile()has returned andnewCache.data = compiler.getOutput()is already populated before this loop runs. The 404 is emitted purely while assembling the cache object — the stylesheet was valid and is discarded. - Any file type triggers it. In the reported case a Velocity template (
.vtl) blocked a stylesheet. It contributes nothing to the CSS and was never imported. - It only fires on cache miss, so it presents as intermittent and is easy to misdiagnose as a caching, permissions, or publishing fault. The reporting customer spent several days on it, attempting file delete/re-add, unpublish/republish, permission audits and a full re-index before support traced it.
Scope is proportional to how high the stylesheet sits: a stylesheet at /application/styles.scss makes the entire /application/ tree a potential source of 404s.
Steps to Reproduce
On an instance whose default language is English:
- Create a stylesheet at
/application/styles.scsson a site and confirm it compiles and serves. - Create any file asset at any depth beneath
/application/— e.g./application/vtl/test/example.vtl. Its content and type are irrelevant; it must simply not be a.scssin the stylesheet's own folder. - Give that file a version in a non-default language only (e.g. German). Do not create an English version. Leave it as a working version.
- Flush the CSS cache, or request the stylesheet on a cold cache.
- Request the stylesheet.
Actual: HTTP 404 for the stylesheet. The log shows VersionInfo for imported URI '<identifier>' in language '1' was not found.
Expected: The stylesheet compiles and is served. An unrelated, un-imported file in another language should not be able to fail it.
Adding an English version of the unrelated file and publishing it restores the stylesheet immediately — confirming the dependency link is the cause.
Acceptance Criteria
- A file asset that is not actually imported by the stylesheet cannot cause that stylesheet to return 404.
- A missing default-language version on a swept (not explicitly
@imported) dependency is logged at WARN and skipped, rather than failing the request. - Files genuinely referenced via
@importretain their existing validation behaviour — a real missing import should still be a hard error. - Consider constraining the
// copy any files that did not make itsweep to file types the SASS compiler can consume, so.vtland similar are never registered as stylesheet dependencies. - The error logged when a stylesheet 404s identifies the offending file's path, not only its identifier, so the cause is diagnosable from logs alone.
dotCMS Version
Reproduced against Current Release (dotEvergreen) on dotCMS Cloud.
Not a regression — long-standing. The sweep was introduced in eaec7f7091 (#16896, Jul 2019); the default-language dependency check predates it and was last modified in eee69a577a (#26892). Neither change accounted for the other, so this latent interaction is expected to affect all currently supported lines, LTS included.
Severity
Low - Minor issue or cosmetic
(Severity per the reporting ticket. Note the diagnostic cost is disproportionate to this rating — the failure mode is silent, intermittent-looking, and points away from its true cause.)
Links
Affected code
dotCMS/src/main/java/com/dotcms/csspreproc/DotCSSCompiler.java:256-291— the unfiltered sweepdotCMS/src/main/java/com/dotcms/csspreproc/CSSPreProcessServlet.java:241-263— the default-language gate that 404s
Workaround
Ensure every file asset beneath a compiled stylesheet's parent folder has a version in the instance's default language. Keeping theme stylesheets in a narrow folder such as /application/themes/<theme>/css/ limits the sweep's blast radius.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with DotCSSCompiler.java:256-291 and CSSPreProcessServlet.java:241-263, tracing how the sweep becomes stylesheet dependencies and how the default-language check handles them. Reproduce the cold-cache case using the listed steps, then verify the acceptance criteria: unrelated files are skipped or warned about, real imports still fail appropriately, and 404 diagnostics include the offending path.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, sass
- Domain
- backend, web-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100