apple/pkl · error · VmException

divisionByZero

divisionByZero

Error message

divisionByZero

What it means

Pkl's truncating integer division (`~/`) throws `divisionByZero` when the divisor is 0. VmSafeMath.truncatingDivide performs an explicit zero check (rather than relying on catching ArithmeticException, which is unreliable in GraalVM AOT mode) and raises this eval error.

Solutions

  1. Guard the divisor: only divide when `y != 0`, else use a fallback value.
  2. Fix the upstream value so the denominator is nonzero (correct the config or default).
  3. For percentages/averages, special-case zero totals explicitly.
  4. Use a null/absent marker for undefined ratios instead of dividing by a zero placeholder.

Example fix

// before
pct = used * 100 ~/ total  // total may be 0

// after
pct = if (total == 0) 0 else used * 100 ~/ total
Defensive patterns

Strategy: validation

Validate before calling

// Pkl
safeDiv = (x: Int, y: Int) -> if (y == 0) 0 else x ~/ y

Type guard

function isNonZeroDivisor(y: Int): Boolean = y != 0

Prevention

When it happens

Trigger: Evaluating the `~/` Int division operator with a right-hand side that evaluates to 0 — commonly a computed denominator from config, a default `0` property, or an empty-collection-derived count.

Common situations: Computing ratios/averages where a totals property is 0 (e.g. percent = part * 100 ~/ total with total = 0); divisor read from external config/env that defaulted to 0.

Related errors


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

Appendix: source

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

  public static long multiply(long x, long y) {
    try {
      return StrictMath.multiplyExact(x, y);
    } catch (ArithmeticException e) {
      CompilerDirectives.transferToInterpreter();
      throw intOverflow();
    }
  }

  public static double multiply(double x, double y) {
    return x * y;
  }

  public static long truncatingDivide(long x, long y) {
    // for some reason, detecting division by zero by catching ArithmeticException
    // does not work correctly in AOT mode, so let's do an explicit check for now
    if (y == 0) {
      CompilerDirectives.transferToInterpreter();
      throw divisionByZero();
    }

    var result = x / y;

    if ((x & y & result)
        < 0) { // use same check as com.oracle.truffle.sl.nodes.expression.SLDivNode
      CompilerDirectives.transferToInterpreter();
      assert x == Long.MIN_VALUE && y == -1;
      throw intOverflow();
    }

    return result;
  }

  public static long remainder(long x, long y) {
    return x % y;
  }

View on GitHub (pinned to f3efcbfc9b)