[bug] Settings POST endpoint silently drops keys not in DEFAULT_SETTINGS — non-default prefs lost on save #921

Closed
opened 2026-06-04 11:32:03 +02:00 by sleepy · 1 comment
Owner

Bug

When the Settings UI saves via POST /api/auth/settings, the handler at routes/settings_routes.py:60-69 only writes back keys that exist in DEFAULT_SETTINGS:

for key in DEFAULT_SETTINGS:
    if key in body:
        current[key] = body[key]

Keys that were added to settings.json by other code paths (tool manager, email routes, skill routes, etc.) but are NOT in DEFAULT_SETTINGS get silently dropped on every save cycle. This includes:

  • disabled_tools
  • email_auto_summarize, email_auto_reply, email_auto_tag, email_auto_spam, email_auto_calendar
  • email_writing_style
  • Any future settings added by routes without updating DEFAULT_SETTINGS

Meanwhile, load_settings() does {**DEFAULT_SETTINGS, **saved} which DOES preserve extras in the file. The bug only triggers when the Settings UI does a save — it rewrites the file with only DEFAULT_SETTINGS keys, nuking everything else.

Root Cause

The set_settings POST handler iterates over DEFAULT_SETTINGS keys instead of merging the body into the current settings. It should write back ALL existing keys plus any new ones from the body.

Fix

# Before (broken):
for key in DEFAULT_SETTINGS:
    if key in body:
        current[key] = body[key]

# After (correct):
for key in body:
    current[key] = body[key]

This lets the frontend send partial updates (only changed fields) while preserving all existing keys. Should also validate that unknown keys are allowed (or at least log a warning).

Reproduction

  1. Set email_writing_style via chat tool (manage_settings set email_writing_style=...)
  2. Open Settings UI, change any unrelated setting (e.g. toggle a feature)
  3. Save
  4. email_writing_style is gone from data/settings.json

Impact

This is the likely cause of reported symptoms: teacher model settings, default chat model, and other non-DEFAULT_SETTINGS keys not surviving across restarts — they survive the restart itself (load_settings merges fine), but get wiped the next time the Settings panel saves.

## Bug When the Settings UI saves via `POST /api/auth/settings`, the handler at `routes/settings_routes.py:60-69` only writes back keys that exist in `DEFAULT_SETTINGS`: ```python for key in DEFAULT_SETTINGS: if key in body: current[key] = body[key] ``` Keys that were added to `settings.json` by other code paths (tool manager, email routes, skill routes, etc.) but are NOT in `DEFAULT_SETTINGS` get silently dropped on every save cycle. This includes: - `disabled_tools` - `email_auto_summarize`, `email_auto_reply`, `email_auto_tag`, `email_auto_spam`, `email_auto_calendar` - `email_writing_style` - Any future settings added by routes without updating `DEFAULT_SETTINGS` Meanwhile, `load_settings()` does `{**DEFAULT_SETTINGS, **saved}` which DOES preserve extras in the file. The bug only triggers when the Settings UI does a save — it rewrites the file with only `DEFAULT_SETTINGS` keys, nuking everything else. ## Root Cause The `set_settings` POST handler iterates over `DEFAULT_SETTINGS` keys instead of merging the body into the current settings. It should write back ALL existing keys plus any new ones from the body. ## Fix ```python # Before (broken): for key in DEFAULT_SETTINGS: if key in body: current[key] = body[key] # After (correct): for key in body: current[key] = body[key] ``` This lets the frontend send partial updates (only changed fields) while preserving all existing keys. Should also validate that unknown keys are allowed (or at least log a warning). ## Reproduction 1. Set `email_writing_style` via chat tool (`manage_settings set email_writing_style=...`) 2. Open Settings UI, change any unrelated setting (e.g. toggle a feature) 3. Save 4. `email_writing_style` is gone from `data/settings.json` ## Impact This is the likely cause of reported symptoms: teacher model settings, default chat model, and other non-DEFAULT_SETTINGS keys not surviving across restarts — they survive the restart itself (load_settings merges fine), but get wiped the next time the Settings panel saves.
Author
Owner

Fixed in PR #928 — merged to dev via --no-ff. Root cause: PUT /settings iterated over DEFAULT_SETTINGS keys instead of body keys, so any setting not in the defaults was silently dropped. Fix: iterate body keys, guard with if key in current to prevent arbitrary key injection.

Fixed in PR #928 — merged to dev via --no-ff. Root cause: PUT /settings iterated over DEFAULT_SETTINGS keys instead of body keys, so any setting not in the defaults was silently dropped. Fix: iterate body keys, guard with `if key in current` to prevent arbitrary key injection.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sleepy/odysseus#921
No description provided.