{"record":{"id":"d67069ddd8ab1393","repo":"jlcodes99/cockpit-tools","slug":"crontab-parts-must-be-five","errorCode":"crontab_parts_must_be_five","errorMessage":"crontab_parts_must_be_five","messagePattern":"crontab_parts_must_be_five","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/pages/WakeupTasksPage.tsx","lineNumber":551,"sourceCode":"  }\n  segments.forEach((segment) => {\n    const normalizedSegment = segment.trim();\n    if (!normalizedSegment) {\n      throw new Error('crontab_segment_empty');\n    }\n    parseCrontabSegment(normalizedSegment, min, max, normalizeDayOfWeek, values);\n  });\n\n  if (values.size === 0) {\n    throw new Error('crontab_no_values');\n  }\n  return { values, wildcard: false };\n};\n\nconst parseCrontabExpression = (expr: string): ParsedCrontab => {\n  const parts = expr.trim().split(/\\s+/);\n  if (parts.length !== 5) {\n    throw new Error('crontab_parts_must_be_five');\n  }\n\n  return {\n    minute: parseCrontabField(parts[0], 0, 59, false),\n    hour: parseCrontabField(parts[1], 0, 23, false),\n    dayOfMonth: parseCrontabField(parts[2], 1, 31, false),\n    month: parseCrontabField(parts[3], 1, 12, false),\n    dayOfWeek: parseCrontabField(parts[4], 0, 7, true),\n  };\n};\n\nconst isCrontabMatch = (parsed: ParsedCrontab, date: Date): boolean => {\n  const minute = date.getMinutes();\n  const hour = date.getHours();\n  const dayOfMonth = date.getDate();\n  const month = date.getMonth() + 1;\n  const dayOfWeek = date.getDay();\n","sourceCodeStart":533,"sourceCodeEnd":569,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/src/pages/WakeupTasksPage.tsx#L533-L569","documentation":"parseCrontabExpression splits the trimmed expression on whitespace and requires exactly five fields (minute hour day-of-month month day-of-week). Any other count — too few or too many — throws 'crontab_parts_must_be_five'; six/eight-field cron dialects with seconds or years are not supported.","triggerScenarios":"parseCrontabExpression called with '*/5 * * *' (4 fields), '* * * * * *' (6 fields, e.g. a Quartz or seconds-precision cron), or an empty string (split gives ['']).","commonSituations":"Pasting a Quartz expression ('0 0/5 * * * ?') or a systemd/6-field cron into the Wakeup Tasks crontab input; an empty crontab field on the form; trailing comments or extra tokens counted as fields.","solutions":["Convert the expression to standard 5-field cron: drop the seconds field and replace Quartz '?' with '*'.","If seconds precision is needed, note it is unsupported; move the sub-minute logic into the scheduler, not the cron string.","Trim stray whitespace/tokens and ensure exactly five space-separated fields: '*/5 * * * *'.","Validate with parseCrontabExpression in a try/catch before save and show the code to the user."],"exampleFix":"// before\n'0 0/5 * * * ?'      // Quartz 6-field\n// after\n'*/5 * * * *'        // standard 5-field cron","handlingStrategy":"validation","validationCode":"const isFiveFieldCron = (expr: string): boolean =>\n  expr.trim().split(/\\s+/).length === 5;\n// additionally reject Quartz '?' and seconds field before parsing","typeGuard":"const isStandardCron = (expr: unknown): expr is string =>\n  typeof expr === 'string' && expr.trim().split(/\\s+/).length === 5 && !expr.includes('?');","tryCatchPattern":"try {\n  const parsed = parseCrontabExpression(expr);\n} catch (e) {\n  if ((e as Error).message === 'crontab_parts_must_be_five') {\n    setFieldError('use standard 5-field cron (minute hour dom month dow)');\n  }\n}","preventionTips":["Convert Quartz/6-field crons to 5-field before storing or submitting","Disable submit while the crontab input is empty","Count fields client-side with split(/\\s+/) and show a live field counter","Strip stray tokens/comments from pasted cron strings"],"tags":["validation","crontab","input-parsing"],"backgroundTag":"crontab-parts-must-be-five","analyzedSha":"1ed8b77992d62ca81fabf744deb0839ad361d5bf","analyzedAt":"2026-09-05T09:51:41.178Z","contentChangedAt":"2026-09-05T09:51:41.178Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}