goharbor/harbor · error · ConflictError

CONFLICT

CONFLICT

Error message

rule %d is conflict with rule %d

What it means

Duplicate-rule detector in checkRuleConflict (used by both create and update retention endpoints): each rule is serialized to JSON (with its ID zeroed) and used as a map key; if an identical rule body was already seen, the new rule conflicts with the earlier one and the policy is rejected. Two rules are 'the same' when every configured field except the ID matches.

Solutions

  1. Remove the duplicated rule — an identical rule adds nothing over the first copy
  2. If near-duplicates were intended, differentiate them by repository selector, tag selector, scope level, or parameters
  3. Review the whole rules array for copies before resubmitting
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at src/server/v2.0/handler/retention.go:242 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16). Data as JSON: /api/errors/27e0dd5ef3d18ee4. Report an issue: GitHub.

Appendix: source

Thrown at src/server/v2.0/handler/retention.go:242

	}

	if err := r.requirePolicyAccess(ctx, p); err != nil {
		return r.SendError(ctx, err)
	}

	if err := r.retentionCtl.UpdateRetention(ctx, p); err != nil {
		return r.SendError(ctx, err)
	}
	return operation.NewUpdateRetentionOK()
}

func (r *retentionAPI) checkRuleConflict(p *policy.Metadata) error {
	temp := make(map[string]int)
	for n, rule := range p.Rules {
		rule.ID = 0
		bs, _ := json.Marshal(rule)
		if old, exists := temp[string(bs)]; exists {
			return fmt.Errorf("rule %d is conflict with rule %d", n, old)
		}
		temp[string(bs)] = n
		rule.ID = n
	}
	return nil
}

func (r *retentionAPI) DeleteRetention(ctx context.Context, params operation.DeleteRetentionParams) middleware.Responder {
	p, err := r.retentionCtl.GetRetention(ctx, params.ID)
	if err != nil {
		return r.SendError(ctx, errors.BadRequestError(err))
	}
	err = r.requireAccess(ctx, p, rbac.ActionDelete)
	if err != nil {
		return r.SendError(ctx, err)
	}

	if err = r.retentionCtl.DeleteRetention(ctx, params.ID); err != nil {

View on GitHub (pinned to 7b2fd08cc5)