#22408: fix: doctor --fix now persists config when removing unrecognized keys
commands
size: XS
Cluster:
Doctor and Memory Health Checks
## Summary
Fixes #22272
When `doctor --fix` strips unknown config keys via `stripUnknownConfigKeys()`, the repaired config is correctly assigned to `cfg`, but `shouldWriteConfig` remains `false`.
In `doctor.ts`, `cfgForPersistence` is cloned from `cfg` **after** `loadAndMaybeMigrateDoctorConfig` returns — so the JSON comparison finds no diff and the file is never written to disk.
## Root Cause
In `doctor-config-flow.ts`, `shouldWriteConfig` is only set to `true` in the interactive (non-repair) path when the user confirms. In the `--fix` path, even though `pendingChanges` is `true` and `cfg` has been modified, `shouldWriteConfig` stays `false`.
## Fix
Set `shouldWriteConfig = true` when `shouldRepair` is active and `pendingChanges` were made, ensuring the caller always writes the repaired config to disk.
## Testing
1. Add an unrecognized key to `~/.openclaw/openclaw.json` (e.g. `models.providers.anthropic.cacheRetention`)
2. Run `openclaw doctor --fix`
3. Verify the key is removed from the config file
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Fixed a bug where `openclaw doctor --fix` would strip unrecognized config keys but fail to persist the changes to disk. The issue was that `shouldWriteConfig` remained `false` in the repair path, even though `pendingChanges` was `true` and `cfg` was modified.
The fix adds a check after all config repairs are complete: if `shouldRepair` is active (from `--fix` or `--yes` flag) and `pendingChanges` is `true`, it sets `shouldWriteConfig = true`. This ensures the caller in `doctor.ts` writes the repaired config to disk via the comparison at line 288-289.
The fix is minimal, well-placed, and directly addresses the root cause described in the PR description.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- The fix is a simple, well-targeted boolean assignment that directly addresses the bug described in the issue. The logic is sound: when repair mode is active and changes were made, the config should be written. The placement is correct (after all repairs, before the return statement), and the fix doesn't introduce any side effects or change existing behavior for interactive mode.
- No files require special attention
<sub>Last reviewed commit: d5676e5</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#22342: fix(doctor): --fix now actually removes unrecognized config keys
by MisterGuy420 · 2026-02-21
93.8%
#22501: fix(doctor): preserve logging config in doctor --fix
by Shuai-DaiDai · 2026-02-21
86.5%
#21240: fix: GH#20607 prevent doctor from dropping custom config sections
by theognis1002 · 2026-02-19
84.7%
#11602: fix(config): skip stale legacy config files when openclaw.json exists
by akoscz · 2026-02-08
79.4%
#23432: Doctor: prevent permissive secret file modes during --fix
by bmendonca3 · 2026-02-22
79.2%
#22524: fix(doctor): preserve precision of large Discord snowflake IDs in -...
by jmasson · 2026-02-21
78.7%
#21742: fix(doctor): warn on conflicting exec approval config surfaces
by habakan · 2026-02-20
78.6%
#18546: fix(doctor): replace deprecated `auth add` command reference
by Phineas1500 · 2026-02-16
78.5%
#4897: fix: config logic issues (#4689, #4654)
by lailoo · 2026-01-30
77.6%
#22327: fix(doctor): use gateway health status for memory search key check
by therk · 2026-02-21
76.9%