{"record":{"id":"0b529be5a5bc5603","repo":"jlcodes99/cockpit-tools","slug":"crontab-no-values","errorCode":"crontab_no_values","errorMessage":"crontab_no_values","messagePattern":"crontab_no_values","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"info","filePath":"src/pages/WakeupTasksPage.tsx","lineNumber":543,"sourceCode":"    insertCrontabRange(values, min, max, 1, normalizeDayOfWeek);\n    return { values, wildcard: true };\n  }\n\n  const values = new Set<number>();\n  const segments = trimmed.split(',');\n  if (segments.length === 0) {\n    throw new Error('crontab_field_empty');\n  }\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};","sourceCodeStart":525,"sourceCodeEnd":561,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/src/pages/WakeupTasksPage.tsx#L525-L561","documentation":"After parsing all segments of a field into a shared Set, parseCrontabField checks values.size === 0 and throws 'crontab_no_values'. This guards against inputs whose segments parsed but produced no numeric values (practically a companion to crontab_segment_empty; with the current segment parser, values are always inserted or an earlier error throws, so it is largely defensive).","triggerScenarios":"A field whose comma segments yield no inserted values — with current parseCrontabSegment this requires reaching the check via a code path where segments parsed without inserting; effectively defensive against future segment types (e.g. step-only segments like '/5' or empty range expansions).","commonSituations":"No common user-facing situation today; relevant when extending the parser (e.g. adding '@reboot' aliases, step-only syntax, or list macros that expand to nothing).","solutions":["Provide at least one concrete value or range in the field (e.g. '0' or '*/5').","If extending parseCrontabSegment, ensure every accepted syntax inserts at least one value or throws its own specific error.","Keep the try/catch around parseCrontabExpression at the form level and map 'crontab_no_values' to a user-facing message."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"const fieldHasValues = (values: Set<number>): boolean => values.size > 0;","tryCatchPattern":"try {\n  const parsed = parseCrontabExpression(expr);\n} catch (e) {\n  if ((e as Error).message === 'crontab_no_values') {\n    setFieldError('field produced no values; provide at least one value or range');\n  }\n}","preventionTips":["If extending parseCrontabSegment, guarantee each accepted syntax inserts at least one value","Write parser unit tests asserting every valid-looking segment yields a non-empty Set","Map this error code to a clear user-facing message in the crontab form"],"tags":["crontab","defensive-code","input-parsing"],"backgroundTag":"crontab-no-values","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"}