{"record":{"id":"b97d50cb31ee5c36","repo":"robfig/cron","slug":"unknown-optional-field","errorCode":null,"errorMessage":"unknown optional field","messagePattern":"unknown optional field","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"parser.go","lineNumber":200,"sourceCode":"\tmin := max - optionals\n\n\t// Validate number of fields\n\tif count := len(fields); count < min || count > max {\n\t\tif min == max {\n\t\t\treturn nil, fmt.Errorf(\"expected exactly %d fields, found %d: %s\", min, count, fields)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"expected %d to %d fields, found %d: %s\", min, max, count, fields)\n\t}\n\n\t// Populate the optional field if not provided\n\tif min < max && len(fields) == min {\n\t\tswitch {\n\t\tcase options&DowOptional > 0:\n\t\t\tfields = append(fields, defaults[5]) // TODO: improve access to default\n\t\tcase options&SecondOptional > 0:\n\t\t\tfields = append([]string{defaults[0]}, fields...)\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unknown optional field\")\n\t\t}\n\t}\n\n\t// Populate all fields not part of options with their defaults\n\tn := 0\n\texpandedFields := make([]string, len(places))\n\tcopy(expandedFields, defaults)\n\tfor i, place := range places {\n\t\tif options&place > 0 {\n\t\t\texpandedFields[i] = fields[n]\n\t\t\tn++\n\t\t}\n\t}\n\treturn expandedFields, nil\n}\n\nvar standardParser = NewParser(\n\tMinute | Hour | Dom | Month | Dow | Descriptor,","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/robfig/cron/blob/bc59245fe10efaed9d51b56900192527ed733435/parser.go#L182-L218","documentation":"When a spec has the minimum number of fields and the parser must pad the missing optional one, normalizeFields switches on which optional bit is configured. If neither DowOptional nor SecondOptional is set (i.e. padding was attempted without any optional field) it returns this internal error. It is effectively an invariant violation in option inference.","triggerScenarios":"A Parser whose option mask was manipulated or combined so that min<max while neither optional bit is present — normally unreachable through the public NewParser, which prevents multiple/zero-optional mismatches; hand-constructed Parser structs.","commonSituations":"Code building cron.Parser{options} directly instead of via NewParser; combining option bits programmatically producing inconsistent masks.","solutions":["Always construct parsers via cron.NewParser instead of instantiating the Parser struct directly","Audit code that combines option bitmasks so optional bits stay consistent","If hit despite correct usage, report it as a library bug"],"exampleFix":"// before\np := cron.Parser{options: bits} // hand-built mask\n// after\np := cron.NewParser(bits)","handlingStrategy":"type-guard","validationCode":"var _ = cron.NewParser // ensure parsers are built via NewParser","typeGuard":"func isWellFormedParser(p cron.Parser) bool {\n\t// A well-formed parser is constructed by NewParser and never triggers\n\t// the unknown-optional-field padding path.\n\treturn true // enforce by construction: use cron.NewParser(bits)\n}","tryCatchPattern":"sched, err := parser.Parse(spec)\nif err != nil {\n\treturn fmt.Errorf(\"parser configuration error: %w\", err)\n}","preventionTips":["Never construct cron.Parser struct literals directly","Use cron.NewParser for all parser construction","Add a regression test for every parser option mask you ship"],"tags":["go","cron","parser","invariant","internal"],"backgroundTag":"internal-invariant-violation","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"}