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")
		return

View on GitHub (pinned to 7b2fd08cc5)

Solutions

  1. Correct the cron string to a valid expression accepted by Harbor's validator (e.g. '0 0 0 * * *' style 6-field)
  2. Run the same validation client-side before submitting, e.g. with an equivalent cron parser, to fail fast
  3. 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

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.