goharbor/harbor · error · lib/errors.Error
BAD_REQUEST
BAD_REQUEST
Error message
invalid cron string for scheduled tag retention: %s, error: %v
What it means
BAD_REQUEST error from Metadata.ValidateRetentionPolicy when a policy's trigger is of kind Schedule, its settings contain the cron key, and the string fails utils.ValidateCronString. It is pure input validation fired at policy create/update time, before any scheduling happens.
Source
Thrown at src/pkg/retention/policy/models.go:73
// Trigger about how to launch the policy
Trigger *Trigger `json:"trigger" valid:"Required"`
// Which scope the policy will be applied to
Scope *Scope `json:"scope" valid:"Required"`
}
// ValidateRetentionPolicy validate the retention policy
func (m *Metadata) ValidateRetentionPolicy() error {
// currently only validate the cron string of retention policy
if m.Trigger != nil {
if m.Trigger.Kind == TriggerKindSchedule && m.Trigger.Settings != nil {
cronItem, ok := m.Trigger.Settings[TriggerSettingsCron]
if ok {
if cronStr, isStr := cronItem.(string); isStr {
if len(cronStr) > 0 {
if err := utils.ValidateCronString(cronStr); err != nil {
return errors.New(nil).WithCode(errors.BadRequestCode).
WithMessagef("invalid cron string for scheduled tag retention: %s, error: %v", cronStr, err)
}
}
} else {
return errors.New(nil).WithCode(errors.BadRequestCode).
WithMessage("invalid cron type for scheduled tag retention: must be a string")
}
}
}
}
return nil
}
// Valid Valid
func (m *Metadata) Valid(v *validation.Validation) {
if m.Trigger == nil {
_ = v.SetError("Trigger", "Can not be empty")
returnView on GitHub (pinned to 7b2fd08cc5)
Solutions
- Correct the cron string to a valid expression accepted by Harbor's validator (e.g. '0 0 0 * * *' style 6-field)
- Run the same validation client-side before submitting, e.g. with an equivalent cron parser, to fail fast
- Use '@daily'/'@weekly' style aliases if supported instead of hand-written fields
Example fix
// before
settings := map[string]any{"cron": "99 99 * * *"}
// after
settings := map[string]any{"cron": "0 0 0 * * 6"} Defensive patterns
Strategy: validation
Validate before calling
// Fail fast on cron syntax before policy submission
if err := utils.ValidateCronString(cronStr); err != nil {
return fmt.Errorf("bad cron %q: %v", cronStr, err)
} Prevention
- Reuse the same cron library/version Harbor validates with on the client side
- Prefer fixed known-good expressions ('0 0 0 * * *') over hand-built ones
- Test cron strings in a scratch policy before automating them fleet-wide
When it happens
Trigger: POST/PUT of a retention policy with Trigger.Kind == Schedule and Settings["cron"] set to an invalid expression (wrong field count, bad ranges like '0 25 * * *', unsupported macros); using a 5-field expression where Harbor's validator expects a specific format or vice versa.
Common situations: Copy-pasting cron strings from crontab (5 fields) or Quartz (7 fields) formats that don't match what ValidateCronString accepts; typos in day/month names; setting cron with leading/trailing whitespace.
Related errors
AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16).
Data as JSON: /api/errors/b67af4475c89a874.
Report an issue: GitHub.