goharbor/harbor · warning · lib/errors.Error

BAD_REQUEST

BAD_REQUEST

Error message

name cannot be empty

What it means

Registry validate() is called on create (and update) and first checks the registry name: an empty name yields BAD_REQUEST 'name cannot be empty'. The name is a required identifier for the registry entry, so the request is rejected before URL or health checks run.

Source

Thrown at src/controller/registry/controller.go:90

	}
}

type controller struct {
	regMgr reg.Manager
	repMgr replication.Manager
	proMgr project.Manager
}

func (c *controller) Create(ctx context.Context, registry *model.Registry) (int64, error) {
	if err := c.validate(ctx, registry); err != nil {
		return 0, err
	}
	return c.regMgr.Create(ctx, registry)
}

func (c *controller) validate(ctx context.Context, registry *model.Registry) error {
	if len(registry.Name) == 0 {
		return errors.New(nil).WithCode(errors.BadRequestCode).WithMessage("name cannot be empty")
	}
	if len(registry.Name) > 64 {
		return errors.New(nil).WithCode(errors.BadRequestCode).WithMessage("the max length of name is 64")
	}
	url, err := lib.ValidateHTTPURL(registry.URL)
	if err != nil {
		return err
	}
	registry.URL = url

	healthy, err := c.IsHealthy(ctx, registry)
	if err != nil {
		return err
	}
	if !healthy {
		return errors.New(nil).WithCode(errors.BadRequestCode).WithMessage("the registry is unhealthy")
	}
	registry.Status = model.Healthy

View on GitHub (pinned to 7b2fd08cc5)

Solutions

  1. Include a non-empty, descriptive name (1-64 chars) in the registry payload.
  2. Validate the payload client-side before the API call.
  3. Check for whitespace-only names - they pass this check but fail elsewhere; trim first.

Example fix

# before
POST /api/v2/registries
{"url": "https://docker.io", "type": "docker-hub"}

# after
POST /api/v2/registries
{"name": "docker-hub", "url": "https://docker.io", "type": "docker-hub"}
Defensive patterns

Strategy: validation

Validate before calling

func validRegistryName(name string) error {
    name = strings.TrimSpace(name)
    if name == "" { return fmt.Errorf("name cannot be empty") }
    if len(name) > 64 { return fmt.Errorf("the max length of name is 64") }
    return nil
}
// run before POST/PUT /api/v2/registries

Type guard

func hasRegistryName(r *model.Registry) bool {
    return r != nil && strings.TrimSpace(r.Name) != "
}

Try / catch

if _, err := regCtl.Create(ctx, r); err != nil {
    if liberrors.IsErr(err, liberrors.BadRequestCode) && err.Error() == "name cannot be empty" {
        // payload bug: add name field, do not retry unchanged
    }
    return err
}

Prevention

When it happens

Trigger: POST /api/v2/registries with a JSON body missing the name field or with name:""; automation templates omitting the name key.

Common situations: Copy-pasted payload edited to remove the name; Terraform/Ansible module variable left empty; client struct zero value marshalled.

Related errors


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