{"record":{"id":"717f7fe506299b06","repo":"goharbor/harbor","slug":"bad-request-717f7f","errorCode":"BAD_REQUEST","errorMessage":"invalid cron string for scheduled preheat: %s, error: %v","messagePattern":"invalid cron string for scheduled preheat: (.+?), error: (.+?)","errorType":"validation","errorClass":"errors.Error","httpStatus":400,"severity":"error","filePath":"src/pkg/p2p/preheat/models/policy/policy.go","lineNumber":126,"sourceCode":"// TriggerType represents the type of trigger.\ntype TriggerType = string\n\n// Trigger holds the trigger info.\ntype Trigger struct {\n\t// The preheat policy trigger type. The valid values ar manual, scheduled.\n\tType     TriggerType `json:\"type\"`\n\tSettings struct {\n\t\t// The cron string for scheduled trigger.\n\t\tCron string `json:\"cron,omitempty\"`\n\t} `json:\"trigger_setting,omitempty\"`\n}\n\n// ValidatePreheatPolicy validate preheat policy\nfunc (s *Schema) ValidatePreheatPolicy() error {\n\t// currently only validate cron string of preheat policy\n\tif s.Trigger != nil && s.Trigger.Type == TriggerTypeScheduled && len(s.Trigger.Settings.Cron) > 0 {\n\t\tif err := utils.ValidateCronString(s.Trigger.Settings.Cron); err != nil {\n\t\t\treturn errors.New(nil).WithCode(errors.BadRequestCode).\n\t\t\t\tWithMessagef(\"invalid cron string for scheduled preheat: %s, error: %v\", s.Trigger.Settings.Cron, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Encode encodes policy schema.\nfunc (s *Schema) Encode() error {\n\tif s.Filters != nil {\n\t\tfilterStr, err := json.Marshal(s.Filters)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ts.FiltersStr = string(filterStr)\n\t}\n\n\tif s.Trigger != nil {","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/src/pkg/p2p/preheat/models/policy/policy.go#L108-L144","documentation":"Schema.ValidatePreheatPolicy rejects a P2P preheat policy whose trigger is scheduled but whose cron string is invalid. Harbor parses cron with a 6-field parser (second minute hour day-of-month month day-of-week) and additionally requires the first field (seconds) to be the literal 0 — so both malformed strings and non-zero seconds fail. Maps to BAD_REQUEST when creating/updating policies (POST/PUT /api/v2.0/projects/{project}/preheat/policies).","triggerScenarios":"POST/PUT preheat policy with trigger {\"type\": \"scheduled\", \"trigger_setting\": {\"cron\": \"*/5 * * * *\"}} — a classic 5-field crontab string; or 6 fields with a non-zero seconds field like \"30 */5 * * * *\"; or invalid ranges/step syntax per robfig/cron.","commonSituations":"Copying standard 5-field crontab entries from Linux docs; assuming Harbor uses the same cron dialect as Dragonfly/Kraken; harbor replicate-schedule muscle memory where seconds are allowed; step values on day-of-week names.","solutions":["Use exactly 6 fields with a leading 0 for seconds, e.g. \"0 */5 * * * *\" fires every 5 minutes.","Validate the string with the same rules client-side: 6 fields, parseable, first field == \"0\".","If the policy only needs manual or event-based preheat, use trigger type \"manual\"/\"event\" instead of \"scheduled\"."],"exampleFix":"# before\ncurl -X POST https://harbor/api/v2.0/projects/1/preheat/policies -d '{\"name\": \"p\", \"provider_id\": 1, \"trigger\": {\"type\": \"scheduled\", \"trigger_setting\": {\"cron\": \"*/5 * * * *\"}}}'\n# after\ncurl -X POST https://harbor/api/v2.0/projects/1/preheat/policies -d '{\"name\": \"p\", \"provider_id\": 1, \"trigger\": {\"type\": \"scheduled\", \"trigger_setting\": {\"cron\": \"0 */5 * * * *\"}}}'","handlingStrategy":"validation","validationCode":"// Replicate Harbor's cron rules before submitting a scheduled policy\nfunc validPreheatCron(c string) error {\n    if len(c) == 0 { return errors.New(\"cron string is required\") }\n    if _, err := utils.CronParser().Parse(c); err != nil { return err } // 6 fields: sec min hour dom mon dow\n    p := strings.Split(c, \" \")\n    if len(p) == 6 && p[0] != \"0\" { return errors.New(\"seconds field must be 0\") }\n    return nil\n}","typeGuard":"function isScheduledPolicyWithBadCron(p) {\n  return p?.trigger?.type === 'scheduled' && !validCron6(p.trigger.trigger_setting?.cron);\n}","tryCatchPattern":"On HTTP 400 'invalid cron string for scheduled preheat', parse the returned error detail, coerce the cron to 6 fields with seconds=0, and resubmit the policy once.","preventionTips":["Memorize the Harbor rule: 6 fields, first field (seconds) must be literal 0.","Never paste 5-field crontab entries directly into preheat policies.","Add a cron-lint step to policy-as-code pipelines."],"tags":["p2p-preheat","cron","scheduler","validation","harbor"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}