jlcodes99/cockpit-tools · info

crontab_no_values

crontab_no_values

Error message

crontab_no_values

What it means

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).

Solutions

  1. Provide at least one concrete value or range in the field (e.g. '0' or '*/5').
  2. If extending parseCrontabSegment, ensure every accepted syntax inserts at least one value or throws its own specific error.
  3. Keep the try/catch around parseCrontabExpression at the form level and map 'crontab_no_values' to a user-facing message.
Defensive patterns

Strategy: try-catch

Type guard

const fieldHasValues = (values: Set<number>): boolean => values.size > 0;

Try / catch

try {
  const parsed = parseCrontabExpression(expr);
} catch (e) {
  if ((e as Error).message === 'crontab_no_values') {
    setFieldError('field produced no values; provide at least one value or range');
  }
}

Prevention

When it happens

Trigger: 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).

Common situations: 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).

Related errors


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

Appendix: source

Thrown at src/pages/WakeupTasksPage.tsx:543

    insertCrontabRange(values, min, max, 1, normalizeDayOfWeek);
    return { values, wildcard: true };
  }

  const values = new Set<number>();
  const segments = trimmed.split(',');
  if (segments.length === 0) {
    throw new Error('crontab_field_empty');
  }
  segments.forEach((segment) => {
    const normalizedSegment = segment.trim();
    if (!normalizedSegment) {
      throw new Error('crontab_segment_empty');
    }
    parseCrontabSegment(normalizedSegment, min, max, normalizeDayOfWeek, values);
  });

  if (values.size === 0) {
    throw new Error('crontab_no_values');
  }
  return { values, wildcard: false };
};

const parseCrontabExpression = (expr: string): ParsedCrontab => {
  const parts = expr.trim().split(/\s+/);
  if (parts.length !== 5) {
    throw new Error('crontab_parts_must_be_five');
  }

  return {
    minute: parseCrontabField(parts[0], 0, 59, false),
    hour: parseCrontabField(parts[1], 0, 23, false),
    dayOfMonth: parseCrontabField(parts[2], 1, 31, false),
    month: parseCrontabField(parts[3], 1, 12, false),
    dayOfWeek: parseCrontabField(parts[4], 0, 7, true),
  };
};

View on GitHub (pinned to 1ed8b77992)