Describe the bug
Any request to /settings/update deletes the user's subscriptions and filters cookies unless those two fields happen to be present in the query string.
/settings/update is the "quick update one preference" endpoint. It calls set_cookies_method(req, false) — i.e. remove_cookies = false, meaning "don't clear settings that weren't passed". The PREFS loop honours that flag, but the subscriptions and filters blocks below it do not: their else branches call remove_cookie(...) unconditionally.
This is reachable from links that ship in the UI, so a user can lose their entire subscription list with one click and no warning:
| Template |
Link |
templates/utils.html |
Enable HLS (?use_hls=on) |
templates/utils.html |
disable this notification (?hide_hls_notification=on) |
templates/nsfwlanding.html |
bypass this gate link (?show_nsfw=on) |
POST /settings is unaffected — it's a separate handler (settings::set) that doesn't touch these cookies at all.
Steps to reproduce the bug
Reproduced on a from-source build of main at a4d36e954cf1bd64f209cd8868c5a29edc81b374.
curl -s -D - -o /dev/null \
-H 'Cookie: subscriptions=selfhosted+Fedora+linux; filters=spam' \
'http://127.0.0.1:8080/settings/update?use_hls=on&redirect=/r/selfhosted'
Response headers:
set-cookie: use_hls=on; HttpOnly; Path=/; Expires=Sun, 25 Jul 2027 19:48:04 GMT
set-cookie: subscriptions=; HttpOnly; Path=/; Expires=Sun, 26 Jul 2026 19:48:04 GMT
set-cookie: filters=; HttpOnly; Path=/; Expires=Sun, 26 Jul 2026 19:48:04 GMT
The second and third are deletion cookies (expiry = now). Same result with ?show_nsfw=on and ?hide_hls_notification=on.
Control — POST /settings correctly leaves them alone:
curl -s -D - -o /dev/null -X POST \
-H 'Cookie: subscriptions=selfhosted+Fedora' \
-d 'use_hls=on' 'http://127.0.0.1:8080/settings'
# no subscriptions=/filters= deletion cookies
In the browser: subscribe to a few subreddits, open a video post, click Enable HLS — the subscription list is empty afterwards.
What's the expected behavior?
/settings/update should only change the preference named in the query string. Subscriptions and filters should be left untouched, exactly as the remove_cookies = false flag already implies for everything in PREFS.
/settings/restore (remove_cookies = true) should keep its current behaviour — it restores a complete state, so clearing what's absent is correct there.
Additional context / screenshot
Root cause, src/settings.rs (line numbers from a4d36e9):
// line 143 — the PREFS loop honours the flag:
None => {
if remove_cookies {
response.remove_cookie(name.to_string());
}
}
// line 195 — subscriptions block does not:
} else {
// Remove unnumbered subscriptions cookie
response.remove_cookie("subscriptions".to_string());
...
}
// line 246 — same for filters
} else {
// Remove unnumbered filters cookie
response.remove_cookie("filters".to_string());
...
}
A minimal fix is to gate both else branches on the existing flag:
- } else {
+ } else if remove_cookies {
// Remove unnumbered subscriptions cookie
response.remove_cookie("subscriptions".to_string());
- } else {
+ } else if remove_cookies {
// Remove unnumbered filters cookie
response.remove_cookie("filters".to_string());
I'm running this two-line change on my own instance and it behaves as expected: /settings/update stops clearing the cookies, /settings/restore still clears them when they're absent from the query, and POST /settings is unchanged.
Root-cause analysis assisted by Claude Fable 5; the reproduction above was run against a clean from-source build of main.
Describe the bug
Any request to
/settings/updatedeletes the user'ssubscriptionsandfilterscookies unless those two fields happen to be present in the query string./settings/updateis the "quick update one preference" endpoint. It callsset_cookies_method(req, false)— i.e.remove_cookies = false, meaning "don't clear settings that weren't passed". ThePREFSloop honours that flag, but thesubscriptionsandfiltersblocks below it do not: theirelsebranches callremove_cookie(...)unconditionally.This is reachable from links that ship in the UI, so a user can lose their entire subscription list with one click and no warning:
templates/utils.html?use_hls=on)templates/utils.html?hide_hls_notification=on)templates/nsfwlanding.html?show_nsfw=on)POST /settingsis unaffected — it's a separate handler (settings::set) that doesn't touch these cookies at all.Steps to reproduce the bug
Reproduced on a from-source build of
mainata4d36e954cf1bd64f209cd8868c5a29edc81b374.Response headers:
The second and third are deletion cookies (expiry = now). Same result with
?show_nsfw=onand?hide_hls_notification=on.Control —
POST /settingscorrectly leaves them alone:In the browser: subscribe to a few subreddits, open a video post, click Enable HLS — the subscription list is empty afterwards.
What's the expected behavior?
/settings/updateshould only change the preference named in the query string. Subscriptions and filters should be left untouched, exactly as theremove_cookies = falseflag already implies for everything inPREFS./settings/restore(remove_cookies = true) should keep its current behaviour — it restores a complete state, so clearing what's absent is correct there.Additional context / screenshot
Root cause,
src/settings.rs(line numbers froma4d36e9):A minimal fix is to gate both
elsebranches on the existing flag:I'm running this two-line change on my own instance and it behaves as expected:
/settings/updatestops clearing the cookies,/settings/restorestill clears them when they're absent from the query, andPOST /settingsis unchanged.Root-cause analysis assisted by Claude Fable 5; the reproduction above was run against a clean from-source build of main.