{"record":{"id":"82ed0bf990e30caa","repo":"goharbor/harbor","slug":"the-namespace-of-resource-cannot-be-null-82ed0b","errorCode":null,"errorMessage":"the namespace of resource cannot be null","messagePattern":"the namespace of resource cannot be null","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/pkg/reg/adapter/quay/adapter.go","lineNumber":161,"sourceCode":"\t}, nil\n}\n\n// PrepareForPush does the prepare work that needed for pushing/uploading the resource\n// eg: create the namespace or repository\nfunc (a *adapter) PrepareForPush(resources []*model.Resource) error {\n\tif !a.autoCreateNs {\n\t\treturn nil\n\t}\n\tnamespaces := []string{}\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 namespace 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 namespace cannot be null\")\n\t\t}\n\t\tpaths := strings.Split(resource.Metadata.Repository.Name, \"/\")\n\t\tnamespace := paths[0]\n\t\tnamespaces = append(namespaces, namespace)\n\t}\n\n\tfor _, namespace := range namespaces {\n\t\terr := a.createNamespace(&model.Namespace{\n\t\t\tName: namespace,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"create namespace '%s' in Quay error: %v\", namespace, err)\n\t\t}\n\t\tlog.Debugf(\"namespace %s created\", namespace)\n\t}","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/src/pkg/reg/adapter/quay/adapter.go#L143-L179","documentation":"Returned by the Quay adapter's PrepareForPush (src/pkg/reg/adapter/quay/adapter.go:161) when resource.Metadata is set but resource.Metadata.Repository is nil. The adapter needs Repository.Name to compute the Quay namespace (first path segment) to auto-create; a nil Repository pointer makes that impossible, so it fails before any API call to Quay.","triggerScenarios":"Passing a resource whose ResourceMetadata has Vtags/Artifact but no Repository to quay PrepareForPush with autoCreateNs enabled.","commonSituations":"Metadata built for tag operations reused for push; struct literals after a refactor that moved Repository into a conditional branch; clones that copy only selected fields.","solutions":["Always set Metadata.Repository (with a non-empty Name) for resources destined for push.","Validate the slice up front (see validationCode) for a precise index.","Assert non-nil Repository in builder unit tests.","When cloning source metadata, copy the Repository pointer rather than rebuilding it field-by-field."],"exampleFix":"// before\nMetadata: &model.ResourceMetadata{Vtags: []string{\"latest\"}},\n\n// after\nMetadata: &model.ResourceMetadata{\n    Repository: &model.Repository{Name: \"myteam/ubuntu\"},\n    Vtags:     []string{\"latest\"},\n},","handlingStrategy":"validation","validationCode":"for i, r := range resources {\n\tif r == nil || r.Metadata == nil || r.Metadata.Repository == nil {\n\t\treturn fmt.Errorf(\"resources[%d]: missing resource/metadata/repository\", i)\n\t}\n}","typeGuard":"func hasRepository(r *model.Resource) bool {\n\treturn r != nil && r.Metadata != nil && r.Metadata.Repository != nil\n}","tryCatchPattern":"if err := a.PrepareForPush(resources); err != nil {\n\tif strings.Contains(err.Error(), \"namespace of resource cannot be null\") {\n\t\t// set Metadata.Repository before retry\n\t}\n\treturn err\n}","preventionTips":["Copy the source Metadata (including Repository pointer) when cloning.","Builder tests assert Repository non-nil."],"tags":["go","quay","replication","validation","nil-check"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}