goharbor/harbor · error

Data cannot be converted to v1 report format

Error message

Data cannot be converted to v1 report format

What it means

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.

Source

Thrown at src/pkg/scan/postprocessors/report_converters.go:234

	}
	if len(vulnerabilityItems) > 0 {
		rp.Vulnerabilities = make([]*vuln.VulnerabilityItem, 0)
		rp.Vulnerabilities = append(rp.Vulnerabilities, vulnerabilityItems...)
	}

	data, err := json.Marshal(rp)
	if err != nil {
		return "", err
	}
	return string(data), nil
}

// GetNativeV1ReportFromResolvedData returns the native V1 scan report from the resolved
// interface data.
func (c *nativeToRelationalSchemaConverter) getNativeV1ReportFromResolvedData(ctx job.Context, rp any) (*vuln.Report, error) {
	report, ok := rp.(*vuln.Report)
	if !ok {
		return nil, errors.New("Data cannot be converted to v1 report format")
	}
	ctx.GetLogger().Infof("Converted raw data to report. Count of Vulnerabilities in report : %d", len(report.Vulnerabilities))
	return report, nil
}

func toVulnerabilityRecord(ctx context.Context, item *vuln.VulnerabilityItem, registrationUUID string) *scan.VulnerabilityRecord {
	record := new(scan.VulnerabilityRecord)

	record.CVEID = item.ID
	record.Description = item.Description
	record.Package = item.Package
	record.PackageVersion = item.Version
	record.PackageType = "Unknown"
	record.Fix = item.FixVersion
	record.URLs = strings.Join(item.Links, "|")
	record.RegistrationUUID = registrationUUID
	record.Severity = item.Severity.String()
	record.Status = item.Status

View on GitHub (pinned to 7b2fd08cc5)

Solutions

  1. Verify the scanner registration declares a supported mime type and that the adapter returns the native report format
  2. In converter chains, ensure the previous stage returns the parsed *vuln.Report object, not its JSON string
  3. After Harbor upgrades, re-register/re-test adapters against the supported report schema

Example fix

// before
func convert(ctx job.Context, resolved any) (*vuln.Report, error) {
    return c.getNativeV1ReportFromResolvedData(ctx, resolved)
}

// after
func convert(ctx job.Context, resolved any) (*vuln.Report, error) {
    if s, ok := resolved.(string); ok {
        rp := new(vuln.Report)
        if err := json.Unmarshal([]byte(s), rp); err != nil {
            return nil, err
        }
        resolved = rp
    }
    return c.getNativeV1ReportFromResolvedData(ctx, resolved)
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Normalize before calling the converter
switch v := resolved.(type) {
case *vuln.Report:
    return c.getNativeV1ReportFromResolvedData(ctx, v)
case string:
    rp := new(vuln.Report)
    if err := json.Unmarshal([]byte(v), rp); err != nil {
        return nil, err
    }
    return c.getNativeV1ReportFromResolvedData(ctx, rp)
}

Type guard

func isNativeVulnReport(rp any) bool {
    _, ok := rp.(*vuln.Report)
    return ok
}

Prevention

When it happens

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

Common situations: 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.

Related errors


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