{"record":{"id":"c800a22596a1126d","repo":"can1357/oh-my-pi","slug":"invalid-query-time","errorCode":null,"errorMessage":"Invalid query time","messagePattern":"Invalid query time","errorType":"exception","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"packages/mnemopi/src/core/beam/recall.ts","lineNumber":400,"sourceCode":"\t\t\t}\n\t\t}\n\t}\n\treturn clamp01((exact + partial * 0.5) / queryTokens.length);\n}\n\nfunction recencyDecay(timestamp: unknown, halfLifeHours = 72): number {\n\tconst raw = asString(timestamp);\n\tif (raw.length === 0) return 0;\n\tconst parsed = Date.parse(raw);\n\tif (!Number.isFinite(parsed)) return 0;\n\tconst ageHours = Math.max(0, (Date.now() - parsed) / 3_600_000);\n\treturn Math.exp(-ageHours / Math.max(halfLifeHours, 0.001));\n}\n\nexport function parseQueryTime(value: RecallOptionsInternal[\"queryTime\"]): Date {\n\tif (value == null) return new Date();\n\tif (value instanceof Date) {\n\t\tif (!Number.isFinite(value.getTime())) throw new RangeError(\"Invalid query time\");\n\t\treturn value;\n\t}\n\tif (typeof value === \"string\") {\n\t\tconst normalized = /^\\d{4}-\\d{2}-\\d{2}$/.test(value)\n\t\t\t? `${value}T00:00:00.000Z`\n\t\t\t: /(?:Z|[+-]\\d{2}:?\\d{2})$/.test(value)\n\t\t\t\t? value\n\t\t\t\t: `${value}Z`;\n\t\tconst parsed = new Date(normalized);\n\t\tif (Number.isFinite(parsed.getTime())) return parsed;\n\t}\n\tthrow new TypeError(\"queryTime must be null, an ISO date string, or a valid Date\");\n}\n\nexport function temporalBoost(timestamp: unknown, queryTime: Date, halfLifeHours: number): number {\n\tconst raw = asString(timestamp);\n\tif (raw.length === 0) return 0;\n\tconst parsed = Date.parse(raw);","sourceCodeStart":382,"sourceCodeEnd":418,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/mnemopi/src/core/beam/recall.ts#L382-L418","documentation":"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.","triggerScenarios":"Passing `queryTime` as a Date built from invalid input (e.g. `new Date(NaN)` or `new Date(\"foo\")`) to recall/decay/scoreCandidate/eventBoost options.","commonSituations":"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.","solutions":["Check `Number.isFinite(d.getTime())` before assigning the Date to queryTime.","Pass an ISO string (YYYY-MM-DD or full ISO with Z) instead of a Date when the source is text.","Fix the upstream construction: use Date.now() or a validated parse for the source value."],"exampleFix":"// before\nconst qt = new Date(record.timestamp); // record.timestamp missing -> Invalid Date\nrecall(query, { queryTime: qt });\n// after\nconst qt = new Date(record.timestamp);\nif (Number.isNaN(qt.getTime())) qt = new Date(); // fall back to now\nrecall(query, { queryTime: qt });","handlingStrategy":"validation","validationCode":"if (queryTime instanceof Date && !Number.isFinite(queryTime.getTime())) {\n  queryTime = new Date(); // fallback to now\n}","typeGuard":"function isUsableDate(v: unknown): v is Date {\n  return v instanceof Date && Number.isFinite(v.getTime());\n}","tryCatchPattern":"try {\n  await recall(query, { queryTime });\n} catch (e) {\n  if (e instanceof RangeError && e.message === \"Invalid query time\") {\n    await recall(query, {}); // default to now\n  } else throw e;\n}","preventionTips":["Validate Dates at deserialization boundaries (JSON.parse yields strings, not Dates).","Use parseQueryTime's string path (ISO/ YYYY-MM-DD) when the source is textual.","Add a single sanitize step where queryTime is produced, not at every call site."],"tags":["date","validation","rangeerror"],"backgroundTag":"invalid-date-value","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}