{"record":{"id":"2f452c1a8c58d98c","repo":"amruthpillai/reactive-resume","slug":"bad-request-2f452c","errorCode":"BAD_REQUEST","errorMessage":"Date must use YYYY-MM-DD format.","messagePattern":"Date must use YYYY-MM-DD format\\.","errorType":"exception","errorClass":"ORPCError","httpStatus":400,"severity":"error","filePath":"packages/api/src/features/applications/service.ts","lineNumber":22,"sourceCode":"\tApplicationTimelineEntry,\n\tContact,\n} from \"@reactive-resume/schema/applications/data\";\nimport type { ApplicationDocumentKind } from \"../../dto/application\";\nimport { ORPCError } from \"@orpc/client\";\nimport { and, arrayContains, desc, eq, inArray, sql } from \"drizzle-orm\";\nimport { db } from \"@reactive-resume/db/client\";\nimport * as schema from \"@reactive-resume/db/schema\";\nimport { generateId } from \"@reactive-resume/utils/string\";\nimport { resumeService } from \"../resume/service\";\nimport { getStorageService, uploadFile } from \"../storage/service\";\n\nfunction timelineDate(value: Date | string): Date {\n\treturn value instanceof Date ? value : new Date(value);\n}\n\nfunction atFromDateString(date: string, existing?: Date | string): Date {\n\tconst [year, month, day] = date.split(\"-\").map(Number);\n\tif (!year || !month || !day) throw new ORPCError(\"BAD_REQUEST\", { message: \"Date must use YYYY-MM-DD format.\" });\n\n\tconst existingDate = existing ? timelineDate(existing) : undefined;\n\n\tconst parsed = new Date(\n\t\tDate.UTC(\n\t\t\tyear,\n\t\t\tmonth - 1,\n\t\t\tday,\n\t\t\texistingDate?.getUTCHours() ?? 12,\n\t\t\texistingDate?.getUTCMinutes() ?? 0,\n\t\t\texistingDate?.getUTCSeconds() ?? 0,\n\t\t\texistingDate?.getUTCMilliseconds() ?? 0,\n\t\t),\n\t);\n\tif (timelineDay(parsed) !== date) throw new ORPCError(\"BAD_REQUEST\", { message: \"Date must use YYYY-MM-DD format.\" });\n\n\treturn parsed;\n}","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/amruthpillai/reactive-resume/blob/3a5b12e2a40374a9571988701fcb75c5a1831c42/packages/api/src/features/applications/service.ts#L4-L40","documentation":"Thrown by atFromDateString() when a date string passed to an application timeline operation cannot split on '-' into three non-zero numeric components (year, month, day). The applications service requires calendar dates as strict 'YYYY-MM-DD' strings so it can pin UTC time-of-day to 12:00:00Z while preserving any existing hours/minutes. This is the first of two format guards — it catches structurally malformed input before any Date is constructed.","triggerScenarios":"Calling applicationService.create or importMany with stageEnteredAt like '2024/01/15', 'Jan 15 2024', '2024-1', '' or 'abc'; or addNote/updateTimelineEntry with a date field in any non-dashed, time-bearing, or incomplete shape.","commonSituations":"A frontend date picker emitting locale-formatted strings (en-US 'MM/DD/YYYY'), an importer mapping spreadsheet dates verbatim, or a test fixture using ISO datetime ('2024-01-15T10:00:00Z') instead of date-only.","solutions":["Normalize every date to 'YYYY-MM-DD' (e.g. new Date(value).toISOString().slice(0,10)) before calling create/importMany/addNote/updateTimelineEntry.","If the source is a Date object, format it with Date.UTC(...) then toISOString().slice(0,10).","Strip any time component or timezone offset before submission."],"exampleFix":"// before\napplicationService.create({ ..., stageEnteredAt: '01/15/2024' });\n// after\nconst d = new Date('2024-01-15');\nconst stageEnteredAt = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate())).toISOString().slice(0,10);\napplicationService.create({ ..., stageEnteredAt });","handlingStrategy":"validation","validationCode":"const ISO_DATE = /^\\d{4}-\\d{2}-\\d{2}$/;\nfunction toIsoDate(value: string | Date): string {\n  const d = value instanceof Date ? value : new Date(value);\n  const iso = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate())).toISOString().slice(0, 10);\n  if (!ISO_DATE.test(iso)) throw new Error(`Not a YYYY-MM-DD date: ${String(value)}`);\n  return iso;\n}\n// toIsoDate('01/15/2024') -> '2024-01-15'","typeGuard":"function isIsoDateString(value: unknown): value is string {\n  return typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2}$/.test(value);\n}","tryCatchPattern":null,"preventionTips":["Always format dates with Date.UTC(...).toISOString().slice(0,10) before sending.","Never pass locale-formatted or datetime strings to timeline endpoints.","Centralize date formatting in one helper used by all callers."],"tags":["validation","date-format","applications","bad-request"],"backgroundTag":null,"analyzedSha":"3a5b12e2a40374a9571988701fcb75c5a1831c42","analyzedAt":"2026-08-12T22:31:22.666Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}