{"record":{"id":"b68a5429a51a49ca","repo":"goharbor/harbor","slug":"data-cannot-be-converted-to-v1-report-format","errorCode":null,"errorMessage":"Data cannot be converted to v1 report format","messagePattern":"Data cannot be converted to v1 report format","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/pkg/scan/postprocessors/report_converters.go","lineNumber":234,"sourceCode":"\t}\n\tif len(vulnerabilityItems) > 0 {\n\t\trp.Vulnerabilities = make([]*vuln.VulnerabilityItem, 0)\n\t\trp.Vulnerabilities = append(rp.Vulnerabilities, vulnerabilityItems...)\n\t}\n\n\tdata, err := json.Marshal(rp)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn string(data), nil\n}\n\n// GetNativeV1ReportFromResolvedData returns the native V1 scan report from the resolved\n// interface data.\nfunc (c *nativeToRelationalSchemaConverter) getNativeV1ReportFromResolvedData(ctx job.Context, rp any) (*vuln.Report, error) {\n\treport, ok := rp.(*vuln.Report)\n\tif !ok {\n\t\treturn nil, errors.New(\"Data cannot be converted to v1 report format\")\n\t}\n\tctx.GetLogger().Infof(\"Converted raw data to report. Count of Vulnerabilities in report : %d\", len(report.Vulnerabilities))\n\treturn report, nil\n}\n\nfunc toVulnerabilityRecord(ctx context.Context, item *vuln.VulnerabilityItem, registrationUUID string) *scan.VulnerabilityRecord {\n\trecord := new(scan.VulnerabilityRecord)\n\n\trecord.CVEID = item.ID\n\trecord.Description = item.Description\n\trecord.Package = item.Package\n\trecord.PackageVersion = item.Version\n\trecord.PackageType = \"Unknown\"\n\trecord.Fix = item.FixVersion\n\trecord.URLs = strings.Join(item.Links, \"|\")\n\trecord.RegistrationUUID = registrationUUID\n\trecord.Severity = item.Severity.String()\n\trecord.Status = item.Status","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/src/pkg/scan/postprocessors/report_converters.go#L216-L252","documentation":"Thrown by nativeToRelationalSchemaConverter.getNativeV1ReportFromResolvedData when the resolved upstream data cannot be type-asserted to *vuln.Report. The relational-schema converter expects the resolved report to already be a native vulnerability report object; anything else (string, map, other report type) fails the assertion.","triggerScenarios":"A postprocessor/converter chain handing the wrong type into the converter (e.g. raw JSON string instead of the parsed *vuln.Report); a scanner producing a report of an unsupported mime type that got routed into the native converter; code changes to the resolution pipeline after upgrades.","commonSituations":"Harbor upgrades changing the resolved-data contract between report converter stages; third-party scanners declaring the native mime type but returning incompatible payloads; custom postprocessors inserting themselves into the conversion chain.","solutions":["Verify the scanner registration declares a supported mime type and that the adapter returns the native report format","In converter chains, ensure the previous stage returns the parsed *vuln.Report object, not its JSON string","After Harbor upgrades, re-register/re-test adapters against the supported report schema"],"exampleFix":"// before\nfunc convert(ctx job.Context, resolved any) (*vuln.Report, error) {\n    return c.getNativeV1ReportFromResolvedData(ctx, resolved)\n}\n\n// after\nfunc convert(ctx job.Context, resolved any) (*vuln.Report, error) {\n    if s, ok := resolved.(string); ok {\n        rp := new(vuln.Report)\n        if err := json.Unmarshal([]byte(s), rp); err != nil {\n            return nil, err\n        }\n        resolved = rp\n    }\n    return c.getNativeV1ReportFromResolvedData(ctx, resolved)\n}","handlingStrategy":"type-guard","validationCode":"// Normalize before calling the converter\nswitch v := resolved.(type) {\ncase *vuln.Report:\n    return c.getNativeV1ReportFromResolvedData(ctx, v)\ncase string:\n    rp := new(vuln.Report)\n    if err := json.Unmarshal([]byte(v), rp); err != nil {\n        return nil, err\n    }\n    return c.getNativeV1ReportFromResolvedData(ctx, rp)\n}","typeGuard":"func isNativeVulnReport(rp any) bool {\n    _, ok := rp.(*vuln.Report)\n    return ok\n}","tryCatchPattern":null,"preventionTips":["Keep converter chain stage contracts typed; pass parsed objects, not strings","Register scanners only for mime types they truly emit","Add contract tests for postprocessor data types in CI"],"tags":["scan","report-converter","type-assertion","vulnerability"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}