pre_process's width repair sizes a value with floor division dressed up as a ceiling, so any value just past an octet boundary is sized one octet too small and to_bytes raises OverflowError.
Mechanism
pcapkit/corekit/fields/numbers.py:198:
self._length = math.ceil(value.bit_length() // 8)
math.ceil on an int is a no-op — // has already floored it — so the expression is value.bit_length() // 8. The intent was evidently math.ceil(value.bit_length() / 8).
Measured
On origin/main (fa6d18e31), CPython 3.14.7:
value=255 bit_length=8 sized=1 -> ok
value=256 bit_length=9 sized=1 -> OverflowError
value=65535 bit_length=16 sized=2 -> ok
value=65536 bit_length=17 sized=2 -> OverflowError
So it fails at every octet boundary, not at one unlucky width: any value needing 8n + 1 bits or more is sized at n octets. 255 works and 256 does not; 65535 works and 65536 does not.
The correct expression gives sized=2 for 256 and sized=3 for 65536, both of which pack.
Reachability
This is the repair path taken when a field's length is still the -1 placeholder at pack time — the branch guarded by if self._length < 0: at numbers.py:197. It is therefore reached only when a width was never resolved, which makes it narrower than #591 but not unreachable.
Notes
pre_process's width repair sizes a value with floor division dressed up as a ceiling, so any value just past an octet boundary is sized one octet too small andto_bytesraisesOverflowError.Mechanism
pcapkit/corekit/fields/numbers.py:198:math.ceilon anintis a no-op —//has already floored it — so the expression isvalue.bit_length() // 8. The intent was evidentlymath.ceil(value.bit_length() / 8).Measured
On
origin/main(fa6d18e31), CPython 3.14.7:So it fails at every octet boundary, not at one unlucky width: any value needing
8n + 1bits or more is sized atnoctets.255works and256does not;65535works and65536does not.The correct expression gives
sized=2for 256 andsized=3for 65536, both of which pack.Reachability
This is the repair path taken when a field's length is still the
-1placeholder at pack time — the branch guarded byif self._length < 0:atnumbers.py:197. It is therefore reached only when a width was never resolved, which makes it narrower than #591 but not unreachable.Notes
/for//— but it changes the packed width of any value past a boundary on that path, so it wants a test per boundary rather than a single case.