pydantic/monty · error · napi::Error
{name} must be a safe integer (<= 9007199254740991)
Error message
{name} must be a safe integer (<= 9007199254740991) What it means
napi-rs `Error` (Status::InvalidArg) thrown by `js_number_to_u64` when a numeric option exceeds `Number.MAX_SAFE_INTEGER` (2^53 - 1 = 9007199254740991). Beyond that, doubles cannot represent every integer exactly, so the helper refuses to cast to `u64`.
Source
Thrown at crates/monty-js/src/limits.rs:110
/// 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)
Solutions
- Use a value <= Number.MAX_SAFE_INTEGER, or express the limit in smaller units (MiB)
- If a larger value is genuinely needed, use BigInt and convert with an explicit range check first
- Omit the option to use the library default
Example fix
// before
const maxMemory = BigInt(opts.maxMemoryBytes);
await Monty.create({ maxMemory: Number(maxMemory) }) // precision loss / rejection
// after
const maxMemory = Number(opts.maxMemoryBytes); // caller guarantees <= MAX_SAFE_INTEGER
await Monty.create({ maxMemory }) Defensive patterns
Strategy: validation
Validate before calling
const MAX_SAFE = 2 ** 53 - 1;
function assertSafeInteger(name, v) {
if (typeof v === 'number' && v > MAX_SAFE) throw new RangeError(`${name} must be <= ${MAX_SAFE}`);
return v;
} Type guard
const isSafeInteger = (v) => Number.isInteger(v) && Math.abs(v) <= Number.MAX_SAFE_INTEGER;
Try / catch
try {
await Monty.create({ maxMemory: rawBytes });
} catch (e) {
if (/safe integer/.test(e?.message ?? '')) {
// express the limit in smaller units or clamp to MAX_SAFE_INTEGER
} else throw e;
} Prevention
- Express very large limits in MiB/GiB rather than raw bytes
- Avoid Number() on BigInt values without a range check
- Remember JS doubles lose integer precision above 2^53-1
When it happens
Trigger: Passing a limit greater than 9007199254740991, e.g. a byte-count above ~9 PB (`maxMemory: 10 ** 16`) or any value from BigInt arithmetic that lost precision via `Number(...)`.
Common situations: Configuring sizes in bytes at petabyte scale; converting from BigInt with `Number()` instead of using an exact path; accidental exponent typos (`1e16`).
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- {name} must be a finite number
- {name} must be non-negative
- {name} must be an integer
- Cannot convert JS Symbol to Monty value
- MontyFileHandle position exceeds JavaScript's maximum safe i
AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13).
Data as JSON: /api/errors/c203be4ea541ddb6.
Report an issue: GitHub.