{"record":{"id":"21b6575401ff114f","repo":"goharbor/harbor","slug":"10013-21b657","errorCode":"10013","errorMessage":"parameters required for replication job","messagePattern":"parameters required for replication job","errorType":"validation","errorClass":"badRequestError","httpStatus":400,"severity":"error","filePath":"src/jobservice/job/impl/sample/job.go","lineNumber":48,"sourceCode":"// MaxFails is implementation of same method in Interface.\nfunc (j *Job) MaxFails() uint {\n\treturn 3\n}\n\n// MaxCurrency is implementation of same method in Interface.\nfunc (j *Job) MaxCurrency() uint {\n\treturn 1\n}\n\n// ShouldRetry ...\nfunc (j *Job) ShouldRetry() bool {\n\treturn true\n}\n\n// Validate is implementation of same method in Interface.\nfunc (j *Job) Validate(params job.Parameters) error {\n\tif len(params) == 0 {\n\t\treturn errors.New(\"parameters required for replication job\")\n\t}\n\tname, ok := params[\"image\"]\n\tif !ok {\n\t\treturn errors.New(\"missing parameter 'image'\")\n\t}\n\n\tif !strings.HasPrefix(name.(string), \"demo\") {\n\t\treturn fmt.Errorf(\"expected '%s' but got '%s'\", \"demo *\", name)\n\t}\n\n\treturn nil\n}\n\n// Run the replication logic here.\nfunc (j *Job) Run(ctx job.Context, params job.Parameters) error {\n\tlogger := ctx.GetLogger()\n\n\tlogger.Info(\"Sample job starting\")","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/src/jobservice/job/impl/sample/job.go#L30-L66","documentation":"Harbor's sample/demo job (src/jobservice/job/impl/sample/job.go:48) illustrates the job.Interface contract: Validate rejects an empty params map (len(params) == 0, note: nil and {} both count) at submission time with code 10013. It then requires an 'image' key whose string value starts with 'demo'.","triggerScenarios":"Submitting the SAMPLE job with no parameters — e.g. POST to the job launch API with name SAMPLE and an absent/empty params object.","commonSituations":"Integration tests against a dev Harbor; copy-pasting job-launch examples without the params block; smoke-testing the jobservice after deployment.","solutions":["Pass at least {\"image\": \"demo/...\"} — the value must start with 'demo' or the next validation fails","Use this sample implementation as the template when writing your own job's Validate"],"exampleFix":"// before\nparams := job.Parameters{}\n// after\nparams := job.Parameters{\"image\": \"demo/alpine\"}","handlingStrategy":"validation","validationCode":"if len(params) == 0 {\n    return fmt.Errorf(\"sample job requires params\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never submit a job with an empty params map — check len(params) first","Copy the sample job's Validate pattern (non-empty map, required keys, value checks) into custom jobs","Include required params in every job-launch fixture and example"],"tags":["jobservice","sample","validation","job-parameters","demo","harbor"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}