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 []string

View on GitHub (pinned to 7b2fd08cc5)

Solutions

  1. Inspect the replication rule's destination namespace/repository override and make sure it yields a non-empty 'project/repository' string.
  2. If you build the resources yourself, set resource.Metadata.Repository.Name from the source repository (e.g. 'library/ubuntu') before calling PrepareForPush.
  3. 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.
  4. 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

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


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