{"record":{"id":"0d652bad77d94ff9","repo":"ionic-team/ionic-framework","slug":"invalid-hour-cycle-hourcycle","errorCode":null,"errorMessage":"Invalid hour cycle \"${hourCycle}\"","messagePattern":"Invalid hour cycle \"(.+?)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"core/src/components/datetime/utils/data.ts","lineNumber":193,"sourceCode":"  return days;\n};\n\n/**\n * Returns an array of pre-defined hour\n * values based on the provided hourCycle.\n */\nconst getHourData = (hourCycle: DatetimeHourCycle) => {\n  switch (hourCycle) {\n    case 'h11':\n      return hour11;\n    case 'h12':\n      return hour12;\n    case 'h23':\n      return hour23;\n    case 'h24':\n      return hour24;\n    default:\n      throw new Error(`Invalid hour cycle \"${hourCycle}\"`);\n  }\n};\n\n/**\n * Given a local, reference datetime parts and option\n * max/min bound datetime parts, calculate the acceptable\n * hour and minute values according to the bounds and locale.\n */\nexport const generateTime = (\n  locale: string,\n  refParts: DatetimeParts,\n  hourCycle: DatetimeHourCycle = 'h12',\n  minParts?: DatetimeParts,\n  maxParts?: DatetimeParts,\n  hourValues?: number[],\n  minuteValues?: number[]\n) => {\n  const computedHourCycle = getHourCycle(locale, hourCycle);","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/ionic-team/ionic-framework/blob/625f9c38ad8c5db8a6c12df5c1622a36da90f9e3/core/src/components/datetime/utils/data.ts#L175-L211","documentation":"Thrown by getHourData() inside ion-datetime's time-generation pipeline when the resolved hourCycle is not one of 'h11', 'h12', 'h23', or 'h24'. The switch has no other cases, so any other value falls to the default branch. The DatetimeHourCycle type already constrains the input at compile time, so a runtime hit almost always means the value was cast to the type unsafely or came from a corrupted/partially-initialized state.","triggerScenarios":"generateTime() is called (e.g. while rendering the ion-datetime time wheel) and the computedHourCycle passed into getHourData() is undefined, an empty string, a typo like 'H12', or a locale-derived value that bypassed getHourCycle's validation. Also reachable by directly importing and calling getHourData with an arbitrary string.","commonSituations":"Passing hourCycle via a generic <any> cast or reading it from a config file/URL query without validation; SSR or test environments where Intl returns unexpected shapes; upgrading Ionic and a stale cache serves an old value.","solutions":["Do not pass hourCycle directly; let ion-datetime derive it from the locale via its preferredHours/hourCycle prop, or set hourCycle explicitly to one of the four valid literals.","If you compute hourCycle yourself, validate it against the set {'h11','h12','h23','h24'} before assigning it to the component or feeding generateTime.","Search the codebase for `as DatetimeHourCycle` / `as any` casts on hourCycle and replace them with a runtime check.","Clear node_modules/build cache and rebuild if the value appears after an Ionic upgrade."],"exampleFix":"// before\nconst hc = (config.hourCycle as any) as DatetimeHourCycle; // e.g. 'H12' slips through\n<ion-datetime hour-cycle={hc}></ion-datetime>\n\n// after\nconst VALID = ['h11','h12','h23','h24'] as const;\nconst hc = VALID.includes(config.hourCycle) ? config.hourCycle : 'h12';\n<ion-datetime hour-cycle={hc}></ion-datetime>","handlingStrategy":"type-guard","validationCode":"const VALID_HOUR_CYCLES = ['h11','h12','h23','h24'] as const;\nfunction resolveHourCycle(input: unknown): DatetimeHourCycle {\n  return (VALID_HOUR_CYCLES as readonly string[]).includes(input as string)\n    ? (input as DatetimeHourCycle)\n    : 'h12';\n}","typeGuard":"function isDatetimeHourCycle(v: unknown): v is DatetimeHourCycle {\n  return v === 'h11' || v === 'h12' || v === 'h23' || v === 'h24';\n}","tryCatchPattern":"try {\n  datetime.generateTime(locale, parts, hourCycle);\n} catch (e) {\n  if (e instanceof Error && /Invalid hour cycle/.test(e.message)) {\n    // fall back to a safe cycle and retry render\n    hourCycle = 'h12';\n  } else { throw e; }\n}","preventionTips":["Never cast arbitrary strings to DatetimeHourCycle; run them through an allow-list.","Let ion-datetime derive hourCycle from locale instead of setting it manually.","Add a unit test that feeds every supported cycle through your datetime wrapper."],"tags":["datetime","hour-cycle","locale","runtime","validation"],"backgroundTag":null,"analyzedSha":"625f9c38ad8c5db8a6c12df5c1622a36da90f9e3","analyzedAt":"2026-08-12T16:00:25.413Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}