Possible Open edX Static Pipeline Bug – SuspiciousFileOperation referencing /openedx/css/images

Hello development community I am seeking advice,

I’m encountering a persistent static asset build failure in Tutor 21 (Ulmo) where the LMS collectstatic process crashes with a SuspiciousFileOperation. After extensive troubleshooting, it appears a generated asset references /openedx/css/images/…, which is outside the allowed static directory.

I’m trying to determine whether this is a misconfiguration or a bug in the Open edX static pipeline (RequireJS / pipeline storage).

Our Environment:

· Open edX Release: Ulmo, Tutor: 21+

· Deployment: Tutor Local, Python: 3.11

· OS: Ubuntu (cloud VM), No custom themes or plugins installed

· Fresh Ulmo install

The Failure when running:

· tutor local exec lms ./manage.py lms collectstatic --noinput

fails with:

django.core.exceptions.SuspiciousFileOperation:

The joined path (/openedx/css/images/correct-icon.png)

is located outside of the base path component (/openedx/staticfiles)

This occurs during the post-processing stage of collectstatic, inside the Open edX theming storage wrapper.

Traceback shows the error originates here:

· openedx/core/djangoapps/theming/storage.py

· django/contrib/staticfiles/storage.py

Specifically:

safe_join(self.location, name)

which rejects the path.

Also an Important Detail is that the invalid path being generated is:

· /openedx/css/images/correct-icon.png

But Open edX normally references images like:

· /static/images/correct-icon.png

or

· ../images/correct-icon.png

So something in the pipeline is rewriting or generating an incorrect path.

Troubleshooting Already Done

1. Full static rebuild

· rm -rf /openedx/staticfiles

· rm -rf /tmp/tmp*

· tutor local exec lms ./manage.py lms collectstatic --noinput

Result: same failure

2. Verified source CSS

Checked files like:

· lms/static/css/lms-footer-edx.css

They contain correct paths:

· --icon-correct:url(“/static/images/correct-icon.png”);

· No /openedx/css/images reference exists in source CSS.

3. Grep search

Attempted:

· grep -R “/openedx/css/images” /openedx/edx-platform

No results.

This suggests the path is being generated during the asset build step, likely by:

· RequireJS optimizer

· pipeline post-processing

· theming storage hash rewriting

4. CMS build works

Running Studio static build:

· tutor local exec cms ./manage.py cms collectstatic --noinput

Succeeds without errors.

The failure only occurs in LMS static processing.

Observed During Build

The pipeline reports many normal warnings such as:

· Found another file with the destination path …

· Cannot uglify2 file …

These appear to be typical Open edX behavior and do not halt the build.

The failure occurs only when Django staticfiles hashes CSS references.

Possibilities include:

· RequireJS or pipeline generating a malformed path

· CSS rewriting step incorrectly resolving asset paths

A bug in:

· openedx/core/storage.py

· openedx/core/djangoapps/theming/storage.py

A compatibility issue with Python 3.11 / Django staticfiles hashing

Questions:

· Has anyone seen /openedx/css/images/… appear during static builds?

· Could this be a RequireJS path rewriting issue?

· Is this a known Ulmo + Tutor 21 bug?

· Is there a recommended way to trace which asset generates the invalid path?

Temporary Workaround Attempted

· Clearing static files and rebuilding did not resolve the issue.

· Currently the LMS container cannot complete collectstatic, preventing full startup.

· Any guidance or confirmation whether this is a known issue would be greatly appreciated.

Thank you,

Phillip

@arbrandes - do you have any advice here?

Hello Sarina,

The entire static build stops and it appears Open edX is trying to rewrite CSS during collectstatic. During this process it scans CSS files for image references like url(/openedx/css/images/correct-icon.png).
This path seems to be invalid for Open edX. The correct paths should look like: /static/images/correct-icon.png or ../images/correct-icon.png.

I have confirmed the real images exist: /openedx/staticfiles/images/correct-icon.png, but Django is being asked to load: /openedx/css/images/correct-icon.png.

Note: the con.png is used for quizzes.

Thank you,

Phillip

I’m not particularly versed in the asset pipeline. @kmccormick might have an idea, though.