Repository navigation
Description
Summary
settings.ParseBytes (pkgs/mcpx/internal/settings/value.go:450) accepts the non-finite float spellings NaN and Inf — bare and with size suffixes (NaNMB, InfGB) — and converts them to math.MinInt64 (-9223372036854775808) with no error. Validate's KindBytes branch (value.go:510-513) accepts anything ParseBytes does not error on, so a KindBytes setting (e.g. http.streamBufferInit, http.bodyLimit, artifacts.quota, logging.maxBytes) can be applied at any layer (file/env/flag/preset/runtime) with the value NaN and every reader then sees the most negative int64 there is.
This is a residual of #1697 (byte sizes accept negatives and int64 overflow), not a duplicate of it: #1697's acceptance pins refusing "negative results and magnitudes that do not fit in an int64". NaN is neither — every comparison against NaN is false, so a fix that adds the obvious sign/range checks (f < 0, f * mult > MaxInt64) still admits NaN (and a > MaxInt64 check alone admits +Inf spellings only via the conversion, not via the check). The non-finite spellings need an explicit math.IsNaN / math.IsInf rejection, and regression tests that name them.
Evidence (verified this run, main 74bf342)
Line trace, pkgs/mcpx/internal/settings/value.go:
ParseBytes(:450-479) strips a suffix, thenstrconv.ParseFloat(v, 64)+int64(f * float64(mult))with no finiteness check. Go'sParseFloatacceptsNaN,nan,Inf,+Inf,Infinity(case-insensitive); converting a non-finite float to int64 yieldsmath.MinInt64on amd64/arm64.ValidateKindBytes case (:510-513) returns an error only whenParseByteserrors — so the values above are valid settings.Set.Bytes()(:325) discards the parse error the same way.- Consumers spend the result as in mcpx(settings): byte sizes accept negatives and int64 overflow — http.streamBufferInit=-1 passes validation, then panics the CLI with 'makeslice: cap out of range' at the first streaming read #1697:
make([]byte, 0, set.Bytes("http.streamBufferInit"))(internal/cli/opcmd.go:557-558, internal/cli/client.go:1238) panics on the negative cap;http.MaxBytesReaderwith a negative limit (internal/daemon/routes_secrets.go:49,114 and the otherhttp.bodyLimitcall sites, whosebodyByteshelper at internal/daemon/server.go:1196 does not guard<= 0either) rejects every request body; guarded consumers (artifactsQuota <= 0= no ceiling, internal/artifacts/artifacts.go:483; loggingmaxBytes <= 0= default, internal/logging/file.go:86) silently reinterpret a configured cap as no cap / default.
Laptop probe (real ParseBytes extracted verbatim from internal/settings/value.go; the laptop clone's file is md5-identical to sandbox main, b55906a4286878d8897d1e60300e0f5c; probe + logs at ~/git/fleet/probe-2026-11-01-laneA-parsebytes/ on the laptop):
"16MB" -> 16000000 err=<nil> validateAccepts=true (control)
"64KiB" -> 65536 err=<nil> validateAccepts=true (control)
"banana" -> 0 err=not a size: "banana" validateAccepts=false (control)
"1e999" -> 0 err=not a size: "1e999" validateAccepts=false (ParseFloat range error — correctly refused)
"NaN" -> -9223372036854775808 err=<nil> validateAccepts=true
"nan" -> -9223372036854775808 err=<nil> validateAccepts=true
"Inf" -> -9223372036854775808 err=<nil> validateAccepts=true
"+Inf" -> -9223372036854775808 err=<nil> validateAccepts=true
"NaNMB" -> -9223372036854775808 err=<nil> validateAccepts=true
"InfGB" -> -9223372036854775808 err=<nil> validateAccepts=true
Note the contrast the probe pins: 1e999 is refused because ParseFloat itself range-errors, while the named non-finite spellings sail through the same parser — the hole is specifically the non-finite names, not float parsing in general.
Why it matters
The settings system is the choke point whose job is keeping an invalid value out of a running process. A generated or fat-fingered config carrying NaN (a spelling JSON-adjacent tooling and template engines readily emit for "unknown") currently validates cleanly and then either crashes the CLI at the first streaming read, makes the daemon reject every request body, or silently uncaps a store quota the operator believed was set — the same three failure shapes as #1697, reachable through a spelling its fix does not obviously cover.
Acceptance criteria
-
ParseBytesrefuses non-finite results:NaN,nan,Inf,+Inf,Infinity— bare and with every size suffix (e.g.NaNMB,InfGB) — with an error naming the offending value. - Regression tests cover the non-finite spellings alongside mcpx(settings): byte sizes accept negatives and int64 overflow — http.streamBufferInit=-1 passes validation, then panics the CLI with 'makeslice: cap out of range' at the first streaming read #1697's negative/overflow cases (if mcpx(settings): byte sizes accept negatives and int64 overflow — http.streamBufferInit=-1 passes validation, then panics the CLI with 'makeslice: cap out of range' at the first streaming read #1697 lands first, extend its test table; the two issues' test cases must coexist).
- A
KindBytessetting therefore cannot be applied at any layer with a non-finite spelling; the error surfaces at apply time, not at first use. - Existing internal/settings, internal/cli and internal/daemon tests keep passing.
Notes for triage
- Related: mcpx(settings): byte sizes accept negatives and int64 overflow — http.streamBufferInit=-1 passes validation, then panics the CLI with 'makeslice: cap out of range' at the first streaming read #1697 (negatives + finite overflow in the same function — coordinate the fix; one
ParseByteschange can close both, but this issue's non-finite test cases are the part a sign/range-only fix misses). Distinct from mcpx(settings): reject non-positive ticker intervals before NewTicker #3467 (non-positive ticker intervals, KindDuration) and mcpx(plugin): goDurationMs treats Go-valid duration spellings as absent — dot fractions (.5s, 1.s) and Greek-mu μs (U+03BC) silently fall back to the default cooldown #3490 (Go duration spellings in the plugin's TS parser). - Found by new-issue-creator-code-a, 2026-11-01.
Activity
developing-today commentedon Nov 1, 2026
CODE-1350
dezren39 commentedon Nov 1, 2026
🤖 Agent note · filed
25 remaining items
dezren39 commentedon Nov 3, 2026
agent-note:v1
event: picked-up
task: 6147 (repo-health-code-pilot, repo-worker-code; lane 9aca43b4-5439-4939-9f71-323f5d32521b)
state: claimed (resume of parked task); prior work intact
verified: Fresh 2026-11-03T08:28Z: branch queue/6147-3521-parsebytes-nonfinite @ 8643e8a exists in /home/user/git/fleet/6147-3521-parsebytes-nonfinite (clean); PR #4788 OPEN; diff matches packet scope (explicit math.IsNaN/IsInf guard + extended test tables). CI so far: line-limit pass + CodeRabbit skipping; Go test workflows not yet reporting.
next: Run targeted go tests locally; read CI fresh; merge if green, else park.
Merge pull request #4788 from developing-today/queue/6147-3521-parseb…
dezren39 commentedon Nov 3, 2026
agent-note:v1
event: done
task: 6147 (repo-health-code-pilot, repo-worker-code; lane 9aca43b4-5439-4939-9f71-323f5d32521b)
state: MERGED — PR #4788 merged as eeb8764 (2026-11-03T08:24Z); issue closed by merge; merge commit on origin/main verified.
tests: Targeted
go test ./internal/settings/ -run TestParseBytes|TestByteSizes|TestValidatePASS in worktree; full settings package shows only the 5 pre-existing clean-main failures (TestEveryDocumentHasAChapter, TestEverySettingHasAnEffectProbeOrAnExemption, TestNoUndeclaredEnvRead, TestTheEnvironmentDocIsCurrent, TestTheScriptEnvironmentIsWhatTheCodeSets) proven identical on pristine origin/main worktree. CI on PR: production line-limit pass; mergeStateStatus CLEAN at merge.bookkeeping: sandbox backlog and sweep log deferred to fleet reconciliation.