{"record":{"id":"fb1e0d1a2dab8f27","repo":"google/zx","slug":"invalid-duration-d","errorCode":null,"errorMessage":"Invalid duration: \"${d}\".","messagePattern":"Invalid duration: \"(.+?)\"\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/util.ts","lineNumber":106,"sourceCode":"      .replace(/\\v/g, '\\\\v')\n      .replace(/\\0/g, '\\\\0') +\n    `'`\n  )\n}\n\nexport function quotePowerShell(arg: string): string {\n  if (arg === '') return `''`\n  if (/^[\\w/.\\-@:=,+%]+$/.test(arg)) return arg\n\n  return `'` + arg.replace(/'/g, \"''\") + `'`\n}\n\nexport type Duration =\n  number | `${number}` | `${number}m` | `${number}s` | `${number}ms`\n\nexport function parseDuration(d: Duration) {\n  if (typeof d === 'number') {\n    if (isNaN(d) || d < 0) throw new Error(`Invalid duration: \"${d}\".`)\n    return d\n  }\n  const [m, v, u] = d.match(/^(\\d+)(m?s?)$/) || []\n  if (!m) throw new Error(`Unknown duration: \"${d}\".`)\n\n  return +v * ({ s: 1000, ms: 1, m: 60_000 }[u] || 1)\n}\n\nexport const once = <T extends (...args: any[]) => any>(fn: T) => {\n  let called = false\n  let result: ReturnType<T>\n\n  return (...args: Parameters<T>): ReturnType<T> =>\n    called ? result : ((called = true), (result = fn(...args)))\n}\n\nexport const proxyOverride = <T extends object>(\n  origin: T,","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/google/zx/blob/00a2c484e219c2e84bfc3a199febf7fbce2cfbf4/src/util.ts#L88-L124","documentation":"Thrown by parseDuration() when the input is a number that is NaN or negative. Durations must be a non-negative finite number, or a string matching /^(\\d+)(m?s?)$/ (e.g. '100ms', '2s', '3m'). parseDuration backs sleep(), retry() delays, expBackoff(), and $.timeout, so any of those surfaces can surface this error. Note: this is thrown as a plain `new Error`, not a zx Fail instance.","triggerScenarios":"`sleep(-1)`; `$.timeout = -100`; `retry(3, NaN, fn)`; `parseDuration(Number('abc'))` (NaN); `expBackoff(-5)`; a computed duration that underflows to negative.","commonSituations":"Subtracting timestamps that yield a negative delta; parseFloat on malformed input producing NaN; config that uses -1 to mean 'disabled' fed directly into zx; overflow/underflow in delay math.","solutions":["Validate before passing: `if (Number.isFinite(d) && d >= 0) ...`.","Clamp to a safe minimum: `Math.max(0, d)`.","Prefer the explicit string form ('100ms', '2s') for readability and to avoid NaN.","Guard config-driven values and treat -1/NaN as 'no timeout'."],"exampleFix":"// before\n$.timeout = rawTimeout   // rawTimeout may be -1 or NaN\n// after\n$.timeout = Number.isFinite(rawTimeout) && rawTimeout >= 0 ? rawTimeout : undefined","handlingStrategy":"validation","validationCode":"import { parseDuration } from 'zx'\n\nfunction safeDuration(d: number | string | undefined): number | undefined {\n  if (d == null) return undefined\n  const n = typeof d === 'number' ? d : Number(d)\n  if (!Number.isFinite(n) || n < 0) return undefined // treat as 'no duration'\n  return parseDuration(d as any)\n}\n\nconst delay = safeDuration(raw)","typeGuard":"const isValidDurationNumber = (v: unknown): v is number =>\n  typeof v === 'number' && Number.isFinite(v) && v >= 0","tryCatchPattern":"try {\n  await sleep(duration)\n} catch (e) {\n  if (e instanceof Error && /Invalid duration/.test(e.message)) {\n    // skip the wait; duration was NaN/negative\n    return\n  }\n  throw e\n}","preventionTips":["Validate duration with Number.isFinite(d) && d >= 0 before passing to sleep/retry/timeout.","Clamp computed deltas with Math.max(0, delta) to avoid negatives.","Prefer the string form ('100ms', '2s') over numeric inputs derived from untrusted sources."],"tags":["duration","validation","sleep","retry","timeout"],"backgroundTag":null,"analyzedSha":"00a2c484e219c2e84bfc3a199febf7fbce2cfbf4","analyzedAt":"2026-08-13T02:11:06.305Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}