{"record":{"id":"68241ecf175a61ba","repo":"goharbor/harbor","slug":"the-name-of-the-repository-cannot-be-null","errorCode":null,"errorMessage":"the name of the repository cannot be null","messagePattern":"the name of the repository cannot be null","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/pkg/reg/adapter/harbor/base/adapter.go","lineNumber":154,"sourceCode":"\n\treturn info, nil\n}\n\n// PrepareForPush creates projects\nfunc (a *Adapter) PrepareForPush(resources []*model.Resource) error {\n\tprojects := map[string]*Project{}\n\tfor _, resource := range resources {\n\t\tif resource == nil {\n\t\t\treturn errors.New(\"the resource cannot be null\")\n\t\t}\n\t\tif resource.Metadata == nil {\n\t\t\treturn errors.New(\"the metadata of resource cannot be null\")\n\t\t}\n\t\tif resource.Metadata.Repository == nil {\n\t\t\treturn errors.New(\"the repository of resource cannot be null\")\n\t\t}\n\t\tif len(resource.Metadata.Repository.Name) == 0 {\n\t\t\treturn errors.New(\"the name of the repository cannot be null\")\n\t\t}\n\n\t\tpaths := strings.Split(resource.Metadata.Repository.Name, \"/\")\n\t\tprojectName := paths[0]\n\t\t// handle the public properties\n\t\tmetadata := abstractPublicMetadata(resource.Metadata.Repository.Metadata)\n\t\tpro, exist := projects[projectName]\n\t\tif exist {\n\t\t\tmetadata = mergeMetadata(pro.Metadata, metadata)\n\t\t}\n\t\tprojects[projectName] = &Project{\n\t\t\tName:     projectName,\n\t\t\tMetadata: metadata,\n\t\t}\n\t}\n\n\t// Create a list of the project names.\n\tvar ps []string","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/src/pkg/reg/adapter/harbor/base/adapter.go#L136-L172","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nresources = append(resources, &model.Resource{\n    Metadata: &model.ResourceMetadata{\n        Repository: &model.Repository{}, // Name left empty\n    },\n})\nerr := dstAdapter.PrepareForPush(resources)\n\n// after\nresources = append(resources, &model.Resource{\n    Metadata: &model.ResourceMetadata{\n        Repository: &model.Repository{Name: \"library/ubuntu\"},\n    },\n})\nerr := dstAdapter.PrepareForPush(resources)","handlingStrategy":"validation","validationCode":"func validatePushResources(resources []*model.Resource) error {\n\tfor i, r := range resources {\n\t\tif r == nil {\n\t\t\treturn fmt.Errorf(\"resources[%d]: nil resource\", i)\n\t\t}\n\t\tif r.Metadata == nil {\n\t\t\treturn fmt.Errorf(\"resources[%d]: nil metadata\", i)\n\t\t}\n\t\tif r.Metadata.Repository == nil {\n\t\t\treturn fmt.Errorf(\"resources[%d]: nil repository\", i)\n\t\t}\n\t\tif r.Metadata.Repository.Name == \"\" {\n\t\t\treturn fmt.Errorf(\"resources[%d]: empty repository name\", i)\n\t\t}\n\t}\n\treturn nil\n}\n// call before adapter.PrepareForPush(resources)\nif err := validatePushResources(resources); err != nil { return err }","typeGuard":"func hasValidRepoName(r *model.Resource) bool {\n\treturn r != nil && r.Metadata != nil &&\n\t\tr.Metadata.Repository != nil && r.Metadata.Repository.Name != \"\"\n}","tryCatchPattern":"if err := dstAdapter.PrepareForPush(resources); err != nil {\n\tlog.Errorf(\"prepare push failed: %v\", err)\n\treturn fmt.Errorf(\"prepare resources before push: %w\", err)\n}","preventionTips":["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."],"tags":["go","harbor","replication","validation","nil-check","prepare-for-push"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}