{"record":{"id":"1de7931991a9b874","repo":"can1357/oh-my-pi","slug":"date-bounds-require-a-date-type","errorCode":null,"errorMessage":"date bounds require a Date type","messagePattern":"date bounds require a Date type","errorType":"exception","errorClass":"OmpTypeError","httpStatus":null,"severity":"error","filePath":"packages/omptype/src/type.ts","lineNumber":1787,"sourceCode":"\t\t\t: {}),\n\t};\n}\n\nfunction acceptsDateIR(ir: IR): boolean {\n\tif (ir.k === \"instance\") return ir.ctor === Date;\n\tif (ir.k === \"refine\") return acceptsDateIR(ir.base);\n\tif (ir.k === \"union\") return ir.members.every(acceptsDateIR);\n\treturn false;\n}\n\nfunction dateRefinement(\n\tschema: InternalType,\n\ttimestamp: number,\n\trelation: string,\n\tpredicate: (value: number) => boolean,\n): InternalType {\n\tif (!Number.isFinite(timestamp)) throw new OmpTypeError(\"date bound must be valid\");\n\tif (!acceptsDateIR(schema.ir)) throw new OmpTypeError(\"date bounds require a Date type\");\n\tconst bound = new Date(timestamp);\n\treturn makeType(\n\t\t{\n\t\t\tk: \"refine\",\n\t\t\tbase: schema.ir,\n\t\t\tpred: value => value instanceof Date && predicate(value.valueOf()),\n\t\t\texpected: `a Date ${relation} ${bound.toISOString()}`,\n\t\t\tjson: relation.includes(\"after\") ? { minimum: bound.toISOString() } : { maximum: bound.toISOString() },\n\t\t},\n\t\tschema[kSteps],\n\t\tmetaOf(schema),\n\t);\n}\n\nfunction selectNodes(root: IR, kind: string): readonly SelectedNode[] {\n\tconst selected: SelectedNode[] = [];\n\tconst seen = new Set<IR>();\n\tconst visit = (node: IR): void => {","sourceCodeStart":1769,"sourceCodeEnd":1805,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/omptype/src/type.ts#L1769-L1805","documentation":"Date bounds (min/max/after/before) only apply to schemas whose IR is Date-shaped; acceptsDateIR() rejects anything else. Calling a date refinement on a string or number schema is almost always a mistake, so omptype throws at schema-construction time rather than failing every validation later.","triggerScenarios":"string.minDate(...) or number.after(...) — any date refinement applied to a non-Date schema.","commonSituations":"Dates stored as ISO strings: developers reach for date bounds on string() instead of isoDate refinements; confusion after refactoring a Date field to a timestamp number.","solutions":["Apply the bound to a date() schema: date().min(...)","For string dates use a string refinement (e.g. isoDateTime) or convert the schema to date()","For numeric timestamps use a number refinement like number().min(timestamp)","Check which field you called the method on; the wrong-variable bug is common"],"exampleFix":"// before\nstring().minDate(new Date('2024-01-01'))\n// after\ndate().min(new Date('2024-01-01'))","handlingStrategy":"type-guard","validationCode":"function assertDateSchema(schema) {\n  if (!schema.ir || schema.ir.k !== 'refine' && !isDateShaped(schema.ir)) throw new Error('date bound needs a date() schema');\n}","typeGuard":"function isDateSchema(t): t is InternalType {\n  return typeof t === 'object' && t !== null && acceptsDateIR(t.ir);\n}","tryCatchPattern":"try {\n  return schema.min(bound);\n} catch (err) {\n  if (err instanceof OmpTypeError && err.message === 'date bounds require a Date type') {\n    throw new Error('call date bounds on date(), not string()/number()');\n  }\n  throw err;\n}","preventionTips":["Decide up front whether dates are Date objects, ISO strings, or epoch numbers — and use the matching schema type","Name fields explicitly (createdAtDate vs createdAtIso) to avoid wrong-schema method calls","Keep a table of which refinement methods belong to which schema kind"],"tags":["omptype","date","wrong-type","api-misuse"],"backgroundTag":"date-bound-on-non-date-type","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}