robfig/cron · critical
multiple optionals may not be configured
Error message
multiple optionals may not be configured
What it means
NewParser panics when more than one optional field bit (SecondOptional, DowOptional) is set in the option mask. The parser can only handle one optional field because the normalization logic can only pad one missing field. It is a programming error, so it panics instead of returning an error.
Solutions
- Remove one of SecondOptional or DowOptional from the NewParser option mask
- Use two separate Parser instances if both flexible forms are needed
- Gate the option construction on configuration so only one optional bit can ever be set
Example fix
// before p := cron.NewParser(cron.SecondOptional | cron.DowOptional | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Descriptor) // after p := cron.NewParser(cron.SecondOptional | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Descriptor)
Defensive patterns
Strategy: validation
Validate before calling
func validateParserOptions(opts uint64) error {
optionals := 0
if opts&cron.SecondOptional > 0 { optionals++ }
if opts&cron.DowOptional > 0 { optionals++ }
if optionals > 1 { return fmt.Errorf("at most one optional field bit allowed") }
return nil
} Prevention
- Define parser option constants once in a central helper
- Never OR together both SecondOptional and DowOptional
- Write a unit test asserting NewParser does not panic for your chosen mask
When it happens
Trigger: Calling NewParser with option flags combining both SecondOptional and DowOptional (e.g. NewParser(SecondOptional|DowOptional|Minute|Hour|...)).
Common situations: Developers copying parser option examples add both optional bits to support flexible 5/6-field cron specs, not realizing they are mutually exclusive. Merging feature flags from two call sites can also accumulate both bits.
Related errors
- parser does not accept descriptors
- provided bad location
- expected exactly fields, found
- expected to fields, found
- unknown optional field
AI-assisted analysis of robfig/cron@bc59245fe1 (2026-09-07).
Data as JSON: /api/errors/61b00fe0dc3572b7.
Report an issue: GitHub.
Appendix: source
Thrown at parser.go:80
//
// // Same as above, just excludes time fields
// specParser := NewParser(Dom | Month | Dow)
// sched, err := specParser.Parse("15 */3 *")
//
// // Same as above, just makes Dow optional
// specParser := NewParser(Dom | Month | DowOptional)
// sched, err := specParser.Parse("15 */3")
//
func NewParser(options ParseOption) Parser {
optionals := 0
if options&DowOptional > 0 {
optionals++
}
if options&SecondOptional > 0 {
optionals++
}
if optionals > 1 {
panic("multiple optionals may not be configured")
}
return Parser{options}
}
// Parse returns a new crontab schedule representing the given spec.
// It returns a descriptive error if the spec is not valid.
// It accepts crontab specs and features configured by NewParser.
func (p Parser) Parse(spec string) (Schedule, error) {
if len(spec) == 0 {
return nil, fmt.Errorf("empty spec string")
}
// Extract timezone if present
var loc = time.Local
if strings.HasPrefix(spec, "TZ=") || strings.HasPrefix(spec, "CRON_TZ=") {
var err error
i := strings.Index(spec, " ")
eq := strings.Index(spec, "=")View on GitHub (pinned to bc59245fe1)