#11602: fix(config): skip stale legacy config files when openclaw.json exists
commands
size: M
Cluster:
Cross-Platform Fixes
## Summary
Fix for #11465 — After migrating from clawdbot to openclaw, the gateway reads stale legacy config files (clawdbot.json, moltbot.json, moldbot.json) causing validation failures and log spam every ~10 seconds via systemd restart loop.
## Root Cause
`resolveDefaultConfigCandidates()` in `src/config/paths.ts` generates candidate config paths including legacy filenames for every directory, even when `openclaw.json` already exists there. When a migration symlink exists (`~/.clawdbot → ~/.openclaw`), the stale legacy config gets picked up, fails validation, and the gateway crashes repeatedly.
## Changes
### Primary fix (`src/config/paths.ts`)
- `resolveDefaultConfigCandidates()` now checks if `openclaw.json` exists in each candidate directory
- If it does, legacy filenames (clawdbot.json, moltbot.json, moldbot.json) are skipped for that directory
- Added `skipLegacyIfNewExists` option (default `true`) for backward compatibility in tests
- Exported `LEGACY_CONFIG_FILENAMES` for use by doctor cleanup
### Doctor cleanup (`src/commands/doctor-config-flow.ts`)
- New `renameStaleLegacyConfigs()` function that renames stale legacy configs to `<name>.migrated` when `openclaw.json` exists
- Respects `OPENCLAW_STATE_DIR` via `resolveStateDir()`
- Called during `openclaw doctor` flow after legacy config migration
### Tests
- **`src/config/paths.test.ts`** — 4 new tests:
- Skip legacy filenames when `openclaw.json` exists in same dir
- Include legacy filenames when `openclaw.json` does not exist (backward compat)
- Skip legacy in custom `OPENCLAW_STATE_DIR` with `openclaw.json`
- Symlink regression test (`~/.clawdbot → ~/.openclaw`) — the exact reported scenario
- **`src/commands/doctor-config-flow.test.ts`** — 4 new tests:
- Rename stale legacy configs when `openclaw.json` exists
- Skip when no primary config
- Skip when no legacy configs
- `.migrated` collision (safe to run doctor twice)
- All 17 tests pass, all original tests preserved
## Backward Compatibility
- Legacy config paths still work for actual first-time migrations (when `openclaw.json` doesn't exist)
- Doctor renames to `.migrated` rather than deleting (recoverable)
- No changes to gateway startup logic
## Verification
```
pnpm check ✅ (typecheck + lint + format)
pnpm vitest run ... ✅ (17 tests pass)
```
## Sign-Off
- [x] AI-assisted (Claude Opus 4.6 via OpenClaw, with human review)
- [x] Fully tested (17 unit tests covering all edge cases)
- [x] Tested locally with OpenClaw instance
- [x] Understand what the code does
lobster-biscuit
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR addresses #11465 by preventing stale legacy config files (`clawdbot.json`, `moltbot.json`, `moldbot.json`) from being considered when `openclaw.json` already exists in the same directory.
Key changes:
- `src/config/paths.ts`: `resolveDefaultConfigCandidates()` now omits legacy config filenames per-directory when `openclaw.json` exists, and `resolveConfigPath()` applies the same rule for explicit `stateDir` paths. Legacy config env override support is extended by treating `CLAWDBOT_CONFIG_PATH` as a fallback when `OPENCLAW_CONFIG_PATH` is unset.
- `src/commands/doctor-config-flow.ts`: adds `renameStaleLegacyConfigs()` and runs it during `openclaw doctor` to rename stale legacy configs to `*.migrated` once a primary `openclaw.json` exists.
- Tests cover the primary skip behavior, the symlink regression case, state-dir override behavior, and doctor rename collision behavior.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk.
- Changes are localized to config-path candidate generation and a best-effort doctor cleanup, with targeted tests covering the reported symlink regression and state-dir override scenarios.
- No files require special attention
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#5638: fix: rewrite sessionFile paths during state dir migration
by lailoo · 2026-01-31
83.3%
#23666: fix(doctor): openclaw-browser.service falsely flagged as duplicate ...
by yinghaosang · 2026-02-22
81.9%
#21240: fix: GH#20607 prevent doctor from dropping custom config sections
by theognis1002 · 2026-02-19
81.6%
#18593: fix: resolve symlinks in session path validation (#18553)
by EpaL · 2026-02-16
81.3%
#3561: fix: fail fast when both state dirs exist
by adityarao3 · 2026-01-28
81.2%
#7611: fix: migrate channels.telegram.token to botToken on config load
by luiginotmario · 2026-02-03
81.1%
#17916: [ fix ] : correct config directory path during onboarding
by Dijo-404 · 2026-02-16
80.5%
#21188: doctor: clean up legacy Linux gateway services
by Phineas1500 · 2026-02-19
80.5%
#10182: fix: skip non-openclaw LaunchAgents in doctor gateway scan
by Yida-Dev · 2026-02-06
80.3%
#11455: fix(gateway): default gateway.mode to local when unset
by AnonO6 · 2026-02-07
79.6%