ErrLookup › Background articles › "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries
"value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries
"value is out of range", "must be between 0 and 1", "value must be >=0", "must not be negative" and similar messages all come from the same family of range-validation guards: a library rejects a numeric value that falls outside the bounds its parameter or bit-field can represent. You meet them when passing percentages instead of fractions, raw channel values instead of normalized ones, unit-suffixed or negative numbers, or values that overflow a fixed-width field. This article explains why these bounds exist, how they vary across libraries, and how to clamp, convert units, and validate before the call.
Distilled from 100 documented records across 42 repositories.
Background
Unlike syntax errors or connection failures, this family is produced deliberately: a validation guard inside a library's write path, setter, or packing routine compares an incoming value against an explicit allowed range and throws or returns an error when it falls outside. The ranges are rarely arbitrary — they are dictated by the layer below. Intervention/image's normalized color channels must be 0..1 because the value is a fraction of the channel's full range; its stroke width is capped at 10 and AvifEncoder quality at 0..100 because those are the contracts of the underlying typography and codec layers; cilium's session affinity timeout must fit the 24 bits left in an lb4_service BPF map word after the LB algorithm takes the low 8 bits; Hadoop's LongBitFormat.combine() rejects values below MIN or above 2^LENGTH-1 because a bit field simply has no room for anything else; Deno's KvU64 refuses negative bigints because u64 counters are add-only by design with no wrap-around. When a bound looks odd, it is usually an encoding constraint (bit width, file format, wire protocol) rather than a style preference.
From the caller's side these errors usually mean a unit or representation mismatch, not a broken library. The most common pattern is scale confusion: calling Red::fromNormalized(128) instead of 128/255, constructing ProgressEvent(progress=50) with a percentage where a 0.0-1.0 fraction is required, passing PhortuneCurrency a value whose unit is cents when the bound string means dollars, or handing Phabricator a ngram threshold of 5 meaning 5 percent when it expects 0.05. A second pattern is decoration the parser will not accept: onetimesecret rejects border_radius '12px' or '12.5' because the field accepts only preset names or bare digit strings within 0..64, and siyuan's sort-mode attribute accepts only integer strings '0' through '14' or an empty string to clear. A third is sentinel leakage: -1 used as a 'not selected' marker reaching PhpSpreadsheet's setFirstSheetIndex or Hadoop's bit-field packing.
The exception type varies by library, so catching the right class matters. The same codebase can use different types: matplotlib's internal validators raise RuntimeError (which its own ndivs wrapper catches and re-raises as a ValueError), while its margin setter raises ValueError; Intervention/image uses InvalidArgumentException, including for what is really a TypeError converted from a null or string sneaking into a strictly-typed normalized array; Deno uses RangeError; Hadoop uses IllegalArgumentException; and gin-vue-admin returns a plain Go error whose text appends the violated rule (e.g. ',max=10') so the caller can see which comparison failed. Some guards exist to re-check what a wire layer should already have enforced — koala73/worldmonitor's registerWebhook re-validates alertThreshold 0..100 because direct handler calls bypass buf.validate.
Bounds also differ across libraries even for similar concepts, so never assume a range transfers. A 0..100 percent scale (AvifEncoder quality) coexists in the same family with a 0..1 ratio scale (normalized colors, progress events, Phabricator's ngram threshold) and with matplotlib's margin bound of strictly greater than -0.5 — a bound with a real geometric reason (1 + 2m collapses to zero width at exactly -0.5). Relative caps can be huge but finite: Phabricator caps relative TTLs at 31,536,000 seconds (365 days) to stop callers silently creating effectively-permanent files, and points users at absolute timestamps instead. Several records note inclusive-vs-exclusive subtleties: PhortuneCurrency's bounds are inclusive (a value equal to the maximum passes), matplotlib's ndivs accepts 0 while the margin bound is strictly exclusive, and PhpSpreadsheet's 'must be a positive integer' message actually accepts 0 — the message overstates the code.
Common causes
- Unit or scale confusion (percent vs fraction, raw vs normalized). Passing a 0-100 percentage where a 0-1 fraction is expected (ProgressEvent with 50, a 5 where an ngram threshold of 0.05 is needed) or a raw channel value where a normalized one is expected (Red::fromNormalized(128) instead of 128/255). The bound in the error tells you which scale the API actually uses.
- Values beyond what a fixed-width field or format can encode. Bit-packed or binary-encoded fields reject anything that does not fit: cilium's 24-bit affinity timeout above 16777215, Hadoop's LongBitFormat fields outside [MIN, 2^LENGTH-1], k6's int32-cast element count. These bounds are hard encoding constraints, not tunable limits.
- Negative values or sentinel leakage (-1, null). -1 'not set' sentinels, computed deltas that go negative, or nulls from failed lookups reaching strictly-typed APIs: setFirstSheetIndex(-1), Deno KvU64 sum with a negative delta, null entries in an Intervention/image normalized array. Negative checks and 'positive integer' messages usually still accept 0.
- Decorated or wrongly-typed input where bare values are required. Unit suffixes, decimals, or strings where digit strings or numbers are required: border_radius '12px' or '12.5' (only bare 0..64 or presets), siyuan sort mode 'alpha' or '15' (only '0'..'14' or ''), a float 2.0 where matplotlib wants an int. HTTP form fields often reduce values to strings, so decoration fails server-side.
- Unclamped computed or user-supplied input. Values derived from other data overshoot the range: a stroke width computed from image width exceeding 10, page-setup scale math going negative, text rotation 180/270 from CSS degrees, margin config below -0.5. Validate or clamp at the input boundary before the library call.
- Bypassing the wire-layer validation path. Direct handler calls in tests, jobs, or alternate transports skip schema validation such as buf.validate, so a second in-handler range check (alertThreshold 0..100) fires instead — with a different error shape than the wire layer's. Route requests through the same validation path or validate yourself.
- Extreme values from corrupted data or upstream bugs. Occasionally the value itself is the symptom: k6's out-of-int32 count implies a corrupted JS evaluation result, ory/hydra's out-of-int64 timestamp usually means millisecond-vs-second confusion or malformed token data. Treat these as data-integrity signals, not API usage bugs.
What usually fixes it
- Convert units and scales at the boundary: divide by the channel max or total before passing (128/255, done/total, 5% -> 0.05), convert durations to seconds, and keep one documented conversion point so the API's scale is explicit at every call site.
- Clamp or validate before the call: max(0, min(high, value)) for quality, stroke width, rotation, and scale; Math.min/Math.max for option bounds; reject rather than clamp where out-of-range means corrupted data (k6 counts, hydra timestamps).
- Match the expected representation exactly: send bare digit strings or JSON numbers where decoration is rejected, integers where floats fail strict types, default-out nulls before building typed arrays, and map 'none' sentinels (-1, null) to real defaults like 0.
- Read the bound out of the error and honor its inclusivity: messages often name the exact cap (OpenCLI prints the max, PhortuneCurrency formats the minimum as '$5.00 USD', gin-vue-admin appends the rule). Check whether the endpoints are inclusive (Phortune bounds) or exclusive (matplotlib margins, ngram threshold) before picking the nearest legal value.
- Catch the exception type the library actually raises — which is library-specific and sometimes inconsistent within one library (matplotlib uses RuntimeError in internal validators but its wrapper re-raises ValueError; Intervention/image converts TypeErrors into InvalidArgumentException) — and convert it into a field-level validation message instead of letting it surface as a 500.
- Respect design decisions encoded in the bounds: 'full' corners are deliberately excluded from onetimesecret branding, Deno's u64 counters never wrap negative, Phabricator caps relative TTLs at 365 days and expects absolute timestamps for longer, and Hadoop's fields should be widened rather than masked. Do not work around these; use the alternative API the library provides (fit-to-page instead of computed scale, read+set instead of u64 sum, ttl.absolute instead of a longer relative TTL).
Go deeper
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Documented occurrences
- Unexpected response format (onetimesecret/onetimesecret)
- Illagal value: {NAME} = {value} < MIN = {MIN} (apache/hadoop)
- Value must be >=0; got {s} (matplotlib/matplotlib)
- Minimum allowed amount is %s. (phacility/phabricator)
- Normalized color channel value must be between 0 to 1 (Intervention/image)
- Illagal value: ${NAME} = ${value} < MIN = ${MIN} (apache/hadoop)
- Normalized color value must be in range 0 to 1 (Intervention/image)
- session affinity timeout %d does not fit into 24 bits (is larger than 16777215) (cilium/cilium)
- alertThreshold must be between 0 and 100 (koala73/worldmonitor)
- Threshold must be greater than 0.0 and less than 1.0. (phacility/phabricator)
- Scale must not be negative (PHPOffice/PhpSpreadsheet)
- Normalized color value must be in range 0 to 1 (Intervention/image)
- Text rotation {$angleInDegrees} should be a value between -90 and 90. (PHPOffice/PhpSpreadsheet)
- invalid-idle-time-limit-value: Invalid idleTimeLimit (RocketChat/Rocket.Chat)
- %d is not in cron range(0-23) (Netflix/chaosmonkey)
- Unable to parse RGB color from input "{input}" (Intervention/image)
- Maximum allowed amount is %s. (phacility/phabricator)
- First sheet index must be a positive integer. (PHPOffice/PhpSpreadsheet)
- Relative TTL must not be more than "%s" seconds, but TTL "%s" was specified. (phacility/phabricator)
- Must retain at least 1 container (basecamp/kamal)
…and 80 more across the corpus — use search.
Honest provenance: generated on 2026-09-03 from AI-assisted analysis of the linked records. See how records are made.