{"record":{"id":"b04491513fa20a4b","repo":"goharbor/harbor","slug":"purge-upload-interval-should-set-with-with-nh-n-i","errorCode":null,"errorMessage":"purge upload interval should set with with nh, n is the number of hour","messagePattern":"purge upload interval 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":222,"sourceCode":"        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:\n            self.enabled = False\n        self.enabled = config.get('enabled')\n        self.expire_hours = config.get('expire_hours')\n\n    def validate(self):\n        if not self.enabled:\n            return\n","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/make/photon/prepare/models.py#L204-L240","documentation":"SBOM report manager Create requires an actual report object; passing a nil *model.Report returns 'nil sbom report object' before any field checks, UUID generation, or DB insert. It is the first and coarsest validation in the create path.","triggerScenarios":"mgr.Create(ctx, nil); or Create(ctx, r) where r stayed nil because unmarshalling of the SBOM payload failed and the error was ignored.","commonSituations":"Ingest code that decodes an SBOM body but discards the decode error; conditional report construction skipped under an early return; refactors that changed Create to take a pointer.","solutions":["Non-nil check the report at the call site with a descriptive error","Propagate unmarshal/decode errors from SBOM parsing instead of continuing with nil","Construct the report in one place right before calling Create"],"exampleFix":"// before\nid, err := mgr.Create(ctx, r) // r may be nil\n\n// after\nif r == nil {\n    return \"\", errors.New(\"sbom report not built: decode failed earlier\")\n}\nid, err := mgr.Create(ctx, r)","handlingStrategy":"validation","validationCode":"if r == nil {\n    return errors.New(\"sbom report not built\")\n}\nreturn mgr.Create(ctx, r)","typeGuard":null,"tryCatchPattern":"if _, err := mgr.Create(ctx, r); err != nil {\n    if strings.Contains(err.Error(), \"nil sbom report object\") {\n        return errors.New(\"report decode failed upstream; nothing to create\")\n    }\n    return err\n}","preventionTips":["Propagate decode errors instead of continuing with nil","Construct the report object immediately before Create","Add nil checks in ingest pipelines that read external payloads"],"tags":["go","harbor","sbom","report","validation"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}