can1357/oh-my-pi · warning · RangeError

Invalid Date

Error message

Invalid Date

What it means

normalizeDateTimeUtc() validates an existing Date and returns a UTC-normalized copy. If the input Date holds NaN (an invalid date), it throws a RangeError('Invalid Date'). This catches Dates constructed from bad input (new Date('garbage')) before they propagate into query filters or stored timestamps.

Source

Thrown at packages/mnemopi/src/util/datetime.ts:22

const TZ_RE = /(?:Z|[+-]\d\d:?\d\d)$/;
const DATE_ONLY_RE = /^\d{4}-\d{2}-\d{2}$/;
const TS_CACHE = new LruCache<string, Date>(2000);

export type QueryTime = string | Date | null | undefined;

export function parseIsoDateTimeUtc(value: string): Date {
	let text = value.trim();
	if (!text) throw new RangeError("Invalid ISO datetime: empty string");
	if (DATE_ONLY_RE.test(text)) text += "T00:00:00Z";
	else if (!TZ_RE.test(text)) text += "Z";
	const date = new Date(text);
	if (Number.isNaN(date.getTime())) throw new RangeError(`Invalid ISO datetime: ${value}`);
	return date;
}

export function normalizeDateTimeUtc(value: Date): Date {
	const time = value.getTime();
	if (Number.isNaN(time)) throw new RangeError("Invalid Date");
	return new Date(time);
}

export function parseQueryTime(value: QueryTime): Date {
	if (value === null || value === undefined) return new Date();
	return typeof value === "string" ? parseIsoDateTimeUtc(value) : normalizeDateTimeUtc(value);
}

export function parseTsFast(value: string): Date | undefined {
	if (!value) return undefined;
	const cached = TS_CACHE.get(value);
	if (cached !== undefined) return cached;
	try {
		const parsed = parseIsoDateTimeUtc(value);
		TS_CACHE.set(value, parsed);
		return parsed;
	} catch {
		return undefined;

View on GitHub (pinned to 9690622007)

Solutions

  1. Check isNaN(d.getTime()) at the input boundary before calling.
  2. Ensure values are parsed via parseIsoDateTimeUtc() for strings, which gives a precise error message.
  3. Guard optional values: only construct a Date when the source value is present and valid.
  4. If NaN came from date arithmetic, log the operands — one of them was already invalid.

Example fix

// before
const t = parseQueryTime(new Date(config.since)); // config.since undefined -> Invalid Date
// after
const since = config.since ? parseIsoDateTimeUtc(String(config.since)) : null;
const t = parseQueryTime(since); // null -> now
Defensive patterns

Strategy: type-guard

Validate before calling

function isValidDate(d) {
  return d instanceof Date && !Number.isNaN(d.getTime());
}
if (!isValidDate(candidate)) throw new Error(`Bad date from source: ${String(sourceValue)}`);
const t = parseQueryTime(candidate);

Type guard

function isValidDate(d) { return d instanceof Date && !Number.isNaN(d.getTime()); }
// use: if (isValidDate(d)) parseQueryTime(d);

Try / catch

try {
  const t = normalizeDateTimeUtc(d);
} catch (err) {
  if (err instanceof RangeError && err.message === 'Invalid Date') {
    logger.warn('Invalid Date reached normalizeDateTimeUtc', { raw: String(sourceValue) });
    return new Date(); // or rethrow with source context
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling normalizeDateTimeUtc(new Date('invalid')), normalizeDateTimeUtc(new Date(NaN)), or parseQueryTime(dateObj) with such a Date; also passing a Date that another parser failed to construct.

Common situations: new Date(undefined) from missing config values, arithmetic on dates producing NaN (subtracting invalid dates), JSON deserialization yielding strings that were new Date()'d unvalidated, or new Date(numberString) mis-parsing numeric strings.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/27caf74abca6361b. Report an issue: GitHub.