goharbor/harbor · error · lib/errors.Error

BAD_REQUEST

BAD_REQUEST

Error message

empty name

What it means

Policy.Validate (src/controller/replication/model/model.go:67) requires a non-empty Name when creating or updating a replication policy; an empty name is rejected with BAD_REQUEST (HTTP 400). It is the first check in a chain that also validates registries, filters, namespace, and trigger.

Source

Thrown at src/controller/replication/model/model.go:67

	CopyByChunk               bool            `json:"copy_by_chunk"`
	SingleActiveReplication   bool            `json:"single_active_replication"`
}

// IsScheduledTrigger returns true when the policy is scheduled trigger and enabled
func (p *Policy) IsScheduledTrigger() bool {
	if !p.Enabled {
		return false
	}
	if p.Trigger == nil {
		return false
	}
	return p.Trigger.Type == model.TriggerTypeScheduled
}

// Validate the policy
func (p *Policy) Validate() error {
	if len(p.Name) == 0 {
		return errors.New(nil).WithCode(errors.BadRequestCode).WithMessage("empty name")
	}
	var srcRegistryID, dstRegistryID int64
	if p.SrcRegistry != nil {
		srcRegistryID = p.SrcRegistry.ID
	}
	if p.DestRegistry != nil {
		dstRegistryID = p.DestRegistry.ID
	}

	// one of the source registry and destination registry must be Harbor itself
	if srcRegistryID != 0 && dstRegistryID != 0 ||
		srcRegistryID == 0 && dstRegistryID == 0 {
		return errors.New(nil).WithCode(errors.BadRequestCode).
			WithMessage("either src_registry or dest_registry should be empty and the other one shouldn't be empty")
	}

	// valid the filters
	for _, f := range p.Filters {

View on GitHub (pinned to 7b2fd08cc5)

Solutions

  1. Add a non-empty name to the request body and retry
  2. If using a generated client, verify the name field is actually serialized (check for omitempty on an empty string)
  3. Add client-side schema validation requiring name before calling the API

Example fix

// before
POST /api/v2.0/replication/policies
{"name": "", "src_registry": {"id": 1}}  // 400: empty name

// after
{"name": "prod-to-dr", "src_registry": {"id": 1}}
Defensive patterns

Strategy: validation

Validate before calling

func validatePolicyPayload(p *PolicyPayload) error {
    if strings.TrimSpace(p.Name) == "" {
        return errors.New("policy name is required")
    }
    return nil
}

Type guard

func isEmptyNameErr(err error) bool {
    return errors.IsErr(err, errors.BadRequestCode) && strings.Contains(err.Error(), "empty name")
}

Try / catch

if err := policyCtl.Create(ctx, policy); err != nil {
    if errors.IsErr(err, errors.BadRequestCode) && strings.Contains(err.Error(), "empty name") {
        // surface a form error; do not retry
    }
}

Prevention

When it happens

Trigger: POST /api/v2.0/replication/policies or PUT .../policies/{id} with a body whose name field is missing, empty, or only whitespace; building the policy payload programmatically and forgetting to set Name.

Common situations: Generated API clients with omitempty dropping an unset name; UI form submitted before the name field was filled; JSON payload hand-edited and the name key removed.

Related errors


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