dotCMS / dotCMS/core

SCSS stylesheet 404s when any unrelated file under its parent folder lacks a default-language version

Open
#37,558 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

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:

  1. 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.id
    

    with parent_path bound to <parentPathOfCompiledFile>%.

    This sweep has no language filter and no file-type filter. The only constraints are BaseContentType.FILEASSET and 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 via getAllImportedURI().add(assetUri) — despite nothing having imported it.

  2. CSSPreProcessServlet then 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 and newCache.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:

  1. Create a stylesheet at /application/styles.scss on a site and confirm it compiles and serves.
  2. 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 .scss in the stylesheet's own folder.
  3. 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.
  4. Flush the CSS cache, or request the stylesheet on a cold cache.
  5. 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 @import retain their existing validation behaviour — a real missing import should still be a hard error.
  • Consider constraining the // copy any files that did not make it sweep to file types the SASS compiler can consume, so .vtl and 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 sweep
  • dotCMS/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

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 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.