← Back to PRs

#22524: fix(doctor): preserve precision of large Discord snowflake IDs in --fix

by jmasson open 2026-02-21 08:08 View on GitHub →
commands size: S
## Summary - Problem: `doctor --fix` silently corrupts Discord snowflake IDs that exceed `Number.MAX_SAFE_INTEGER`. `JSON5.parse()` rounds the bare integer, then the repair stringifies the lossy number — producing a valid-looking but wrong ID. - Why it matters: The original Discord ID digits are lost permanently, breaking authorization. - What changed: `maybeRepairDiscordNumericIds` now accepts the raw config file text and extracts original digit sequences via regex before conversion. Handles collisions where multiple distinct IDs round to the same `Number` by consuming originals in file order. - What did NOT change (scope boundary): No changes to schema validation, config parsing, or other repair functions. ## Change Type (select all) - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Docs - [ ] Security hardening - [ ] Chore/infra ## Scope (select all touched areas) - [ ] Gateway / orchestration - [ ] Skills / tool execution - [ ] Auth / tokens - [ ] Memory / storage - [x] Integrations - [ ] API / contracts - [x] UI / DX - [ ] CI/CD / infra ## Linked Issue/PR - Related #18220 (introduced the Discord ID string requirement and `doctor --fix` repair) ## User-visible / Behavior Changes - `doctor --fix` now preserves the exact original digits of large Discord IDs instead of silently truncating them. - Change output includes `(recovered original precision from file)` when raw text recovery is used. ## Security Impact (required) - New permissions/capabilities? No - Secrets/tokens handling changed? No - New/changed network calls? No - Command/tool execution surface changed? No - Data access scope changed? No ## Repro + Verification ### Environment - OS: Any - Runtime/container: Node.js - Integration/channel (if any): Discord ### Steps 1. Write `openclaw.json` with a bare numeric Discord ID exceeding MAX_SAFE_INTEGER, e.g. `{ "channels": { "discord": { "allowFrom": [100000000000000001] } } }` 2. Run `openclaw doctor --fix` 3. Check the written config ### Expected - `allowFrom` contains `"100000000000000001"` (original digits preserved) ### Actual - Before fix: `allowFrom` contains `"100000000000000000"` (truncated) - After fix: `allowFrom` contains `"100000000000000001"` (correct) ## Evidence - [x] Failing test/log before + passing after - [ ] Trace/log snippets - [ ] Screenshot/recording - [ ] Perf numbers (if relevant) Two new e2e tests: single large ID precision preservation, and multiple IDs that round to the same `Number`. ## Human Verification (required) - Verified scenarios: All 14 e2e tests pass including 2 new precision tests - Edge cases checked: Multiple IDs colliding to same lossy Number value - What you did **not** verify: Manual end-to-end run with a real Discord bot token ## Compatibility / Migration - Backward compatible? Yes - Config/env changes? No - Migration needed? No ## Failure Recovery (if this breaks) - How to disable/revert this change quickly: Revert commit; the repair falls back to `String(entry)` when raw text is unavailable - Files/config to restore: None - Known bad symptoms reviewers should watch for: Discord IDs in config not matching expected values after doctor --fix ## Risks and Mitigations - Risk: Regex extracts a bare integer from raw text that isn't actually a Discord ID (e.g. in a comment or unrelated field). - Mitigation: The lookup is keyed by the lossy Number value, so it only matches when the parsed config already contains that exact number in a Discord ID list. False positives would require an unrelated bare integer that happens to round to the same Number as a Discord ID in the same config file. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR fixes a critical data corruption bug in `doctor --fix` where large Discord snowflake IDs exceeding `Number.MAX_SAFE_INTEGER` were silently truncated during repair. **Key changes:** - `maybeRepairDiscordNumericIds` now accepts raw config file text and extracts original digit sequences via regex before JSON parsing - Handles collision cases where multiple distinct IDs round to the same `Number` by storing them in an array and consuming in file order (matching JSON parse order) - Scopes regex extraction to only the Discord config section using brace-depth tracking with proper string literal handling - Adds string-skipping logic to correctly handle braces and quotes inside JSON strings - Includes comprehensive test coverage for both single large ID preservation and collision scenarios All previously identified issues from review threads have been addressed. <h3>Confidence Score: 4/5</h3> - Safe to merge with minor risk around edge cases in Discord config section extraction - All previously identified critical bugs have been fixed (map collisions, string handling, test coverage). The implementation correctly handles the complex case of multiple IDs rounding to the same Number. String-skipping logic properly handles escape sequences. However, deducting one point because the regex-based extraction from raw text could theoretically match unrelated 16+ digit numbers in comments or other Discord fields that happen to round to the same value as actual IDs, though this is acknowledged as a known risk with reasonable mitigation. - No files require special attention - all critical issues from previous review have been addressed <sub>Last reviewed commit: 9791c9c</sub> <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs