jlcodes99/cockpit-tools · error

crontab_step_must_be_positive

crontab_step_must_be_positive

Error message

crontab_step_must_be_positive

What it means

parseCrontabSegment parses a single crontab segment like '*/5' or '1-10/2'. When a step ('/' suffix) is present it is parsed with parseCrontabNumber; if the resulting step is <= 0 the field cannot produce a valid progression, so the parser throws 'crontab_step_must_be_positive'.

Source

Thrown at src/pages/WakeupTasksPage.tsx:482

  normalizeDayOfWeek: boolean,
) => {
  for (let value = start; value <= end; value += step) {
    target.add(normalizeDayOfWeek ? normalizeCrontabDayOfWeek(value) : value);
  }
};

const parseCrontabSegment = (
  segment: string,
  min: number,
  max: number,
  normalizeDayOfWeek: boolean,
  target: Set<number>,
) => {
  const [rawRange, rawStep] = segment.split('/');
  const rangePart = rawRange.trim();
  const step = rawStep ? parseCrontabNumber(rawStep) : 1;
  if (step <= 0) {
    throw new Error('crontab_step_must_be_positive');
  }

  if (rangePart === '*') {
    insertCrontabRange(target, min, max, step, normalizeDayOfWeek);
    return;
  }

  if (rangePart.includes('-')) {
    const [rawStart, rawEnd] = rangePart.split('-');
    const start = parseCrontabNumber(rawStart);
    const end = parseCrontabNumber(rawEnd);
    validateCrontabValue(start, min, max, normalizeDayOfWeek);
    validateCrontabValue(end, min, max, normalizeDayOfWeek);
    if (end < start) {
      throw new Error('crontab_range_invalid');
    }
    insertCrontabRange(target, start, end, step, normalizeDayOfWeek);
    return;

View on GitHub (pinned to 1ed8b77992)

Solutions

  1. Fix the crontab expression so the step after '/' is a positive integer (e.g. '*/5' instead of '*/0').
  2. If the step is computed, clamp it: Math.max(1, step) before building the expression.
  3. Validate the crontab input with parseCrontabExpression in a try/catch before saving, showing the raw code to the user.

Example fix

// before
const expr = `*/${intervalMinutes}`; // intervalMinutes = 0
// after
const step = Math.max(1, Math.floor(intervalMinutes || 1));
const expr = `*/${step}`;
Defensive patterns

Strategy: validation

Validate before calling

function validateCrontabExpression(expr) {
  try { parseCrontabExpression(expr); return true; } catch { return false; }
}
// or directly:
const step = Number(rawStep);
if (!Number.isInteger(step) || step <= 0) throw new Error('crontab_step_must_be_positive');

Type guard

const isValidCrontabStep = (s: unknown): s is number =>
  typeof s === 'number' && Number.isInteger(s) && s > 0;

Try / catch

try {
  const parsed = parseCrontabExpression(expr);
} catch (e) {
  if ((e as Error).message === 'crontab_step_must_be_positive') {
    setFieldError('step must be a positive integer, e.g. */5');
  }
}

Prevention

When it happens

Trigger: Calling parseCrontabSegment (indirectly via parseCrontabField/parseCrontabExpression, e.g. from the Wakeup Tasks crontab input) with a segment whose step is 0 or negative, such as '*/0', '*/-5', '1-10/0'.

Common situations: Users typing a crontab in the WakeupTasksPage editor and entering 0 or a negative number after '/'; programmatic generation of cron strings where the step is computed (e.g. interval/0 when interval defaults to 0).

Related errors


AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05). Data as JSON: /api/errors/a8420977114aeca8. Report an issue: GitHub.