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
- Use a 5-field unix cron ('m h dom mon dow') or 6-field with leading seconds ('s m h dom mon dow').
- Drop the year field if you copied a 7-field quartz expression.
- If you have a 7-field expression, strip the trailing year field programmatically.
- 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
- Validate field count in the UI before submission with the same 5/6 rule.
- If accepting quartz input, strip the trailing year field programmatically.
- Pre-test expressions with a tool like crontab.guru before persisting.
- Document the supported cron dialect (unix 5-field, optional seconds) in the user-facing docs.
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
- Unknown IANA timezone: ${JSON.stringify(schedule.timezone)}
- Invalid cron expression ${JSON.stringify(expression)}: ${(er
- jitterRatio must be at least 0 and below 1, got ${lifecycleO
- ${key} must be a positive number of seconds, got ${value}
- concurrencyMode must be 'sequential' or 'concurrent', got ${
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/0e2c2f818256c4fd.
Report an issue: GitHub.