can1357/oh-my-pi · error · RangeError

Invalid query time

Error message

Invalid query time

What it means

This is recall.ts's own parseQueryTime guard for the `queryTime` option: a Date whose getTime() is not finite is rejected with a RangeError. It mirrors helpers.normalizeDateUtc but lives in the recall scoring path so decay/boost math never receives NaN time.

Source

Thrown at packages/mnemopi/src/core/beam/recall.ts:400

			}
		}
	}
	return clamp01((exact + partial * 0.5) / queryTokens.length);
}

function recencyDecay(timestamp: unknown, halfLifeHours = 72): number {
	const raw = asString(timestamp);
	if (raw.length === 0) return 0;
	const parsed = Date.parse(raw);
	if (!Number.isFinite(parsed)) return 0;
	const ageHours = Math.max(0, (Date.now() - parsed) / 3_600_000);
	return Math.exp(-ageHours / Math.max(halfLifeHours, 0.001));
}

export function parseQueryTime(value: RecallOptionsInternal["queryTime"]): Date {
	if (value == null) return new Date();
	if (value instanceof Date) {
		if (!Number.isFinite(value.getTime())) throw new RangeError("Invalid query time");
		return value;
	}
	if (typeof value === "string") {
		const normalized = /^\d{4}-\d{2}-\d{2}$/.test(value)
			? `${value}T00:00:00.000Z`
			: /(?:Z|[+-]\d{2}:?\d{2})$/.test(value)
				? value
				: `${value}Z`;
		const parsed = new Date(normalized);
		if (Number.isFinite(parsed.getTime())) return parsed;
	}
	throw new TypeError("queryTime must be null, an ISO date string, or a valid Date");
}

export function temporalBoost(timestamp: unknown, queryTime: Date, halfLifeHours: number): number {
	const raw = asString(timestamp);
	if (raw.length === 0) return 0;
	const parsed = Date.parse(raw);

View on GitHub (pinned to 9690622007)

Solutions

  1. Check `Number.isFinite(d.getTime())` before assigning the Date to queryTime.
  2. Pass an ISO string (YYYY-MM-DD or full ISO with Z) instead of a Date when the source is text.
  3. Fix the upstream construction: use Date.now() or a validated parse for the source value.

Example fix

// before
const qt = new Date(record.timestamp); // record.timestamp missing -> Invalid Date
recall(query, { queryTime: qt });
// after
const qt = new Date(record.timestamp);
if (Number.isNaN(qt.getTime())) qt = new Date(); // fall back to now
recall(query, { queryTime: qt });
Defensive patterns

Strategy: validation

Validate before calling

if (queryTime instanceof Date && !Number.isFinite(queryTime.getTime())) {
  queryTime = new Date(); // fallback to now
}

Type guard

function isUsableDate(v: unknown): v is Date {
  return v instanceof Date && Number.isFinite(v.getTime());
}

Try / catch

try {
  await recall(query, { queryTime });
} catch (e) {
  if (e instanceof RangeError && e.message === "Invalid query time") {
    await recall(query, {}); // default to now
  } else throw e;
}

Prevention

When it happens

Trigger: Passing `queryTime` as a Date built from invalid input (e.g. `new Date(NaN)` or `new Date("foo")`) to recall/decay/scoreCandidate/eventBoost options.

Common situations: Date fields round-tripped through JSON that lost their validity, arithmetic on dates producing NaN, or developer confusion between numeric timestamps (ms) and Date objects.

Related errors


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