{"record":{"id":"f4d1e662f1892bcc","repo":"goharbor/harbor","slug":"purge-upload-age-should-set-with-with-nh-n-is-the","errorCode":null,"errorMessage":"purge upload age should set with with nh, n is the number of hour","messagePattern":"purge upload age should set with with nh, n is the number of hour","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"make/photon/prepare/models.py","lineNumber":214,"sourceCode":"            self.otel.validate()\n\n\nclass PurgeUpload:\n    def __init__(self, config: dict):\n        if not config:\n            self.enabled = False\n        self.enabled = config.get('enabled')\n        self.age = config.get('age') or '168h'\n        self.interval = config.get('interval') or '24h'\n        self.dryrun = config.get('dryrun') or False\n        return\n\n    def validate(self):\n        if not self.enabled:\n            return\n        # age should end with h\n        if not isinstance(self.age, str) or not self.age.endswith('h'):\n            raise Exception('purge upload age should set with with nh, n is the number of hour')\n        # interval should larger than 2h\n        age = self.age[:-1]\n        if not age.isnumeric() or int(age) < 2:\n            raise Exception('purge upload age should set with with nh, n is the number of hour and n should not be less than 2')\n\n        # interval should end with h\n        if not isinstance(self.interval, str) or not self.interval.endswith('h'):\n            raise Exception('purge upload interval should set with with nh, n is the number of hour')\n        # interval should larger than 2h\n        interval = self.interval[:-1]\n        if not interval.isnumeric() or int(interval) < 2:\n            raise Exception('purge upload interval should set with with nh, n is the number of hour and n should not beless than 2')\n        return\n\n\nclass Cache:\n    def __init__(self, config: dict):\n        if not config:","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/make/photon/prepare/models.py#L196-L232","documentation":"The second ScanRequest.Validate check: Artifact must be non-nil with non-empty Digest, Repository and MimeType — these identify the exact manifest the adapter must scan. Missing any one of the four yields 'scan request: invalid artifact'.","triggerScenarios":"req.Validate() where artifact, digest, repository, or mime_type is empty — e.g. a scan enqueued for an artifact whose manifest digest was not yet populated by replication or event processing.","commonSituations":"Scans triggered before the artifact is fully replicated or indexed; event handlers forwarding partial artifact payloads; upstream systems changing digest formats or field names.","solutions":["Complete all artifact fields (digest, repository, mime type) before submitting the scan","Validate at event-ingestion time and requeue artifacts that are incomplete","Validate fields individually in logs so the exact missing field is visible"],"exampleFix":"// before\nreq := &v1.ScanRequest{\n    Registry: &v1.Registry{URL: cfg.RegistryURL},\n    Artifact: &v1.Artifact{Repository: \"library/nginx\"}, // digest + mime_type missing\n}\n\n// after\nreq := &v1.ScanRequest{\n    Registry: &v1.Registry{URL: cfg.RegistryURL},\n    Artifact: &v1.Artifact{\n        Repository: \"library/nginx\",\n        Digest:     \"sha256:abc...\",\n        MimeType:   v1.MimeTypeDockerArtifact,\n    },\n}","handlingStrategy":"validation","validationCode":"if req.Artifact == nil || req.Artifact.Digest == \"\" || req.Artifact.Repository == \"\" || req.Artifact.MimeType == \"\" {\n    return fmt.Errorf(\"scan request missing artifact fields: %+v\", req.Artifact)\n}\nreturn req.Validate()","typeGuard":null,"tryCatchPattern":"if err := req.Validate(); err != nil {\n    if strings.Contains(err.Error(), \"invalid artifact\") {\n        return errors.New(\"artifact digest, repository and mime type are all required\")\n    }\n    return err\n}","preventionTips":["Only enqueue scans for fully indexed artifacts (digest present)","Validate artifact payloads at event-ingestion time and requeue incomplete ones","Log which specific field is empty using a per-field check"],"tags":["go","harbor","scan","artifact","validation"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}