{"record":{"id":"7d8e322ee9149ac9","repo":"RocketChat/Rocket.Chat","slug":"invalid-iso-8601-date","errorCode":null,"errorMessage":"invalid ISO 8601 date","messagePattern":"invalid ISO 8601 date","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/ee/server/lib/engagementDashboard/date.ts","lineNumber":14,"sourceCode":"import mem from 'mem';\nimport moment from 'moment';\n\nexport const isDateISOString = mem(\n\t(input: string): input is string => {\n\t\tconst timestamp = Date.parse(input);\n\t\treturn !Number.isNaN(timestamp) && new Date(timestamp).toISOString() === input;\n\t},\n\t{ maxAge: 10000 },\n);\n\nexport const mapDateForAPI = (input: string): Date => {\n\tif (!isDateISOString(input)) {\n\t\tthrow new Error('invalid ISO 8601 date');\n\t}\n\n\treturn new Date(Date.parse(input));\n};\n\nexport const convertDateToInt = (date: Date): number => parseInt(moment(date).clone().format('YYYYMMDD'), 10);\nexport const convertIntToDate = (intValue: number): Date => moment(intValue, 'YYYYMMDD').clone().toDate();\nconst diffBetweenDays = (start: string | number | Date, end: string | number | Date): number =>\n\tmoment(new Date(start)).clone().diff(new Date(end), 'days');\nexport const diffBetweenDaysInclusive = (start: string | number | Date, end: string | number | Date): number =>\n\tdiffBetweenDays(start, end) + 1;\n\nexport const getTotalOfWeekItems = <T extends Record<string, number>>(weekItems: T[], property: keyof T): number =>\n\tweekItems.reduce((acc, item) => {\n\t\tacc += item[property];\n\t\treturn acc;\n\t}, 0);\n","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/ee/server/lib/engagementDashboard/date.ts#L1-L32","documentation":"Thrown by mapDateForAPI (engagementDashboard/date.ts) when the input string fails isDateISOString — a memoized validator that requires both Date.parse to succeed AND new Date(ts).toISOString() to round-trip exactly back to the input. Plain Error. This is intentionally strict: '2021-01-01' or '2021/01/01' will fail because they do not match the full toISOString output.","triggerScenarios":"Calling the engagement dashboard API with a date that is not a full ISO 8601 timestamp in UTC 'Z' form — e.g. date-only, locale strings, millisecond/truncated variants, or strings that parse but do not round-trip identically.","commonSituations":"Client sends a YYYY-MM-DD value from a date picker; integration forwards a locale-formatted date; timezone offset included (e.g. '+00:00') so toISOString !== input; trailing spaces or non-ISO separators.","solutions":["Send the date as a full UTC ISO string produced by new Date(...).toISOString() (e.g. '2021-06-01T00:00:00.000Z').","On the caller, normalize with moment(date).toISOString() before hitting the API.","If only a date is meaningful, expand it to start-of-day UTC on the client."],"exampleFix":"// before\nmapDateForAPI('2021-06-01');          // throws\nmapDateForAPI('06/01/2021 00:00');     // throws\n\n// after\nmapDateForAPI(new Date('2021-06-01').toISOString()); // '2021-06-01T00:00:00.000Z'","handlingStrategy":"validation","validationCode":"function toApiDate(input: string | Date): string {\n  const iso = input instanceof Date ? input.toISOString() : new Date(input).toISOString();\n  if (!isDateISOString(iso)) throw new Error('invalid ISO 8601 date');\n  return iso;\n}","typeGuard":"const isISODate = (s: unknown): s is string =>\n  typeof s === 'string' && !Number.isNaN(Date.parse(s)) && new Date(Date.parse(s)).toISOString() === s;","tryCatchPattern":"try { mapDateForAPI(input); } catch (e) {\n  if (e instanceof Error && e.message === 'invalid ISO 8601 date') { /* normalize input with new Date(input).toISOString() and retry */ } else throw e;\n}","preventionTips":["Always send new Date(value).toISOString() to engagement dashboard endpoints.","Use a date picker that emits full UTC ISO strings, not date-only values.","Strip timezone offsets on the client before submission."],"tags":["validation","date","engagement-dashboard","enterprise"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}