{"record":{"id":"1e20ebe139a4d9c9","repo":"goharbor/harbor","slug":"only-can-have-one-trace-exporter-at-a-time","errorCode":null,"errorMessage":"Only can have one trace exporter at a time","messagePattern":"Only can have one trace exporter at a time","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"make/photon/prepare/models.py","lineNumber":192,"sourceCode":"            raise Exception('Trace url path not set')\n\n\nclass Trace:\n    def __init__(self, config: dict):\n        self.enabled = config.get('enabled') or False\n        self.sample_rate = config.get('sample_rate', 1)\n        self.namespace = config.get('namespace') or ''\n        self.jaeger = JaegerExporter(config.get('jaeger'))\n        self.otel = OtelExporter(config.get('otel'))\n        self.attributes = config.get('attributes') or {}\n\n    def validate(self):\n        if not self.enabled:\n            return\n        if not self.jaeger.enabled and not self.otel.enabled:\n            raise Exception('Trace enabled but no trace exporter set')\n        elif self.jaeger.enabled and self.otel.enabled:\n            raise Exception('Only can have one trace exporter at a time')\n        elif self.jaeger.enabled:\n            self.jaeger.validate()\n        elif self.otel.enabled:\n            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:","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/make/photon/prepare/models.py#L174-L210","documentation":"ScanRequest.Validate requires a Registry with a non-empty URL so the adapter knows where to pull the artifact from. 'scan request: invalid registry' means Registry is nil or its URL is the empty string; the request cannot be fulfilled without a reachable registry.","triggerScenarios":"req.Validate() on a payload where the registry object or registry.url field is missing — typically the enqueuing component did not fill the registry URL when building the request.","commonSituations":"Registry configuration missing in the component that creates scan requests; hand-crafted API calls omitting registry.url; environments where the internal registry address is injected conditionally.","solutions":["Ensure the scan request JSON carries a non-empty registry.url (e.g. https://registry:5000)","Populate the registry from your registry configuration before validating","Return 400 with field-level detail so the caller knows which field is missing"],"exampleFix":"// before\nreq := &v1.ScanRequest{Artifact: art} // Registry left nil\nerr := req.Validate()\n\n// after\nreq := &v1.ScanRequest{\n    Registry: &v1.Registry{URL: cfg.RegistryURL},\n    Artifact: art,\n}\nerr := req.Validate()","handlingStrategy":"validation","validationCode":"if req.Registry == nil || req.Registry.URL == \"\" {\n    return errors.New(\"scan request missing registry.url\")\n}\nreturn req.Validate()","typeGuard":null,"tryCatchPattern":"if err := req.Validate(); err != nil {\n    if strings.Contains(err.Error(), \"invalid registry\") {\n        return errors.New(\"fill registry.url (e.g. from registry config) before submitting\")\n    }\n    return err\n}","preventionTips":["Populate registry.url from configuration when building requests","Include field-level errors in 400 responses","Smoke-test request builders with fixtures that exercise empty configs"],"tags":["go","harbor","scan","registry","validation"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}