{"record":{"id":"9004769fd8906b72","repo":"goharbor/harbor","slug":"the-metadata-of-resource-cannot-be-null-900476","errorCode":null,"errorMessage":"the metadata of resource cannot be null","messagePattern":"the metadata of resource cannot be null","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/pkg/reg/adapter/quay/adapter.go","lineNumber":158,"sourceCode":"\t\t\tmodel.TriggerTypeManual,\n\t\t\tmodel.TriggerTypeScheduled,\n\t\t},\n\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)","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/src/pkg/reg/adapter/quay/adapter.go#L140-L176","documentation":"Returned by the Quay adapter's PrepareForPush (src/pkg/reg/adapter/quay/adapter.go:158) when a resource is non-nil but resource.Metadata is nil. With autoCreateNs enabled the adapter must read Metadata.Repository.Name to derive the Quay namespace to create, so a missing Metadata struct aborts the operation.","triggerScenarios":"Calling quay PrepareForPush with auto-create enabled on a resource built without the Metadata field, e.g. &model.Resource{Type: ...} only.","commonSituations":"Reusing deletion-style or listing-style resource objects (which omit Metadata) on the push path; hand-built test fixtures; partial struct clones.","solutions":["Populate Metadata (with Repository.Name) for every resource that will be pushed.","Run the pre-flight validation helper to catch the failing index early.","Grep construction sites for 'model.Resource{' and require Metadata on push paths.","Share one resource-builder function between production and tests."],"exampleFix":"// before\nres := &model.Resource{Type: model.ResourceTypeImage}\n\n// after\nres := &model.Resource{\n    Type:     model.ResourceTypeImage,\n    Metadata: &model.ResourceMetadata{\n        Repository: &model.Repository{Name: \"myteam/ubuntu\"},\n    },\n}","handlingStrategy":"validation","validationCode":"for i, r := range resources {\n\tif r == nil || r.Metadata == nil {\n\t\treturn fmt.Errorf(\"resources[%d]: missing resource or metadata\", i)\n\t}\n}","typeGuard":"func hasMetadata(r *model.Resource) bool { return r != nil && r.Metadata != nil }","tryCatchPattern":"if err := a.PrepareForPush(resources); err != nil {\n\tif strings.Contains(err.Error(), \"metadata of resource cannot be null\") {\n\t\t// populate Metadata and retry\n\t}\n\treturn err\n}","preventionTips":["One resource builder for prod and tests, always setting Metadata.","Do not reuse listing/deletion-shaped resources on push paths."],"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"}