#141166·Kubernetes

Burndown: Quantity int64 overflow and checked accessors

Author: jpbetzCreated Aug 4, 2026Updated Sep 17, 2026
Labelskind/bugkind/cleanupsig/api-machinerytriage/accepted

This tracks ongoing and planned work to fix resource.Quantity's int64 accessor overflow behavior.

Goal

  • Resolve all known correctness issues, lock in correct behavior with tests
  • Introduce (int64, ok bool) checked accessors (AsScaledInt64, AsMilliInt64) so that callers can detect overflow. ok is false on overflow and the returned value saturates at the sign-correct MinInt64/MaxInt64 rail (matching Go's strconv) rather than wrapping, so an overflowed result is the least dangerous value possible. Landed in #141305.
  • Convert all existing accessors that don't return an ok bool (Value, MilliValue, ScaledValue) to wrap the checked accessors and drop the bool. Landed in #141305.

Known Gaps

Expression Returns Gap
NewScaledQuantity(MaxInt64, 1).Value() -10 multiply wraps around 64 bits
MustParse("100E").Value() 0 conversion fails internally and falls back to zero
MustParse("9223372036854775808").Value() MinInt64 barely-too-large value becomes negative
MustParse("-9.5Gi").Value() 8246196746 bug in unsigned math flips the sign (#138510)
NewQuantity(MinInt64).Neg() MinInt64 −MinInt64 doesn't fit in int64, so negation silently does nothing
zero.Sub(MinInt64 quantity) MinInt64 similar to above, but using .Sub() instead of .Neg()
MustParse("1000E").String() "1" serialization drops the suffix for decimal values above 10^18 (#140459)
ParseQuantity("1e4294967297") 10, no error exponent is truncated to 32 bits (2³²+1 → 1), should be parse error
NewQuantity(MinInt64).Neg(); q.AsInt64() (MinInt64, true) AsInt64 reports ok=true for a value that isn't the true result of the operation; same after zero.Sub(MinInt64 quantity)
MustParse("1e100").Value() vs MustParse("1e100").ToDec().Value() 0 vs MinInt64 same input, different wrong values on the int64 vs Dec backends; fixes must land on both paths

Task List

  • #138309: parse boundary tests (18/19/20 digits, MinInt64/MaxInt64 +/- 1)

  • #140556, #140518, #140702: shared inf.Dec state (aliasing) fixes for #140744

  • #141170: baseline test matrix; each wrong-today field carries a TODO for its fixed value; suite green on master so it doubles as the burndown tracker

  • #138510: scaledValue negative rounding + tests

  • #140459: String() suffix drop for DecimalSI > 10^18

    • #141817: regression from #140459. BinarySI values >= 1024 that are not a multiple of 1024 serialize in e notation when divisible by 10 (NewQuantity(5000000000, BinarySI) -> "5e9", was "5000000000"). Must land before 1.38.
  • #140674: MaxMilliQuantity + overflow docs

  • #138507: EBNF grammar fix for integer exponents

  • #141264: fix MinInt64 Neg/Sub via decimal fallback; extreme source scales tracked separately

  • #141169: switch validateBasicResource to Sign() < 0

  • #141181: stop using Value() overflow to detect sign or unset limits in csi_client.go and eviction

  • Checked-accessor contract settled: (int64, ok bool), saturate at the sign-correct rail, round away from zero, Dec path matches; accessors and wrapper flip land together

  • #141305 (@thc1006): add AsScaledInt64/AsMilliInt64, switch Value/MilliValue/ScaledValue to saturating wrappers, bound int64MultiplyScale*/scaledValue; fixes cmd/ kubelet/app/server.go:1425 in lockstep

  • #141937: AsApproximateFloat64 NaN for zero at large scale

  • #141938: MustParse near MaxInt64. Skew note: CEL isInteger()/asInteger() start returning true/values for 19-digit quantities.

  • #141203 (@thc1006): reject exponents that don't fit in int32 (1e4294967297)

  • #142013: Cmp bounding

  • #141201 (@semx): regression test for Scale(MinInt32).infScale() sign edge case

  • #141980: clear cached serialization when JSON/CBOR null resets a Quantity

  • #142104: AsInt64 answers the same on both backends (Cmp's ToDec side effect turned "50k" from (50000, true) into (0, false)); value-based follow-up (1000m, 1.5Gi -> whole, true) pending decision

  • #141306 (@thc1006, draft since 08-11): bound work when parsing sub-nano quantities

  • #142156: fix canonical exponent overflow (q := MustParse("1000e2147483647"); q.String() returns "1e-2147483646")

  • TODO: String() fast path caches non-canonical spellings verbatim (+1, 01, 1E3, 1e+21, 1e0); pinned as current behavior by #142052, untouched by #138166; needs an owner and a compatibility decision

  • TODO: resolve extreme source-scale behavior in conversion, comparison and Neg/Sub; #141201 tests the MinInt32 edge but does not fix it

  • TODO: audit remaining scale arithmetic and work bounds in Add/Sub, AsScale and AsFloat64Slow

  • Move callers doing raw int64 math to Cmp or the checked accessors:

    • #141348 LimitRanger min/max/ratio
    • #141349 core validation integer-resource check
    • #141352 hugepage divisibility
    • #141327 kubelet CPU quota/shares conversions
    • #141328 scheduler NodeInfo requested totals
    • #141618 PV controller explicit binding (#141617)
    • #142088 volumebinding CSI capacity check and capacity-change queueing hint
    • #141999 HPA individual requests and per-pod container sums
    • #141978 HPA resource utilization totals and percentages
    • #141397 HPA replica-count narrowing
    • TODO: HPA GetMetricUsageRatio sums and remaining scaling-policy arithmetic
    • #140442, #140666 DRA consumable-capacity request and range bounds
    • #141705 (@piyushrajyadav, fixes #141216): DRA negative counter validation and allocator guards
    • TODO: kubelet QoS CPU/memory sums and reserve-percentage arithmetic
    • #141334: kubelet CPU overhead subtraction after lossy quota/shares conversion (follow-up issue)
    • #142112 (@Octopusjust): scheduler scoring additions and request-change event comparisons (the resource_allocation.go hunk stays in #141328)
    • #142131 (@6democratickim9): fractional-byte warnings in pod and PVC via AsScale(0) exactness
    • TODO: ceil(MilliValue/MilliValue) in pkg/api/v1/resource/helpers.go and its two kubectl copies
    • TODO (low priority): endpointslice topologycache zone ratios
    • TODO: compatibility decision for LimitRanger re-admission of unchanged PVC values (#141348 merged without it; #141352 ratchets stored pod-level hugepages), plus create/update/skew test coverage for the chosen behavior
  • #140135: OpenAPI description CommonMark formatting

  • #142052 (@krishhna24): golden String/JSON/CBOR/proto tests; lifts the hold on #138166

  • TODO: CEL isInteger()/asInteger() coverage for 19-digit quantities (#141938)

  • #138166 (@tgao26, fixes #138165): canonicalization of fractional decimal inputs; /hold until #142052 merges; needs rebase; must stay backward compatible

  • #135995: Mul/Div

Exit criteria

An item is done when it has a merged fix with regression coverage, or an explicit deferral to a linked follow-up issue with an owner. The tracker closes when every task-list line is one of those two.

Out of scope: #140744 and #141404 (shallow-copy detection and the read-mutation data race, separate effort), #137590 (parse-format widening), #131972 (CRD formats).

/sig api-machinery /kind bug /kind cleanup cc @liggitt @thc1006 @qflen @pohly @semx