[GH-ISSUE #4917] [Bug] Codex setup rejects valid 64-bit TOML integers as malformed configuration #3050

Closed
opened 2026-10-31 00:35:30 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @xu91102 on GitHub (Oct 17, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/4917

Before submitting

  • I searched open and closed issues and pull requests for related reports.
  • I removed credentials, private paths and sensitive target data.

Area

Setup, packaging, or upgrade

Observed behavior

With a valid Codex configuration containing a signed 64-bit integer outside JavaScript's safe integer range, REA refuses even a read-only setup plan. It returns exit 1, status: "needs_human", no planned/applied actions, and says the file is malformed because integer value cannot be represented losslessly.

The native Codex CLI accepts the exact same immutable files. The problem reproduced for both 9007199254740993 and 9223372036854775807 as [history].max_bytes. A small integer works in both clients. A value outside Int64, 9223372036854775808, is rejected by both and must remain rejected.

Reproduction

Starting from the compiled source revision below, create an isolated directory and write .codex/config.toml with:

[history]
max_bytes = 9223372036854775807

Run these commands with HOME pointing at that isolated directory and CODEX_HOME at its .codex subdirectory:

codex mcp list --json
node scripts/rea.mjs setup --client codex --dry-run --format json

I ran four immutable fixtures once each through both commands, with these results:

max_bytes Native Codex REA setup dry-run
1048576 exit 0, [] exit 0, planned
9007199254740993 exit 0, [] exit 1, needs_human
9223372036854775807 exit 0, [] exit 1, needs_human
9223372036854775808 exit 1, TOML range error exit 1, needs_human

Every configuration's SHA-256 remained unchanged. These are native configuration-read and REA dry-run controls; I did not run a Codex agent/model or apply a registration in this reproduction.

Expected behavior

Setup, doctor and uninstall should read valid client TOML without rounding unrelated integers or calling a valid file malformed. Setup should be able to add its own entry while preserving those values, backups and idempotency. Invalid or out-of-range client input must still fail before writes.

TOML 1.0's integer contract covers lossless signed 64-bit integers. The native Codex results above confirm the selected client accepts these concrete files. REA's existing setup contract also requires preserving unrelated configuration.

Impact and scope

Observed: two valid large-integer configurations deterministically block a setup plan; both controls behave as described above. No wrong write or data loss was observed. The common TOML reader is also used by Grok Build, but native Grok behavior has not been tested here.

REA version

6.5.0 source f0b9ef34c404c1c65f8167502db972b0bd708403, freshly built with the pinned toolchain.

Runtime and platform

Node 24.18.0, npm 11.16.0, macOS arm64; native codex-cli 0.160.1.

Target and artifact context

Self-authored isolated config.toml files; no analysis target or provider.

Interface

Package or setup

Earliest failure stage

Setup or provider admission

Relevant output or evidence

For the valid Int64 maximum, native codex mcp list --json returns [] with exit 0 and empty stderr. REA returns needs_human with this diagnostic:

Configuration <isolated-home>/.codex/config.toml is malformed:
Invalid TOML document: integer value cannot be represented losslessly

Analysis or suspected cause

Source-derived and checked against the installed dependency: ClientConfigurationDocument.ts calls smol-toml without integer-preservation options. Its default reader rejects integers beyond the safe Number range. The same raw parser is also used when checking that an edited TOML document preserves its values. A shared lossless reader must cover those consumers, retain normal Number behavior for existing safe settings, and keep the client's signed 64-bit rejection boundary.

The earlier #4856/#4870 line-expansion capacity fix and #4873 scan-cost fix concern different causes. I read their actual production changes. The earlier #2368 numeric-preservation change concerns Hermes YAML rather than this TOML admission failure.

Local fix and verification

A normal fork commit is now available: 5b4049135, based on d205c528e31897f1f2919b80a4245356b502c703. There is no upstream PR or upstream CI result for it.

The shared TOML owner retains exact integers when needed and rejects values outside signed Int64. Setup and doctor share positive timeout interpretation; the inline writer also retains exact values without triggering a whole-document fallback. The old setup-only timeout reader is removed. Dependency, tool schema, registration identity, transaction and backup ownership are unchanged.

The frozen final version passed 15 relevant files / 281 tests plus five distinct README checks: 286 total, zero skipped. Check, docs, discovery, actual package verification and explicit pack dry-run passed. A newly installed local tarball passed 30 CLI lifecycle calls across six Codex/Grok layouts, with exact original backups, peers, comments/history spelling and repeat bytes retained. Python 3.12 tomllib independently checked exact values; native Codex 0.160.1 accepted the before/after files in 24 read/list calls. Its own JSON timeout projection is not used as an exact integer oracle.

Independent Standards and Spec reviews both passed on the final frozen bytes. Earlier review failures exposed missing timeout and inline consumers; their actual public regression failures were retained and corrected before commit. No earlier run is added to the final test count.

Limits: native Codex configuration admission only; no native Grok client, full agent/model/server session, Windows/Linux or performance qualification. Local verification and fork publication do not establish human readiness, upstream CI, merge or release.

Publication update (2026-10-18)

The existing fork repair at 5b4049135e11d0f9993949795342ab99120e3e32 is now held read-only. I read the complete current diffs of #4935 (a7fc23d52afbdc3bacc1df1a5167c11cd3ff769a) and #4937 (3cbb8793ff9352b33cfc7f81177f250a866e7274): both address the same shared TOML parsing root and exact integer serialization, so I will not open a duplicate PR. Both were OPEN and unmerged when checked. I have not run either foreign head or established full coverage of my additional timeout and comment-preservation controls; the validation above remains bound to my original frozen fork. No upstream PR or CI run was created for my repair.

Merged-main follow-up (2026-10-18 02:02 UTC): #4937 was merged as 270bc38f7282f4bead10a652b7b328a96f6d739d, and this issue was closed by the maintainer. I independently read back the merge metadata and actual main production diff. My fork stays read-only; this is the other author's PR merge, not my own upstream PR or an established adoption of my fork. I have not run the merged Int64 workflow or certified full coverage of my extra controls.

Originally created by @xu91102 on GitHub (Oct 17, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4917 ### Before submitting - [x] I searched open and closed issues and pull requests for related reports. - [x] I removed credentials, private paths and sensitive target data. ### Area Setup, packaging, or upgrade ### Observed behavior With a valid Codex configuration containing a signed 64-bit integer outside JavaScript's safe integer range, REA refuses even a read-only setup plan. It returns exit 1, `status: "needs_human"`, no planned/applied actions, and says the file is malformed because `integer value cannot be represented losslessly`. The native Codex CLI accepts the exact same immutable files. The problem reproduced for both `9007199254740993` and `9223372036854775807` as `[history].max_bytes`. A small integer works in both clients. A value outside Int64, `9223372036854775808`, is rejected by both and must remain rejected. ### Reproduction Starting from the compiled source revision below, create an isolated directory and write `.codex/config.toml` with: ```toml [history] max_bytes = 9223372036854775807 ``` Run these commands with `HOME` pointing at that isolated directory and `CODEX_HOME` at its `.codex` subdirectory: ```sh codex mcp list --json node scripts/rea.mjs setup --client codex --dry-run --format json ``` I ran four immutable fixtures once each through both commands, with these results: | `max_bytes` | Native Codex | REA setup dry-run | | --- | --- | --- | | `1048576` | exit 0, `[]` | exit 0, `planned` | | `9007199254740993` | exit 0, `[]` | exit 1, `needs_human` | | `9223372036854775807` | exit 0, `[]` | exit 1, `needs_human` | | `9223372036854775808` | exit 1, TOML range error | exit 1, `needs_human` | Every configuration's SHA-256 remained unchanged. These are native configuration-read and REA dry-run controls; I did not run a Codex agent/model or apply a registration in this reproduction. ### Expected behavior Setup, doctor and uninstall should read valid client TOML without rounding unrelated integers or calling a valid file malformed. Setup should be able to add its own entry while preserving those values, backups and idempotency. Invalid or out-of-range client input must still fail before writes. [TOML 1.0's integer contract](https://toml.io/en/v1.0.0#integer) covers lossless signed 64-bit integers. The native Codex results above confirm the selected client accepts these concrete files. REA's existing setup contract also requires preserving unrelated configuration. ### Impact and scope Observed: two valid large-integer configurations deterministically block a setup plan; both controls behave as described above. No wrong write or data loss was observed. The common TOML reader is also used by Grok Build, but native Grok behavior has not been tested here. ### REA version 6.5.0 source `f0b9ef34c404c1c65f8167502db972b0bd708403`, freshly built with the pinned toolchain. ### Runtime and platform Node 24.18.0, npm 11.16.0, macOS arm64; native `codex-cli 0.160.1`. ### Target and artifact context Self-authored isolated `config.toml` files; no analysis target or provider. ### Interface Package or setup ### Earliest failure stage Setup or provider admission ### Relevant output or evidence For the valid Int64 maximum, native `codex mcp list --json` returns `[]` with exit 0 and empty stderr. REA returns `needs_human` with this diagnostic: ```text Configuration <isolated-home>/.codex/config.toml is malformed: Invalid TOML document: integer value cannot be represented losslessly ``` ### Analysis or suspected cause Source-derived and checked against the installed dependency: `ClientConfigurationDocument.ts` calls `smol-toml` without integer-preservation options. Its default reader rejects integers beyond the safe Number range. The same raw parser is also used when checking that an edited TOML document preserves its values. A shared lossless reader must cover those consumers, retain normal Number behavior for existing safe settings, and keep the client's signed 64-bit rejection boundary. The earlier #4856/#4870 line-expansion capacity fix and #4873 scan-cost fix concern different causes. I read their actual production changes. The earlier #2368 numeric-preservation change concerns Hermes YAML rather than this TOML admission failure. ### Local fix and verification A normal fork commit is now available: [5b4049135](https://github.com/xu91102/rea/commit/5b4049135e11d0f9993949795342ab99120e3e32), based on `d205c528e31897f1f2919b80a4245356b502c703`. There is no upstream PR or upstream CI result for it. The shared TOML owner retains exact integers when needed and rejects values outside signed Int64. Setup and doctor share positive timeout interpretation; the inline writer also retains exact values without triggering a whole-document fallback. The old setup-only timeout reader is removed. Dependency, tool schema, registration identity, transaction and backup ownership are unchanged. The frozen final version passed 15 relevant files / 281 tests plus five distinct README checks: 286 total, zero skipped. Check, docs, discovery, actual package verification and explicit pack dry-run passed. A newly installed local tarball passed 30 CLI lifecycle calls across six Codex/Grok layouts, with exact original backups, peers, comments/history spelling and repeat bytes retained. Python 3.12 tomllib independently checked exact values; native Codex 0.160.1 accepted the before/after files in 24 read/list calls. Its own JSON timeout projection is not used as an exact integer oracle. Independent Standards and Spec reviews both passed on the final frozen bytes. Earlier review failures exposed missing timeout and inline consumers; their actual public regression failures were retained and corrected before commit. No earlier run is added to the final test count. Limits: native Codex configuration admission only; no native Grok client, full agent/model/server session, Windows/Linux or performance qualification. Local verification and fork publication do not establish human readiness, upstream CI, merge or release. ### Publication update (2026-10-18) The existing fork repair at `5b4049135e11d0f9993949795342ab99120e3e32` is now held read-only. I read the complete current diffs of #4935 (`a7fc23d52afbdc3bacc1df1a5167c11cd3ff769a`) and #4937 (`3cbb8793ff9352b33cfc7f81177f250a866e7274`): both address the same shared TOML parsing root and exact integer serialization, so I will not open a duplicate PR. Both were OPEN and unmerged when checked. I have not run either foreign head or established full coverage of my additional timeout and comment-preservation controls; the validation above remains bound to my original frozen fork. No upstream PR or CI run was created for my repair. Merged-main follow-up (2026-10-18 02:02 UTC): #4937 was merged as `270bc38f7282f4bead10a652b7b328a96f6d739d`, and this issue was closed by the maintainer. I independently read back the merge metadata and actual main production diff. My fork stays read-only; this is the other author's PR merge, not my own upstream PR or an established adoption of my fork. I have not run the merged Int64 workflow or certified full coverage of my extra controls.
Author
Owner

@XinwangTao commented on GitHub (Oct 18, 2026):

Solid analysis — the root cause (smol-toml defaulting to JS number conversion without integer preservation) matches what I'd expect: 9007199254740993 and 9223372036854775807 both exceed Number.MAX_SAFE_INTEGER, so any naive read rounds them or refuses them, while native Codex reads them losslessly as i64. Rejecting 9223372036854775808 (outside Int64) is the right contract to keep.

The draft fix direction (read client TOML integers losslessly) looks correct. A couple of additional points worth covering in #4935:

  1. Since the issue notes the common TOML reader is also used by Grok Build, add a Grok-side fixture to the tests so this doesn't regress silently in the other client.
  2. Keep the "invalid or out-of-range input must still fail before writes" guarantee — make sure the lossless read path doesn't weaken admission for genuinely malformed values (e.g. floats or overflow beyond i64).
  3. The setup contract requires preserving unrelated config and idempotency — good to assert in tests that max_bytes round-trips byte-for-byte after a plan is applied.
<!-- gh-comment-id:6244200545 --> @XinwangTao commented on GitHub (Oct 18, 2026): Solid analysis — the root cause (smol-toml defaulting to JS number conversion without integer preservation) matches what I'd expect: 9007199254740993 and 9223372036854775807 both exceed Number.MAX_SAFE_INTEGER, so any naive read rounds them or refuses them, while native Codex reads them losslessly as i64. Rejecting 9223372036854775808 (outside Int64) is the right contract to keep. The draft fix direction (read client TOML integers losslessly) looks correct. A couple of additional points worth covering in #4935: 1. Since the issue notes the common TOML reader is also used by Grok Build, add a Grok-side fixture to the tests so this doesn't regress silently in the other client. 2. Keep the "invalid or out-of-range input must still fail before writes" guarantee — make sure the lossless read path doesn't weaken admission for genuinely malformed values (e.g. floats or overflow beyond i64). 3. The setup contract requires preserving unrelated config and idempotency — good to assert in tests that max_bytes round-trips byte-for-byte after a plan is applied.
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
morluto/rea#3050
No description provided.