ErrLookup › Background articles › "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass
"Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass
Invalid argument value errors, the family behind messages like 'must be a positive integer', 'Invalid value for', 'Unsupported network', and 'Version doesn't exist!', fire when an argument you pass falls outside what a library accepts: not in its closed set of names, not a positive finite number, not the right shape. Developers meet them as ArgumentError, ValueError, or IllegalArgumentException when unvalidated config, env vars, or request parameters reach an API, when a token is misspelled or wrongly cased, or when a computed value degenerates to zero, negative, NaN, or Infinity. The throw is deliberate and early, before side effects, and the fix almost always belongs in the calling code, not the library.
Distilled from 96 documented records across 35 repositories.
Background
Every error in this family comes from an explicit validation at a library's public boundary, not from an operation that went wrong halfway through. The records consistently show the check running before any side effect: the airi screen-capture handler validates its timeout before the setSource mutex is acquired, the Chroma JavaScript client rejects a bad Knn limit before any network request, turso's retryFetch validates its attempts count when the wrapper is constructed rather than per request, and tailscale's firewall helper returns 'unsupported network' before touching iptables. The guards exist because proceeding would produce silent nonsense instead of a clean error: kaminari rejects negative padding because it would become a negative SQL OFFSET, matplotlib's Sankey refuses a radius greater than its gap because the paths would overlap, the integer tick locator rejects a non-positive step because every later operation divides by it, and tailscale's distsign refuses to sign a zero-length package because the signature could never be reproduced. From the caller's side the experience is uniform: an immediate, synchronous throw with no partial state to clean up, and the offending value usually visible in the message.
What varies is the kind of constraint being enforced. The largest group is closed vocabularies: Faraday's request_timeout accepts exactly :read, :write, or :open; Guard's pause accepts :paused, :unpaused, or :toggle; pnpm's runtime set is node, deno, bun; webmock accepts four notation symbols; tailscale accepts only the strings udp4 and udp6; zed enumerates prediction providers; yt-dlp validates youtube:lang against a hard-coded case-sensitive list; carrierwave looks up version names declared in the uploader. A second group enforces numeric domains: strictly positive (matplotlib's linthresh and tick step, Intervention's color limit, hadoop's leastPowerOfTwo), positive and finite (airi's timeout, deno's escapeCodeTimeout), or an integer greater than zero (Chroma's Knn limit and Rrf k, turso's retry attempts). A third group checks shape: matplotlib's button layout must be None, 'vertical', 'horizontal', or a tuple of two plain ints, and relative inset sizes require a 4-tuple or Bbox anchor. A fourth group checks arguments against each other: matplotlib's radius against gap, hadoop's maxSize against step, and rustfs' requirement that the version slice length equal the caller-recorded num_versions.
The error class and message quality are library-specific. Ruby libraries raise ArgumentError (carrierwave, kaminari, faraday, webmock, guard, dotenv); Python and JavaScript raise ValueError or TypeError (matplotlib widgets, Chroma's rank factories); Java throws IllegalArgumentException or HadoopIllegalArgumentException (hibernate, hadoop); PHP's Intervention throws InvalidArgumentException; Rust surfaces either a CLI parse failure (zed) or an io::Error with ErrorKind::InvalidInput (rustfs). Some messages interpolate the offending value, such as dotenv's inspect output, deno's 'Received ...', rustfs' expected/got pair, or tailscale's 'got %d'; others enumerate the accepted set, like zed's provider list, yt-dlp's supported language codes, pnpm's runtime names, or webmock's notation list; the most useful do both.
Coercion policy differs sharply between libraries and is worth checking for the exact API in hand. Kaminari coerces with to_i before checking sign, so the string '-5' fails exactly like -5; dotenv deliberately does no coercion, so the string 'true' is rejected as an overwrite flag; Chroma requires a real integer, so the string '60' fails Number.isInteger; yt-dlp matches language codes exactly, case included. Even the messages can mislead: the Deno polyfill reports the default 500 rather than the value actually passed, zed's provider error omits the accepted 'baseten' token, and turso's 'finite integer' wording lets 2.5 through. Where libraries disagree like this, the details are library-specific; the shared shape of the failure, an argument rejected at the boundary before anything happens, is what makes this one family.
Common causes
- Unvalidated external input forwarded verbatim. Config values, env vars, request parameters, or CLI arguments passed straight into the library: params[:padding] into Kaminari, Number(process.env.KNN_LIMIT) into Chroma's Knn, a YAML string into dotenv's overwrite flag, a user-supplied name into pnpm runtime set. The library's guard is the first validation the value ever meets.
- Typo, wrong case, or wrong token in a closed set. :thumbnail where the uploader declares :thumb, 'EN' or 'pt-BR' against yt-dlp's case-sensitive youtube:lang list, :pause instead of :paused in Guard, 'nodejs' instead of 'node' for pnpm, 'UDP4' instead of 'udp4' in tailscale, the string 'flat' instead of the symbol :flat for webmock.
- Computed value degenerates to 0, negative, NaN, or Infinity. Timeouts from subtractions that drift to zero or below (airi), linthresh from min(abs(data)) when the data contains an exact 0 (matplotlib), a color limit from count($palette) - 1 with a one-color palette (Intervention), retry attempts from userProvided - 1 (turso), NaN from parseInt on an unset variable.
- Sentinel value where the API wants omission or a real value. Infinity passed for 'no timeout' or 'retry forever' (airi, turso), 0 meaning 'auto' or 'unlimited' fed to reduceColors (Intervention), -1 as a 'no padding' sentinel (kaminari), {} as an 'any error' spec in assert.throws (Deno). Most APIs want the argument omitted or a bounded real value instead.
- String instead of symbol, number, or boolean. 'read' instead of :read for Faraday, '500' as a string escapeCodeTimeout for Deno, 'true' instead of true for dotenv, '60' as a string k for Chroma's Rrf. Whether this fails at all is library-specific: Kaminari coerces with to_i, dotenv and Chroma reject.
- Wrong shape, arity, or structure. A 2-tuple point anchor under percent-sized inset_axes (matplotlib), layout=2 or a one-element or float-containing tuple for button widgets, stray segments in zed's teacher:backend strings, nested version names passed in the wrong order for carrierwave.
- Arguments that must agree do not. radius greater than gap in matplotlib's Sankey, maxSize/step breaching the interval ceiling in hadoop's FileDistribution, or a version slice whose length differs from a num_versions recorded before concurrent writes changed it (rustfs).
What usually fixes it
- [object Object]
- [object Object]
- [object Object]
- [object Object]
- [object Object]
- [object Object]
Go deeper
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Documented occurrences
- timeout must be a positive finite number (moeru-ai/airi)
- Version #{version} doesn't exist! (carrierwaveuploader/carrierwave)
- unknown provider `{provider}`. Valid options: mercury, zeta1, zeta2, zeta2:<version>, teacher, teacher:<backend>, teacher-jumps, teacher-jumps:<backend>, teacher-non-batching, teacher-jumps-non-batching, repair For zeta2, you can optionally specify a version like `zeta2:ordered` or `zeta2:V0113_Ordered`. For teacher providers, you can specify a backend like `teacher:sonnet46`, `teacher-jumps:sonnet46`, `teacher-jumps-non-batching:sonnet46`, or `teacher:gpt52`. Available zeta versions: {} (zed-industries/zed)
- InvalidInput: number of versions mismatch, expected {}, got {} (rustfs/rustfs)
- ERR_INVALID_ARG_VALUE: The property 'input.escapeCodeTimeout' is invalid. Received ${this.escapeCodeTimeout} (denoland/deno)
- Expected :read, :write, :open. Got #{type.inspect} :( (lostisland/faraday)
- n = {n} <= 0 (apache/hadoop)
- layout must be None, 'vertical', 'horizontal', or a (rows, cols) tuple; got {layout!r} (matplotlib/matplotlib)
- padding must not be negative (kaminari/kaminari)
- 'radius' is greater than 'gap', which is not allowed because it would cause the paths to overlap (matplotlib/matplotlib)
- Quantization limit must be greater than 0 (Intervention/image)
- Too many distribution intervals {numIntervals} (apache/hadoop)
- Invalid notation. Must be one of: [:flat, :dot, :subscript, :flat_array]. (bblimke/webmock)
- unknown teacher backend or zeta format `{arg}` (zed-industries/zed)
- Unsupported language code: {preferred_lang}. Supported language codes (case-sensitive): {join_nonempty(*self._SUPPORTED_LANG_CODES, delim=", ")}. (yt-dlp/yt-dlp)
- invalid mode: #{expected.inspect} (guard/guard)
- Knn limit must be a positive integer (chroma-core/chroma)
- 'linthresh' must be positive (matplotlib/matplotlib)
- retryFetch: attempts must be a finite integer >= 1, got ${attempts} (tursodatabase/turso)
- Rrf k must be a positive integer (chroma-core/chroma)
…and 76 more across the corpus — use search.
Honest provenance: generated on 2026-08-23 from AI-assisted analysis of the linked records. See how records are made.