aaif-goose/goose · warning

Expected 5 or 6 fields

Error message

Expected 5 or 6 fields

What it means

describeCron() splits the cron expression on whitespace and only hands 5-field (standard) or 6-field (with seconds) expressions to cronstrue. Any other field count — 4, 7+, or an empty-ish string that still splits to the wrong count — throws 'Expected 5 or 6 fields' before cronstrue ever runs. Note parseCron() is more forgiving (it returns a 'custom' period via normalizeCronParts returning null), so this is specific to the human-readable description path.

Source

Thrown at ui/desktop/src/utils/cronSchedule.ts:90

  }
  const parsedDay = parseInt(value, 10);
  if (parsedDay < 1 || parsedDay > max) {
    return null;
  }
  return parsedDay.toString();
};

const asCustomCron = (parts: string[]): ParsedCron => {
  const [second, minute, hour, dayOfMonth, month, dayOfWeek] = parts;
  return { period: 'custom', second, minute, hour, dayOfMonth, month, dayOfWeek };
};

export const describeCron = (cron: string): string => {
  const parts = cron.trim().split(/\s+/);
  if (parts.length === 5 || parts.length === 6) {
    return cronstrue.toString(parts.join(' '));
  }
  throw new Error('Expected 5 or 6 fields');
};

export const parseCron = (cron: string): ParsedCron => {
  if (!cron.trim()) {
    return defaultParsedCron;
  }

  const parts = normalizeCronParts(cron);
  if (!parts) {
    return { ...defaultParsedCron, period: 'custom' };
  }

  const [second, minute, hour, dayOfMonth, month, dayOfWeek] = parts;

  if (!isSingleNumericValue(second)) {
    return asCustomCron(parts);
  }

View on GitHub (pinned to 3810898a74)

Solutions

  1. Normalize the expression to exactly 5 fields (minute hour dom month dow) or 6 with a leading seconds field before calling describeCron
  2. Expand named schedules (@daily, @hourly) to their field form first
  3. Strip appended timezone/extra tokens before passing the string
  4. Prefer parseCron()+field-level rendering for arbitrary user input; it never throws this error

Example fix

// before
describeCron('0 0 12 * * ? 2026'); // 7 fields -> throws
// after
describeCron('0 12 * * ?'); // 6 fields (sec min hour dom mon dow)
Defensive patterns

Strategy: type-guard

Validate before calling

const fields = cron.trim().split(/\s+/).filter(Boolean);
if (fields.length !== 5 && fields.length !== 6) {
  // reject/normalize input before describeCron
  return 'Invalid schedule';
}

Type guard

const isFiveOrSixFieldCron = (cron: string): boolean => {
  const n = cron.trim().split(/\s+/).filter(Boolean).length;
  return n === 5 || n === 6;
};

Try / catch

try {
  label = describeCron(cron);
} catch (e) {
  if (e instanceof Error && e.message === 'Expected 5 or 6 fields') {
    label = cron; // show raw expression instead of crashing the settings UI
  } else throw e;
}

Prevention

When it happens

Trigger: Calling describeCron('0 0 * * * * *') (7 fields, e.g. Quartz with year); describeCron('0 12 * *') (missing a field); describeCron('@daily') (named schedules are not expanded here); double-space strings are fine (split on \s+) but stray tokens like trailing words break the count.

Common situations: Schedules UI receiving user-typed cron; migrated data containing Quartz 7-field expressions; copy-paste from tutorials with @hourly macros; schedulers that prefix or append extra tokens (timezone names like 'UTC' as a 6th/7th word).

Related errors


AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16). Data as JSON: /api/errors/8c841ffda0f13b13. Report an issue: GitHub.