goharbor/harbor · error · Exception
key file {} permission is not 600
Error message
key file {} permission is not 600 What it means
The second assertion in MergeNativeReport (src/pkg/scan/report/report.go): after r1 has already passed the *vuln.Report check, the SECOND operand r2 fails the same type assertion. The merge is between two untyped values routed through SupportedMergers, so any operand that is not exactly a *vuln.Report pointer (nil included) aborts the merge.
Source
Thrown at make/photon/prepare/models.py:80
def _check(self, filename: str):
"""
Check cert and key files are correct
"""
path = Path(os.path.join(internal_tls_dir, filename))
if not path.exists:
if filename == 'harbor_internal_ca.crt':
return
raise Exception('File {} not exist'.format(filename))
if not path.is_file:
raise Exception('invalid {}'.format(filename))
# check key file permission
if filename.endswith('.key') and not check_permission(path, mode=0o600):
raise Exception('key file {} permission is not 600'.format(filename))
# 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():View on GitHub (pinned to 7b2fd08cc5)
Solutions
- Filter or fail on any element of the report list that does not decode to *vuln.Report before merging
- Confirm both reports were resolved under the same mime type and the same SupportedMimes entry
- Log %T of both operands at the call site to identify the odd one out
Example fix
// before
merged, err := report.MergeNativeReport(nr1, r2) // r2 is `any`
// after
nr2, ok := r2.(*vuln.Report)
if !ok {
return nil, fmt.Errorf("second operand is %T, want *vuln.Report", r2)
}
merged, err := report.MergeNativeReport(nr1, nr2) Defensive patterns
Strategy: type-guard
Validate before calling
if !isNativeReport(r2) {
return fmt.Errorf("second merge operand is %T, want *vuln.Report", r2)
} Type guard
func isNativeReport(v any) bool {
_, ok := v.(*vuln.Report)
return ok
} Try / catch
merged, err := report.MergeNativeReport(nr1, r2)
if err != nil && strings.Contains(err.Error(), "native report required") {
return fmt.Errorf("r2 not a native report (%T); re-resolve it under the same mime type", r2)
} Prevention
- Filter report lists so every element decodes to the same concrete type before folding
- Do not merge reports resolved under different mime types
- Skip nil interfaces explicitly before merging
When it happens
Trigger: Merging reports collected from heterogeneous sources — e.g. r1 decoded via ResolveData into *vuln.Report but r2 loaded from a store, a different mime type, or a nil interface.
Common situations: Merging a freshly scanned report with a legacy or raw one; mixed mime types funnelled into one merge call; a report slice where one element failed to parse and was left nil.
Related errors
- invalid {}
- File {} should readable by owner
- cert file {} should include SAN
- File {} not exist
- Internal dir for tls {} not exist
AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16).
Data as JSON: /api/errors/be49c852169f014b.
Report an issue: GitHub.