Remove sweep_orphaned_mounted_uploads feature flag
What does this MR do and why?
Removes the sweep_orphaned_mounted_uploads feature flag and makes the sweeping behavior unconditional.
The flag gated a before_destroy callback in the shared WithUploads concern that cleans up orphaned Upload rows. When a model is destroyed, CarrierWave may leave mounted uploads in the database if the underlying file is already missing from storage. The callback queues an after-commit deletion of these orphaned rows. When CarrierWave cleaned up correctly, the sweep is a no-op safety net.
This MR:
- Removes the
Feature.enabled?check inapp/models/concerns/with_uploads.rbso the sweep always runs - Deletes the feature flag definition at
config/feature_flags/gitlab_com_derisk/sweep_orphaned_mounted_uploads.yml - Removes the flag-disabled test context from
spec/models/concerns/with_uploads_spec.rb
GitLab Dedicated does not support feature flags, so this behavior only reaches Dedicated customers once the flag is removed. The rollout work item schedules this removal for milestone 19.5.
Rollout status: The feature flag has been enabled on all non-production environments (dev, pre, staging, staging-ref) since 2026-09-02 and on GitLab.com production since 2026-09-07, per https://gitlab.com/gitlab-com/gl-infra/feature-flag-log/-/issues/63739. No rollbacks have occurred, and monitoring showed no increase in destroy-path failure rates. The flag's database record is deleted via chatops only after the removal code is fully deployed, so old-version nodes keep the flag-gated sweep behavior (enabled) throughout the rolling deploy window.
References
- Feature issue: #602881 (closed)
- Flag introduced by: !251124 (merged)
- Rollout work item (resolves): #621779 (closed)
Screenshots or screen recordings
No UI changes.
How to set up and validate locally
-
In a rails console, pick a user with an avatar and remove the file from storage so CarrierWave's own cleanup skips the row:
user = User.find_by(username: 'root') # upload an avatar first via the UI if the user has none FileUtils.rm_f(user.avatar.path) -
Destroy the user and check that no orphaned
Uploadrow is left behind:user.destroy! Upload.where(model_type: 'User', model_id: user.id).count # => 0Before this change (with the flag disabled), the count stayed at 1.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Post-merge
Run these chatops commands to complete the rollout:
/chatops gitlab run release check <merge-request-url> 19.5
/chatops gitlab run feature delete sweep_orphaned_mounted_uploads --dev --pre --staging --staging-ref --production