goharbor/harbor · error · Exception

Internal dir for tls {} not exist

Error message

Internal dir for tls {} not exist

What it means

ResolveData in src/pkg/scan/report/supported_mimes.go decodes raw report bytes into the model registered for the mime type in SupportedMimes. If the mime type IS supported but jsonData is zero-length it returns 'empty JSON data', because json.Unmarshal on empty input would only produce a less clear syntax error. Unsupported mime types deliberately return (nil, nil) and never reach this check.

Source

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

        # check certificate file
        if filename.endswith('.crt'):
            if not owner_can_read(path.stat().st_mode):
                # check owner can read cert file
                raise Exception('File {} should readable by owner'.format(filename))
            if not san_existed(path):
                # check SAN included
                if filename == 'harbor_internal_ca.crt':
                    return
                raise Exception('cert file {} should include SAN'.format(filename))

    def validate(self):
        if not self.enabled:
            # pass the validation if not enabled
            return

        if not internal_tls_dir.exists():
            raise Exception('Internal dir for tls {} not exist'.format(internal_tls_dir))

        for filename in self.required_filenames:
            self._check(filename)

    def prepare(self):
        """
        Prepare moves certs in tls file to data volume with correct permission.
        """
        if not self.enabled:
            logging.info('internal tls NOT enabled...')
            return
        original_tls_dir = get_realpath(self.tls_dir)
        if internal_tls_dir.exists():
            rmtree(internal_tls_dir)
        copytree(original_tls_dir, internal_tls_dir, symlinks=True)

        for file in internal_tls_dir.iterdir():
            if file.name.endswith('.key'):

View on GitHub (pinned to 7b2fd08cc5)

Solutions

  1. Length-check jsonData before calling ResolveData and treat empty data as an upstream fetch/storage failure
  2. Fix the producer that stored or returned the empty report body
  3. If a mime type is meant to bypass parsing, do not register it in SupportedMimes — unregistered mimes pass raw data through untouched

Example fix

// before
data, err := report.ResolveData(mime, body) // body may be empty

// after
if len(body) == 0 {
    return nil, fmt.Errorf("report body for mime %s is empty", mime)
}
data, err := report.ResolveData(mime, body)
Defensive patterns

Strategy: validation

Validate before calling

if len(jsonData) == 0 {
    return nil, fmt.Errorf("no data to resolve for mime %s", mime)
}
return report.ResolveData(mime, jsonData)

Try / catch

data, err := report.ResolveData(mime, jsonData)
if err != nil {
    if strings.Contains(err.Error(), "empty JSON data") {
        // data was fetched empty: fix the fetch, do not retry parse
        return nil, fmt.Errorf("report body empty for %s", mime)
    }
    return nil, err
}

Prevention

When it happens

Trigger: Calling ResolveData(mime, nil) or ResolveData(mime, []byte{}) with a mime present in SupportedMimes — e.g. after fetching a report whose body came back empty.

Common situations: A scanner adapter returned 200 with an empty body; a database column holding an empty report blob; passing the wrong variable for the data parameter.

Understand the failure class

Related errors


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