robfig/cron · error

expected to fields, found

Error message

expected %d to %d fields, found %d: %s

What it means

When the parser allows a range of field counts (an optional field is configured), the spec must contain between min and max fields. This error reports the acceptable range, the actual count, and the raw fields when the count falls outside it.

Solutions

  1. Fix the spec to the correct number of fields shown in the error message
  2. Trim extra whitespace/tokens and rebuild the spec from its components
  3. Validate field count with strings.Fields before calling Parse

Example fix

// before
sched, err := p.Parse("0 5 * * 1 extra") // 6 fields to a max-6/optional parser... e.g. 7 tokens
// after
sched, err := p.Parse("0 5 * * 1")
Defensive patterns

Strategy: validation

Validate before calling

n := len(strings.Fields(spec))
if n < 5 || n > 6 {
	return fmt.Errorf("cron spec must have 5 or 6 fields, got %d", n)
}

Try / catch

sched, err := parser.Parse(spec)
if err != nil {
	return fmt.Errorf("check field count in %q: %w", spec, err)
}

Prevention

When it happens

Trigger: Passing fewer than min fields (e.g. 4 fields to a Minute..Dow + DowOptional parser) or more than max fields (e.g. 7 fields with seconds optional).

Common situations: Malformed user-entered cron strings with missing or duplicated fields; specs containing stray tokens that split into extra fields; logging/audit expressions pasted with extra columns.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of robfig/cron@bc59245fe1 (2026-09-07). Data as JSON: /api/errors/ba8bf30f59dda2bf. Report an issue: GitHub.

Appendix: source

Thrown at parser.go:189

	if optionals > 1 {
		return nil, fmt.Errorf("multiple optionals may not be configured")
	}

	// Figure out how many fields we need
	max := 0
	for _, place := range places {
		if options&place > 0 {
			max++
		}
	}
	min := max - optionals

	// Validate number of fields
	if count := len(fields); count < min || count > max {
		if min == max {
			return nil, fmt.Errorf("expected exactly %d fields, found %d: %s", min, count, fields)
		}
		return nil, fmt.Errorf("expected %d to %d fields, found %d: %s", min, max, count, fields)
	}

	// Populate the optional field if not provided
	if min < max && len(fields) == min {
		switch {
		case options&DowOptional > 0:
			fields = append(fields, defaults[5]) // TODO: improve access to default
		case options&SecondOptional > 0:
			fields = append([]string{defaults[0]}, fields...)
		default:
			return nil, fmt.Errorf("unknown optional field")
		}
	}

	// Populate all fields not part of options with their defaults
	n := 0
	expandedFields := make([]string, len(places))
	copy(expandedFields, defaults)

View on GitHub (pinned to bc59245fe1)