← Back to PRs

#22648: fix(plugin-sdk): re-throw non-ENOENT errors in readJsonFileWithFallback

by adhitShet open 2026-02-21 13:09 View on GitHub →
size: XS trusted-contributor
## Summary `readJsonFileWithFallback` silently returns the fallback value for **every** filesystem error, not just `ENOENT`. This means permission errors (`EACCES`), filesystem corruption, and other unexpected conditions are swallowed — callers receive the default value and have no way to detect or recover from the real failure. ## Bug ```ts // Before — lines 19-22 if (code === "ENOENT") { return { value: fallback, exists: false }; } return { value: fallback, exists: false }; // ← same fallback for EACCES, EPERM, etc. ``` The `if (code === "ENOENT")` guard is correct, but the unconditional fallback on line 22 makes it a no-op: non-ENOENT errors fall through and silently return the same `{ value: fallback, exists: false }`. ## Fix ```ts // After if (code !== "ENOENT") { throw err; } return { value: fallback, exists: false }; ``` Invert the guard so that only `ENOENT` returns the fallback. All other errors propagate to the caller. ## Affected callers - `src/pairing/pairing-store.ts` — pairing code persistence - `extensions/msteams/src/store-fs.ts` — MS Teams channel store - Any plugin importing `readJsonFileWithFallback` from `openclaw/plugin-sdk` All callers currently assume errors are surfaced; this fix makes that assumption hold. ## Alignment with upstream direction Recent commits `083298ab` and `ec419895` hardened ENOENT handling in the memory module. This PR applies the same pattern to the plugin-sdk's shared JSON helper. ## Risk Low — the only behavioral change is that non-ENOENT errors now throw instead of being silently ignored. This is strictly safer: callers that were unknowingly receiving stale/default data will now see the real error. ## Test plan - [x] `npx oxfmt --check src/plugin-sdk/json-store.ts` — pass - [x] `npx oxlint src/plugin-sdk/json-store.ts` — 0 warnings, 0 errors - [x] `npx vitest run src/plugin-sdk/ --config vitest.unit.config.ts` — 22 tests pass (1 pre-existing import failure in index.test.ts unrelated to this change) 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- greptile_comment --> <h3>Greptile Summary</h3> Fixed a critical bug in `readJsonFileWithFallback` where non-`ENOENT` filesystem errors (permission errors, corruption, etc.) were silently swallowed and returned the fallback value instead of propagating to the caller. The fix inverts the error guard to re-throw all non-`ENOENT` errors, ensuring callers can detect and handle real failures. - Changed error handling logic from checking `code === "ENOENT"` followed by an unconditional fallback return, to `code !== "ENOENT"` with a `throw`, ensuring only missing-file errors return the fallback - Affects callers in `src/pairing/pairing-store.ts` and `extensions/msteams/src/store-fs.ts` which wrap this function for JSON persistence - Low risk change that strictly improves safety by exposing previously hidden errors <h3>Confidence Score: 5/5</h3> - This PR is safe to merge with no concerns - The fix is minimal, correct, and strictly safer than the existing code. It only changes behavior for error cases that were previously being silently ignored (non-ENOENT errors), ensuring they now propagate properly. The logic is straightforward and the change has been tested according to the PR description. - No files require special attention <sub>Last reviewed commit: 115fe23</sub> <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs