apple/pkl · error · VmException

cannotConvertLargeFloat|cannotConvertNonFiniteFloat (conditi

Error message

cannotConvertLargeFloat|cannotConvertNonFiniteFloat (conditional)

What it means

`VmSafeMath.toInt` truncates a Double toward zero with `RoundingMode.DOWN` and converts to long. It fails when the Float is too large to fit in a Long (cannotConvertLargeFloat) or is NaN/Infinity (cannotConvertNonFiniteFloat), both surfaced as ArithmeticException from MathUtils.roundToLong.

Source

Thrown at pkl-core/src/main/java/org/pkl/core/runtime/VmSafeMath.java:122

      CompilerDirectives.transferToInterpreter();
      throw new VmExceptionBuilder().evalError("intValueTooLarge", x).build();
    }
  }

  public static double truncate(double x) {
    if (x < 0) {
      return StrictMath.ceil(x);
    }
    return StrictMath.floor(x);
  }

  @TruffleBoundary
  public static long toInt(double x, Node sourceNode) {
    try {
      return MathUtils.roundToLong(x, RoundingMode.DOWN);
    } catch (ArithmeticException e) {
      CompilerDirectives.transferToInterpreter();
      throw new VmExceptionBuilder()
          .withLocation(sourceNode)
          .evalError(
              Double.isFinite(x) ? "cannotConvertLargeFloat" : "cannotConvertNonFiniteFloat",
              new ProgramValue("Float", x))
          .build();
    }
  }

  public static long increment(long x) {
    try {
      return Math.incrementExact(x);
    } catch (ArithmeticException e) {
      CompilerDirectives.transferToInterpreter();
      throw intOverflow();
    }
  }

  public static long decrement(long x) {

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Validate the Float is finite and within Long range before converting: `x.isFinite && x >= -9.223372036854776E18 && x < 9.223372036854776E18`.
  2. Fix upstream arithmetic that yields NaN/Infinity (guard division denominators, clamp intermediate results).
  3. Keep the value as a Float if integer precision is not required.
  4. Clamp or scale the value so it fits in the integer range.

Example fix

// before
val n = (1.0e300 / 1.0e-300).toInt()
// after
val raw = 1.0e300 / 1.0e-300
val n = if (raw.isFinite && raw < 9.223372036854776E18) raw.toInt() else Long.MAX_VALUE
Defensive patterns

Strategy: validation

Validate before calling

function canConvertToInt(x) { return Number.isFinite(x) && x > -9.223372036854776e18 && x < 9.223372036854776e18; }

Type guard

function isConvertibleFloat(x) { return typeof x === 'number' && Number.isFinite(x) && Math.abs(x) < 9.223372036854776e18; }

Try / catch

try { x.toInt() } catch (e) { /* Float too large or non-finite; handle/clamp */ }

Prevention

When it happens

Trigger: Calling `Float.toInt()` (or stdlib functions that require an Int from a Float) where the Double is >= 2^63, <= -2^63, NaN, +Infinity or -Infinity.

Common situations: Division producing Infinity (divide by zero on floats), NaN from invalid math (sqrt of negative), or huge computed magnitudes from exponentiation.

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


AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08). Data as JSON: /api/errors/89969491935862bb. Report an issue: GitHub.