{"record":{"id":"61b00fe0dc3572b7","repo":"robfig/cron","slug":"multiple-optionals-may-not-be-configured","errorCode":null,"errorMessage":"multiple optionals may not be configured","messagePattern":"multiple optionals may not be configured","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"parser.go","lineNumber":80,"sourceCode":"//\n//  // Same as above, just excludes time fields\n//  specParser := NewParser(Dom | Month | Dow)\n//  sched, err := specParser.Parse(\"15 */3 *\")\n//\n//  // Same as above, just makes Dow optional\n//  specParser := NewParser(Dom | Month | DowOptional)\n//  sched, err := specParser.Parse(\"15 */3\")\n//\nfunc NewParser(options ParseOption) Parser {\n\toptionals := 0\n\tif options&DowOptional > 0 {\n\t\toptionals++\n\t}\n\tif options&SecondOptional > 0 {\n\t\toptionals++\n\t}\n\tif optionals > 1 {\n\t\tpanic(\"multiple optionals may not be configured\")\n\t}\n\treturn Parser{options}\n}\n\n// Parse returns a new crontab schedule representing the given spec.\n// It returns a descriptive error if the spec is not valid.\n// It accepts crontab specs and features configured by NewParser.\nfunc (p Parser) Parse(spec string) (Schedule, error) {\n\tif len(spec) == 0 {\n\t\treturn nil, fmt.Errorf(\"empty spec string\")\n\t}\n\n\t// Extract timezone if present\n\tvar loc = time.Local\n\tif strings.HasPrefix(spec, \"TZ=\") || strings.HasPrefix(spec, \"CRON_TZ=\") {\n\t\tvar err error\n\t\ti := strings.Index(spec, \" \")\n\t\teq := strings.Index(spec, \"=\")","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/robfig/cron/blob/bc59245fe10efaed9d51b56900192527ed733435/parser.go#L62-L98","documentation":"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.","triggerScenarios":"Calling NewParser with option flags combining both SecondOptional and DowOptional (e.g. NewParser(SecondOptional|DowOptional|Minute|Hour|...)).","commonSituations":"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.","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"],"exampleFix":"// before\np := cron.NewParser(cron.SecondOptional | cron.DowOptional | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Descriptor)\n// after\np := cron.NewParser(cron.SecondOptional | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Descriptor)","handlingStrategy":"validation","validationCode":"func validateParserOptions(opts uint64) error {\n\toptionals := 0\n\tif opts&cron.SecondOptional > 0 { optionals++ }\n\tif opts&cron.DowOptional > 0 { optionals++ }\n\tif optionals > 1 { return fmt.Errorf(\"at most one optional field bit allowed\") }\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["go","cron","parser","configuration","panic"],"backgroundTag":"mutually-exclusive-options","analyzedSha":"bc59245fe10efaed9d51b56900192527ed733435","analyzedAt":"2026-09-07T00:35:06.760Z","contentChangedAt":"2026-09-07T00:35:06.760Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}