goharbor/harbor · error
the name of the repository cannot be null
Error message
the name of the repository cannot be null
What it means
Thrown by the Harbor registry adapter's PrepareForPush (src/pkg/reg/adapter/harbor/base/adapter.go:154) during replication/copy into a Harbor or Harbor-compatible registry. It iterates the []*model.Resource to group artifacts by project, and rejects any resource whose Metadata.Repository is set but whose Name is the empty string. The library throws it because project grouping (strings.Split(name, "/")[0]) is meaningless without a repository name.
Source
Thrown at src/pkg/reg/adapter/harbor/base/adapter.go:154
return info, nil
}
// PrepareForPush creates projects
func (a *Adapter) PrepareForPush(resources []*model.Resource) error {
projects := map[string]*Project{}
for _, resource := range resources {
if resource == nil {
return errors.New("the resource cannot be null")
}
if resource.Metadata == nil {
return errors.New("the metadata of resource cannot be null")
}
if resource.Metadata.Repository == nil {
return errors.New("the repository of resource cannot be null")
}
if len(resource.Metadata.Repository.Name) == 0 {
return errors.New("the name of the repository cannot be null")
}
paths := strings.Split(resource.Metadata.Repository.Name, "/")
projectName := paths[0]
// handle the public properties
metadata := abstractPublicMetadata(resource.Metadata.Repository.Metadata)
pro, exist := projects[projectName]
if exist {
metadata = mergeMetadata(pro.Metadata, metadata)
}
projects[projectName] = &Project{
Name: projectName,
Metadata: metadata,
}
}
// Create a list of the project names.
var ps []stringView on GitHub (pinned to 7b2fd08cc5)
Solutions
- Inspect the replication rule's destination namespace/repository override and make sure it yields a non-empty 'project/repository' string.
- If you build the resources yourself, set resource.Metadata.Repository.Name from the source repository (e.g. 'library/ubuntu') before calling PrepareForPush.
- Log resource.Metadata before the call to find which element has the empty name; the loop fails on the first bad element, not necessarily the whole batch.
- Guard the slice up front with a validation pass (see defense) so the error is reported with the failing index.
Example fix
// before
resources = append(resources, &model.Resource{
Metadata: &model.ResourceMetadata{
Repository: &model.Repository{}, // Name left empty
},
})
err := dstAdapter.PrepareForPush(resources)
// after
resources = append(resources, &model.Resource{
Metadata: &model.ResourceMetadata{
Repository: &model.Repository{Name: "library/ubuntu"},
},
})
err := dstAdapter.PrepareForPush(resources) Defensive patterns
Strategy: validation
Validate before calling
func validatePushResources(resources []*model.Resource) error {
for i, r := range resources {
if r == nil {
return fmt.Errorf("resources[%d]: nil resource", i)
}
if r.Metadata == nil {
return fmt.Errorf("resources[%d]: nil metadata", i)
}
if r.Metadata.Repository == nil {
return fmt.Errorf("resources[%d]: nil repository", i)
}
if r.Metadata.Repository.Name == "" {
return fmt.Errorf("resources[%d]: empty repository name", i)
}
}
return nil
}
// call before adapter.PrepareForPush(resources)
if err := validatePushResources(resources); err != nil { return err } Type guard
func hasValidRepoName(r *model.Resource) bool {
return r != nil && r.Metadata != nil &&
r.Metadata.Repository != nil && r.Metadata.Repository.Name != ""
} Try / catch
if err := dstAdapter.PrepareForPush(resources); err != nil {
log.Errorf("prepare push failed: %v", err)
return fmt.Errorf("prepare resources before push: %w", err)
} Prevention
- Build resources with a single constructor that always sets Metadata.Repository.Name from the source artifact.
- Never append nil to a resource slice; abort on fetch failure.
- Validate the slice at the pipeline boundary with an index-reporting helper.
- Unit-test the destination-name template against empty results.
When it happens
Trigger: Calling adapter.PrepareForPush(resources) where some resources[i].Metadata.Repository.Name == "". In Harbor this happens when a replication rule's repository override/destination naming produces an empty string, or when a custom caller assembles model.Resource values without copying the repository name from the source artifact.
Common situations: Replication rule with a badly formed destination repository override; custom code building model.Resource from manifests and forgetting to set Metadata.Repository.Name; nil-vs-empty confusion after filtering artifacts out of the resource list.
Related errors
- the resource cannot be null
- the metadata of resource cannot be null
- the namespace of resource cannot be null
- the resource cannot be null
- the metadata of resource cannot be null
AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16).
Data as JSON: /api/errors/68241ecf175a61ba.
Report an issue: GitHub.