denoland/deno · error · InvalidData

invalid , must not be infinity or NaN

Error message

invalid ${name}, must not be infinity or NaN

What it means

fs.lutimes(path, atime, mtime, callback) converts each TimeLike (Date, number, or numeric string) into unix seconds/nanoseconds via getValidUnixTime. Strings are coerced with Number(), and if the resulting value is NaN or Infinity the polyfill throws Deno.errors.InvalidData with 'invalid atime/mtime, must not be infinity or NaN'. This guards the OS-level utimensat call, which cannot accept non-finite timestamps.

Solutions

  1. Validate before calling: Number.isFinite(new Date(atime).getTime())
  2. Sanitize strings with a fallback: Number.isNaN(Number(s)) ? Date.now() : s
  3. If the value may be absent, pass a fresh Date or omit the lutimes call instead of sending NaN

Example fix

// before
fs.lutimes(path, 'yesterday-ish', mtime, cb); // Number('yesterday-ish') = NaN

// after
const atime = new Date('2024-01-01T00:00:00Z');
if (Number.isFinite(atime.getTime())) {
  fs.lutimes(path, atime.getTime() / 1000, mtime, cb);
}
Defensive patterns

Strategy: validation

Validate before calling

const toTime = (v) => typeof v === 'string' ? Number(v) : (v instanceof Date ? v.getTime() / 1000 : v);
if (!Number.isFinite(toTime(atime)) || !Number.isFinite(toTime(mtime))) throw new RangeError('atime/mtime must be finite');

Type guard

const isValidTimeLike = (v) => { const n = typeof v === 'string' ? Number(v) : (v instanceof Date ? v.getTime() / 1000 : v); return typeof n === 'number' && Number.isFinite(n); };

Try / catch

try { fs.lutimesSync(p, atime, mtime); } catch (e) { if (e instanceof Deno.errors.InvalidData) { /* coerce to a sane default and retry once with Date.now() */ } else throw e; }

Prevention

When it happens

Trigger: fs.lutimes(path, 'not-a-date', new Date(), cb) — Number('not-a-date') is NaN; passing an already-invalid Date (new Date('garbage')) whose getTime() is NaN; passing Infinity from a computation like 1/0 or Number.MAX_VALUE * 2; an empty string atime ('' coerces to 0 and passes, but 'abc' fails).

Common situations: Parsing timestamps from filenames or metadata that may not be numeric; feeding client-supplied strings straight into utimes-style APIs; DST/parse edge cases producing Invalid Date objects.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/700e3601693045b6. Report an issue: GitHub.

Appendix: source

Thrown at ext/node/polyfills/_fs/_fs_lutimes.ts:37

  PromisePrototypeThen,
} = primordials;

type TimeLike = number | string | Date;
type PathLike = string | Buffer | URL;

function getValidUnixTime(
  value: TimeLike,
  name: string,
): [number, number] {
  if (typeof value === "string") {
    value = Number(value);
  }

  if (
    typeof value === "number" &&
    (NumberIsNaN(value) || !NumberIsFinite(value))
  ) {
    throw new Deno.errors.InvalidData(
      `invalid ${name}, must not be infinity or NaN`,
    );
  }

  const unixSeconds = toUnixTimestamp(value);

  const seconds = MathTrunc(unixSeconds);
  const nanoseconds = MathTrunc((unixSeconds * 1e3) - (seconds * 1e3)) * 1e6;

  return [
    seconds,
    nanoseconds,
  ];
}

export function lutimes(
  path: PathLike,
  atime: TimeLike,

View on GitHub (pinned to 9ad36f7a2c)