pydantic/monty · error · napi::Error
must be a finite number
Error message
{name} must be a finite number What it means
napi-rs `Error` (Status::InvalidArg) thrown by `js_number_to_u64` in monty-js when a numeric option (e.g. a resource-limit field) is not a finite JavaScript number (NaN, Infinity, -Infinity). The helper validates f64 inputs coming over the napi boundary before they are narrowed to u64. This is the first guard in an ordered chain of checks.
Solutions
- Replace NaN/Infinity with a finite number before passing the option
- Check `Number.isFinite(value)` on every numeric option before creating a pool/session
- If 'unlimited' is intended, omit the field and use the library default instead of Infinity
- Sanitize values parsed from JSON/env — `JSON.parse` cannot carry Infinity, so coercion code likely introduced it
Example fix
// before
await Monty.create({ maxMemory: 1024 * 1024 * 1024 * 1024 * 1024 }) // Infinity
// after
const maxMemory = Number.isFinite(opts.maxMemory) ? opts.maxMemory : 100 * 1024 * 1024;
await Monty.create({ maxMemory }) Defensive patterns
Strategy: validation
Validate before calling
function assertFiniteU64Option(name, v) {
if (!Number.isFinite(v)) throw new TypeError(`${name} must be a finite number`);
return v;
} Type guard
const isFiniteNumber = (v) => typeof v === 'number' && Number.isFinite(v);
Try / catch
try {
await Monty.create({ maxMemory: rawMaxMemory });
} catch (e) {
if (e instanceof napi.Status && /must be a finite number/.test(e.message)) {
// fall back to library default
} else throw e;
} Prevention
- Validate all numeric options with Number.isFinite before calls
- Never use Infinity as an 'unlimited' sentinel — omit the field instead
- Sanitize values coerced from env vars or JSON config
When it happens
Trigger: Calling any monty-js API that sets a numeric limit with `NaN`, `Infinity`, or `-Infinity`, e.g. `Monty.create({ maxMemory: Infinity })` or `pool.checkout({ requestTimeout: NaN })`, when that value flows into `js_number_to_usize` -> `js_number_to_u64`.
Common situations: Computing a limit from an arithmetic expression that overflows or divides by zero; loading limits from config where a JSON parser or env-var coercion produced NaN/Infinity; spreading `Infinity` as an 'unlimited' sentinel.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- must be a safe integer (<= 9007199254740991)
- must be an integer
- must be non-negative
- Cannot convert JS Symbol to Monty value
- MontyFileHandle position exceeds JavaScript's maximum safe…
AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13).
Data as JSON: /api/errors/1e6295c3aa3ab075.
Report an issue: GitHub.
Appendix: source
Thrown at crates/monty-js/src/limits.rs:104
Status::InvalidArg,
format!("{name} must fit in Rust usize on this platform"),
)
})
}
/// Converts a JavaScript `number` used for a size/count limit into `u64`.
///
/// JavaScript numbers are IEEE-754 doubles, so integers above `2^53 - 1`
/// cannot be represented exactly. Rejecting values outside the safe integer
/// range avoids silently rounding resource limits at the napi boundary.
///
/// Returns `Err` for non-finite, negative, fractional, or out-of-range inputs.
/// This helper does not panic.
pub(crate) fn js_number_to_u64(value: f64, name: &str) -> Result<u64> {
const JS_MAX_SAFE_INTEGER: u64 = (1_u64 << 53) - 1;
match value {
v if !v.is_finite() => Err(Error::new(
Status::InvalidArg,
format!("{name} must be a finite number"),
)),
v if v < 0.0 => Err(Error::new(Status::InvalidArg, format!("{name} must be non-negative"))),
v if v.fract() != 0.0 => Err(Error::new(Status::InvalidArg, format!("{name} must be an integer"))),
v if v > JS_MAX_SAFE_INTEGER as f64 => Err(Error::new(
Status::InvalidArg,
format!("{name} must be a safe integer (<= {JS_MAX_SAFE_INTEGER})"),
)),
v => {
#[expect(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
let value = v as u64;
Ok(value)
}
}
}
View on GitHub (pinned to adc986b362)