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.HealthyView on GitHub (pinned to 7b2fd08cc5)
Solutions
- Include a non-empty, descriptive name (1-64 chars) in the registry payload.
- Validate the payload client-side before the API call.
- 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
- Trim and require name in payload templates and IaC modules.
- Add client-side schema checks (JSON schema minLength: 1).
- Reject zero-value structs before marshalling.
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
- Only can have one trace exporter at a time
- Error: storage driver %s is not supported, only the followin
- Error: storage driver %s is not supported, only the followin
- BAD_REQUEST
- BAD_REQUEST
AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16).
Data as JSON: /api/errors/89a66309dfa589d1.
Report an issue: GitHub.