{"record":{"id":"edc534904b9f6a8d","repo":"goharbor/harbor","slug":"empty-digest-to-get-report-data","errorCode":null,"errorMessage":"empty digest to get report data","messagePattern":"empty digest to get report data","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/pkg/scan/report/manager.go","lineNumber":167,"sourceCode":"\t\treturn err\n\t}\n\tquery := q.Query{Keywords: q.KeyWords{\"uuid\": uuid}}\n\tcount, err := bm.dao.DeleteMany(ctx, query)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif count == 0 {\n\t\treturn errors.Errorf(\"no report with uuid %s deleted\", uuid)\n\t}\n\n\treturn nil\n}\n\n// GetBy ...\nfunc (bm *basicManager) GetBy(ctx context.Context, digest string, registrationUUID string, mimeTypes []string) ([]*scan.Report, error) {\n\tif len(digest) == 0 {\n\t\treturn nil, errors.New(\"empty digest to get report data\")\n\t}\n\n\tkws := make(map[string]any)\n\tkws[\"digest\"] = digest\n\tif len(registrationUUID) > 0 {\n\t\tkws[\"registration_uuid\"] = registrationUUID\n\t}\n\tif len(mimeTypes) > 0 {\n\t\tkws[\"mime_type__in\"] = mimeTypes\n\t}\n\t// Query all\n\tquery := &q.Query{\n\t\tPageNumber: 0,\n\t\tKeywords:   kws,\n\t}\n\n\treturn bm.dao.List(ctx, query)\n}","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/src/pkg/scan/report/manager.go#L149-L185","documentation":"Returned by basicManager.GetBy when the digest argument is empty. GetBy queries reports filtered by digest (optionally registration UUID and mime types); the digest is the mandatory primary filter and an empty value is rejected before the DAO query is built.","triggerScenarios":"Calling GetBy(ctx, \"\", regUUID, mimes) from an artifact handler where the digest was not resolved; request paths where the artifact reference arrived empty after URL parsing; code passing digest before it is set.","commonSituations":"API handlers trusting request params without validation; artifact lookups failing upstream and the empty result flowing into report queries; tests calling GetBy with placeholders.","solutions":["Resolve and validate the artifact digest (format and non-empty) before querying reports","Return 400 Bad Request at the API boundary when the digest param is missing","Check the caller chain for the step that dropped the digest value"],"exampleFix":"// before\nreports, err := bm.GetBy(ctx, digest, \"\", mimes) // digest == \"\"\n\n// after\nif len(digest) == 0 {\n    return nil, errors.New(nil).WithCode(errors.BadRequestCode).\n        WithMessage(\"artifact digest is required\")\n}\nreports, err := bm.GetBy(ctx, digest, \"\", mimes)","handlingStrategy":"validation","validationCode":"if len(digest) == 0 {\n    return nil, errors.New(nil).WithCode(errors.BadRequestCode).\n        WithMessage(\"digest is required to query reports\")\n}\nreports, err := bm.GetBy(ctx, digest, registrationUUID, mimeTypes)","typeGuard":"func isValidDigest(d string) bool {\n    return len(d) > 0 && strings.HasPrefix(d, \"sha256:\") && len(d) == len(\"sha256:\")+64\n}","tryCatchPattern":null,"preventionTips":["Validate digest format at the request boundary before any report query","Fail loudly when an upstream artifact lookup returns an empty digest","Centralize digest parsing so empty values never reach managers"],"tags":["scan","report","digest","validation"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}