goharbor/harbor · error · Exception

purge upload age should set with with nh, n is the number of

Error message

purge upload age should set with with nh, n is the number of hour

What it means

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'.

Source

Thrown at make/photon/prepare/models.py:214

            self.otel.validate()


class PurgeUpload:
    def __init__(self, config: dict):
        if not config:
            self.enabled = False
        self.enabled = config.get('enabled')
        self.age = config.get('age') or '168h'
        self.interval = config.get('interval') or '24h'
        self.dryrun = config.get('dryrun') or False
        return

    def validate(self):
        if not self.enabled:
            return
        # age should end with h
        if not isinstance(self.age, str) or not self.age.endswith('h'):
            raise Exception('purge upload age should set with with nh, n is the number of hour')
        # interval should larger than 2h
        age = self.age[:-1]
        if not age.isnumeric() or int(age) < 2:
            raise Exception('purge upload age should set with with nh, n is the number of hour and n should not be less than 2')

        # interval should end with h
        if not isinstance(self.interval, str) or not self.interval.endswith('h'):
            raise Exception('purge upload interval should set with with nh, n is the number of hour')
        # interval should larger than 2h
        interval = self.interval[:-1]
        if not interval.isnumeric() or int(interval) < 2:
            raise Exception('purge upload interval should set with with nh, n is the number of hour and n should not beless than 2')
        return


class Cache:
    def __init__(self, config: dict):
        if not config:

View on GitHub (pinned to 7b2fd08cc5)

Solutions

  1. Complete all artifact fields (digest, repository, mime type) before submitting the scan
  2. Validate at event-ingestion time and requeue artifacts that are incomplete
  3. Validate fields individually in logs so the exact missing field is visible

Example fix

// before
req := &v1.ScanRequest{
    Registry: &v1.Registry{URL: cfg.RegistryURL},
    Artifact: &v1.Artifact{Repository: "library/nginx"}, // digest + mime_type missing
}

// after
req := &v1.ScanRequest{
    Registry: &v1.Registry{URL: cfg.RegistryURL},
    Artifact: &v1.Artifact{
        Repository: "library/nginx",
        Digest:     "sha256:abc...",
        MimeType:   v1.MimeTypeDockerArtifact,
    },
}
Defensive patterns

Strategy: validation

Validate before calling

if req.Artifact == nil || req.Artifact.Digest == "" || req.Artifact.Repository == "" || req.Artifact.MimeType == "" {
    return fmt.Errorf("scan request missing artifact fields: %+v", req.Artifact)
}
return req.Validate()

Try / catch

if err := req.Validate(); err != nil {
    if strings.Contains(err.Error(), "invalid artifact") {
        return errors.New("artifact digest, repository and mime type are all required")
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: Scans triggered before the artifact is fully replicated or indexed; event handlers forwarding partial artifact payloads; upstream systems changing digest formats or field names.

Related errors


AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16). Data as JSON: /api/errors/f4d1e662f1892bcc. Report an issue: GitHub.