{"record":{"id":"a76b73a1adde20b1","repo":"apple/pkl","slug":"cannot-convert-pkl-duration-duration-to-iso-8","errorCode":null,"errorMessage":"Cannot convert Pkl duration `${duration}` to ISO 8601 duration.","messagePattern":"Cannot convert Pkl duration `(.+?)` to ISO 8601 duration\\.","errorType":"exception","errorClass":"ArithmeticException","httpStatus":null,"severity":"error","filePath":"pkl-core/src/main/java/org/pkl/core/util/DurationUtils.java","lineNumber":33,"sourceCode":" */\npackage org.pkl.core.util;\n\nimport org.pkl.core.DurationUnit;\n\npublic final class DurationUtils {\n  private DurationUtils() {}\n\n  public static String toPklString(double value, DurationUnit unit) {\n    return MathUtils.isMathematicalInteger(value) ? (long) value + \".\" + unit : value + \".\" + unit;\n  }\n\n  // see: https://standards.calconnect.org/csd/cc-18011.html#toc32\n  public static String toIsoString(double value, DurationUnit unit) {\n    // different rounding behavior from `VmDuration.convertValueTo()`\n    var totalSeconds = value * (unit.getNanos() / 1e9);\n\n    if (!Double.isFinite(totalSeconds)) {\n      throw new ArithmeticException(\n          \"Cannot convert Pkl duration `\"\n              + DurationUtils.toPklString(value, unit)\n              + \"` to ISO 8601 duration.\");\n    }\n\n    var absoluteSeconds = Math.abs(totalSeconds);\n    var hours = (long) (absoluteSeconds / 3600);\n    var minutes = (long) (absoluteSeconds / 60) % 60;\n    var seconds = (long) (absoluteSeconds % 60);\n    var nanos =\n        (long) (absoluteSeconds * 1_000_000_000 - Math.floor(absoluteSeconds) * 1_000_000_000);\n\n    var builder = new StringBuilder();\n\n    if (totalSeconds < 0.0) {\n      builder.append('-');\n    }\n","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-core/src/main/java/org/pkl/core/util/DurationUtils.java#L15-L51","documentation":"DurationUtils.toIsoString converts a Pkl duration (value + unit) to an ISO 8601 duration string. If the computed total number of seconds is not finite (NaN or Infinity, e.g. from overflow of very large values), the conversion is impossible and an ArithmeticException is thrown.","triggerScenarios":"Calling toIsoString with a value so large that value * (unit.getNanos()/1e9) overflows to Double.POSITIVE_INFINITY/NEGATIVE_INFINITY, or a value/unit combination yielding NaN.","commonSituations":"Passing absurdly large duration values (e.g. huge hours/day counts in Float units); a computation upstream produced Infinity (division by zero duration) before conversion; parsing user input without bounds.","solutions":["Check the duration value is finite and within a sane range before calling toIsoString.","Fix the upstream computation that produced NaN/Infinity.","Clamp or split extremely large durations into finite second totals before conversion."],"exampleFix":"// before\nvar iso = DurationUtils.toIsoString(hugeValue, DurationUnit.HOURS);\n// after\nif (Double.isFinite(hugeValue) && hugeValue < 1e15) {\n  var iso = DurationUtils.toIsoString(hugeValue, DurationUnit.HOURS);\n}","handlingStrategy":"validation","validationCode":"if (!Double.isFinite(value)) throw new IllegalArgumentException(\"duration value must be finite\");\n","typeGuard":null,"tryCatchPattern":"try { return DurationUtils.toIsoString(value, unit); } catch (ArithmeticException e) { log.warn(\"non-finite duration: {}\", e.getMessage()); return null; }\n","preventionTips":["Bound-check duration values before conversion.","Fix upstream math that can divide by zero or overflow.","Test conversions with extreme values."],"tags":["pkl","duration","iso8601","arithmetic"],"backgroundTag":"invalid-duration-format","analyzedSha":"f3efcbfc9b60d30053b0536d664948d7aa1b8673","analyzedAt":"2026-09-08T13:10:45.570Z","contentChangedAt":"2026-09-08T13:10:45.570Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}