ErrLookupBackground 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

What usually fixes it

Go deeper

Documented occurrences

…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.