{"record":{"id":"dbf0ecce3148d47f","repo":"goharbor/harbor","slug":"empty-json-data-dbf0ec","errorCode":null,"errorMessage":"empty JSON data","messagePattern":"empty JSON data","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/pkg/scan/job.go","lineNumber":74,"sourceCode":"\n\tauthorizationBearer = \"Bearer\"\n\tauthorizationBasic  = \"Basic\"\n\n\tservice = \"harbor-registry\"\n)\n\n// CheckInReport defines model for checking in the scan report with specified mime.\ntype CheckInReport struct {\n\tDigest           string `json:\"digest\"`\n\tRegistrationUUID string `json:\"registration_uuid\"`\n\tMimeType         string `json:\"mime_type\"`\n\tRawReport        string `json:\"raw_report\"`\n}\n\n// FromJSON parse json to CheckInReport\nfunc (cir *CheckInReport) FromJSON(jsonData string) error {\n\tif len(jsonData) == 0 {\n\t\treturn errors.New(\"empty JSON data\")\n\t}\n\n\treturn json.Unmarshal([]byte(jsonData), cir)\n}\n\n// ToJSON marshal CheckInReport to JSON\nfunc (cir *CheckInReport) ToJSON() (string, error) {\n\tjsonData, err := json.Marshal(cir)\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"To JSON: CheckInReport\")\n\t}\n\n\treturn string(jsonData), nil\n}\n\n// Job for running scan in the job service with async way\ntype Job struct{}\n","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/src/pkg/scan/job.go#L56-L92","documentation":"Returned by CheckInReport.FromJSON when the job check-in message is empty. The scan job's check-in data must be a JSON object with digest, registration_uuid, mime_type and raw_report; an empty string is rejected before unmarshal.","triggerScenarios":"The scanner adapter calls job check-in with an empty message string; the scan job's CheckIn callback receives an empty status message from the job service; adapter returns empty raw_report payload.","commonSituations":"Custom scanner adapters implemented against the job check-in API that post no message; truncation of large report payloads by proxies; version mismatch where the adapter's check-in contract differs from Harbor's.","solutions":["Make the adapter always check in a serialized CheckInReport JSON, even on failure paths","Verify the adapter returns a non-empty body and no intermediary (proxy/gateway) strips it","Check adapter logs for the check-in POST payload size and content"],"exampleFix":"// before\nfunc (j *Job) CheckIn(msg string) { _ = cir.FromJSON(msg) } // msg == \"\"\n\n// after\nfunc (j *Job) CheckIn(msg string) error {\n    if len(msg) == 0 {\n        return errors.New(\"empty check-in data from scanner adapter\")\n    }\n    return cir.FromJSON(msg)\n}","handlingStrategy":"validation","validationCode":"if len(checkInMsg) == 0 {\n    return errors.New(\"scanner adapter checked in with empty report data\")\n}\nvar cir job.CheckInReport\nif err := cir.FromJSON(checkInMsg); err != nil {\n    return err\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Adapters must always POST a serialized CheckInReport, including on error paths","Watch proxy body-size limits that can truncate check-in payloads to empty","Log check-in message length in adapter tests"],"tags":["scan","check-in","json","scanner-adapter"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}