Repository navigation
[DEPR]: static_asset_path XBlock setting #39236
Description
Draft. Written by Claude; to be edited by @kdmccormick before being submitted for RFC.
Dates below are placeholders.
We believe that this feature is effectively un-useable. There is a 4-week comment period to collect feedback on whether anyone is using it. If we confirm the feature is useless, then we will remove immediately. If the feature turns out to have usage, we will allow the standard 1-release-cycle grace period before removing.
RFC Start Date
2026-10-21
Target Plan Accepted Date
2026-11-21
Target Transition Unblocked Date
2026-11-21
Earliest Breaking Changes Unblocked Date
2026-11-21
Earliest Open edX Named Release with Breaking Changes
Willow - 2027-01
Rationale
static_asset_path changes how /static/ references resolve. When it is set, /static/foo.png resolves against Django staticfiles (STATIC_ROOT) instead of the contentstore, and the contentstore is never consulted.
It is defined on InheritanceMixin, so it exists on every block and is inherited down the hierarchy. In practice it is set at the course level and applies to the whole course, but a per-block override is possible via OLX import or direct modulestore writes.
It was built for the era when courses were loaded from disk by XMLModuleStore. That store is no longer in the default MODULESTORE configuration, so on a modern instance there is no supported way to put files where this setting points. Uploading through Files & Uploads writes to the contentstore, which this code path does not read. Placing files in STATIC_ROOT requires operator filesystem access or a custom image build, and the result would be world-readable, globally namespaced, and invisible to the Files page.
Meanwhile the setting is editable by any course author in Studio → Advanced Settings. It is not in FIELDS_EXCLUDE_LIST and no feature flag hides it. Setting it silently breaks every /static/ reference in the course, along with course_image and banner_image, while the Files page continues to list the now-unreachable assets. There is no error; the final except branch returns a path that 404s.
It is also threaded as a parameter through the block rendering path, which adds maintenance cost to code that is otherwise being actively reworked.
Removal
The field itself:
static_asset_pathfield definition —xmodule/modulestore/inheritance.py:133
The branches that honor it:
common/djangoapps/static_replace/__init__.py— thestatic_asset_pathparameter ofreplace_static_urls, theelif (not static_asset_path) and course_idguard (L199), and the filesystem branch (L226-L242)common/djangoapps/static_replace/services.py— L16, L26, L33, L57openedx/core/lib/courses.py:22-30— thecourse_image_urlbranchopenedx/core/lib/xblock_utils/__init__.py:299lms/djangoapps/staticbook/views.py:59
The parameter plumbing:
lms/djangoapps/courseware/block_render.py— L296, L317, L335, L394, L446, L506, L545, L575, L631lms/djangoapps/courseware/courses.py— L429, L488, L908lms/djangoapps/courseware/views/views.py:1310
One behavior change outside the field itself:
xmodule/modulestore/xml_importer.py:425-429setsstatic_asset_path = data_dirwhen a course is imported withdo_import_static=False(the--nostaticflag on./manage.py cms import). This assignment should be dropped. Whether--nostaticitself should stay is a separate question — it has a second effect (skipping the static import) that is independent of this setting.
Replacement
None. Course static assets are served from the contentstore today, and are being migrated to openedx_content under the ADRs in openedx-core#822. Nothing in that plan depends on static_asset_path, and removing it eliminates an asset-resolution mode those ADRs do not account for.
Courses that genuinely need to reference externally hosted files can use absolute URLs.
Deprecation
Before removal:
- Add
static_asset_pathtoFIELDS_EXCLUDE_LISTincms/djangoapps/models/settings/course_metadata.pyso it stops appearing in Studio Advanced Settings. This is a small change worth making on its own merits, independent of the DEPR outcome. - Log a warning when a course is rendered with a non-empty
static_asset_path.
Additional Info
No database migration is required — the value lives in the modulestore course block, and an unread field is inert.
If usage turns out to be zero, the 6-month default before breaking changes is worth shortening so this can land in Xylon (2027-04) rather than Y (2027-10).
The field is read inconsistently today: the XBlock rendering path reads the block's value (static_replace/services.py:57, xblock_utils/__init__.py:299) while course images and textbooks read the course's. Inheritance makes these agree unless the field is overridden on a sub-block, in which case /static/ rewriting and course-image resolution diverge. Removal resolves this.
Operators: please check whether any of your courses have this set, and report back on the Discourse thread. Courses with a non-empty static_asset_path are very likely already broken, so the results are worth looking at regardless of this proposal.
# ./manage.py lms shell
from xmodule.modulestore.django import modulestore
for c in modulestore().get_course_summaries():
course = modulestore().get_course(c.id)
if getattr(course, 'static_asset_path', ''):
print(c.id, repr(course.static_asset_path))Note that a course can have this set without anyone choosing it, via the --nostatic import path described above. The query above checks course blocks only; a per-block override would not show up, but there is no UI that produces one.
Transition Unblocked Tasks
- Add
static_asset_pathtoFIELDS_EXCLUDE_LIST - Add a warning log for courses with a non-empty value
- Collect usage reports from operators on the Discourse thread
Feature Removal Tasks
- Remove the field from
InheritanceMixin - Remove the filesystem branch from
replace_static_urlsand thestatic_asset_pathparameter from its signature - Remove the parameter from
static_replace/services.py - Remove the branch from
course_image_url - Remove usage in
xblock_utils,staticbook/views.py - Remove the parameter plumbing from
block_render.py,courseware/courses.py,courseware/views/views.py - Drop the
static_asset_pathassignment inxml_importer.py - Update tests that set
static_asset_path(lms/djangoapps/staticbook/tests.py,lms/djangoapps/mobile_api/testutils.py)
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDraft
Activity