pydantic/monty · error · napi::Error

{name} 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.

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)

Solutions

  1. Replace NaN/Infinity with a finite number before passing the option
  2. Check `Number.isFinite(value)` on every numeric option before creating a pool/session
  3. If 'unlimited' is intended, omit the field and use the library default instead of Infinity
  4. 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

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


AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13). Data as JSON: /api/errors/1e6295c3aa3ab075. Report an issue: GitHub.