n8n-io/n8n · error · InvalidScheduleError

Cron expression must have ${MIN_CRON_FIELD_COUNT} or ${MAX_C

Error message

Cron expression must have ${MIN_CRON_FIELD_COUNT} or ${MAX_CRON_FIELD_COUNT} fields (seconds optional), got ${fieldCount}: ${JSON.stringify(expression)}

What it means

Thrown by validateCron when the cron expression does not have 5 or 6 fields (6 = with seconds). MIN_CRON_FIELD_COUNT and MAX_CRON_FIELD_COUNT bound the field count before the expression is handed to CronExpressionParser, so a parser-specific error is replaced with a clear field-count message. The check runs on .trim().split(/\s+/) length.

Source

Thrown at packages/@n8n/scheduler/src/core/recurrence/kinds/cron.ts:36

/**
 * Checks that a cron schedule is usable: a 5- or 6-field expression in a real
 * timezone. Also used for `recurring_cron`, which reuses the cron expression.
 * @param schedule The cron (or recurring_cron) schedule to check.
 * @throws {InvalidScheduleError} When the expression or timezone is invalid.
 */
export function validateCron(schedule: CronSchedule | RecurringCronSchedule): void {
	// Raw DB rows may reach here untyped, so check the runtime type before use.
	const expression: unknown = schedule.cronExpression;
	if (typeof expression !== 'string') {
		throw new InvalidScheduleError(
			`${schedule.kind}.cronExpression must be a string, got ${JSON.stringify(expression)}`,
		);
	}

	const fieldCount = expression.trim().split(/\s+/).length;
	if (fieldCount < MIN_CRON_FIELD_COUNT || fieldCount > MAX_CRON_FIELD_COUNT) {
		throw new InvalidScheduleError(
			`Cron expression must have ${MIN_CRON_FIELD_COUNT} or ${MAX_CRON_FIELD_COUNT} fields (seconds optional), got ${fieldCount}: ${JSON.stringify(expression)}`,
		);
	}

	// A null timezone is the instance default, resolved by the caller.
	if (schedule.timezone !== null && !IANAZone.isValidZone(schedule.timezone)) {
		throw new InvalidScheduleError(`Unknown IANA timezone: ${JSON.stringify(schedule.timezone)}`);
	}

	try {
		CronExpressionParser.parse(expression, { tz: schedule.timezone ?? 'UTC' });
	} catch (error) {
		throw new InvalidScheduleError(
			`Invalid cron expression ${JSON.stringify(expression)}: ${(error as Error).message}`,
		);
	}
}

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Use a 5-field unix cron ('m h dom mon dow') or 6-field with leading seconds ('s m h dom mon dow').
  2. Drop the year field if you copied a 7-field quartz expression.
  3. If you have a 7-field expression, strip the trailing year field programmatically.
  4. Validate field count in the UI before submission.

Example fix

// before
validateCron({ kind: 'cron', cronExpression: '0 0 * * * * *', timezone: 'UTC' }); // 7 fields -> throws

// after - drop the year field for quartz-style input
function toUnixCron(expr: string): string {
  const fields = expr.trim().split(/\s+/);
  return fields.length === 7 ? fields.slice(0, 6).join(' ') : expr;
}
validateCron({ kind: 'cron', cronExpression: toUnixCron(userInput), timezone: 'UTC' });
Defensive patterns

Strategy: validation

Validate before calling

function normalizeCronFields(expr: string): string {
  const fields = expr.trim().split(/\s+/);
  if (fields.length === 7) return fields.slice(0, 6).join(' '); // drop quartz year
  if (fields.length === 5 || fields.length === 6) return expr;
  throw new Error(`Cron expression must have 5 or 6 fields, got ${fields.length}`);
}

Type guard

function hasValidFieldCount(expr: string): boolean {
  const n = expr.trim().split(/\s+/).length;
  return n === 5 || n === 6;
}

Prevention

When it happens

Trigger: An expression like '* * * *' (4 fields), '* * * * * * *' (7 fields), an empty string (1 field after split on '' - actually yields ['']), or an expression using tabs/multiple spaces (split on /\s+/ normalizes those).

Common situations: User pastes a 7-field cron with year field (croniter-style) into a 5/6-field scheduler; a missing field typo; an expression built by concatenation that dropped a field; locale confusion between 5-field unix cron and quartz 6/7-field cron.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/0e2c2f818256c4fd. Report an issue: GitHub.