{"record":{"id":"a2f4b7b024a8a6cc","repo":"flipped-aurora/gin-vue-admin","slug":"params-json","errorCode":null,"errorMessage":"params 必须是合法 JSON","messagePattern":"params 必须是合法 JSON","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/service/system/sys_timed_task.go","lineNumber":58,"sourceCode":"\t}\n\treturn nil\n}\n\n// validateTask 落库前统一校验(创建/更新共用)\nfunc (s *TimedTaskService) validateTask(t *system.SysTimedTask) error {\n\tif t.Name == \"\" {\n\t\treturn errors.New(\"任务名不能为空\")\n\t}\n\tif err := s.ValidateSpec(t.Spec, t.WithSeconds); err != nil {\n\t\treturn err\n\t}\n\tswitch t.ExecutorType {\n\tcase system.TimedTaskExecutorMethod:\n\t\tif _, ok := task.Get(t.MethodName); !ok {\n\t\t\treturn fmt.Errorf(\"方法 %s 未注册\", t.MethodName)\n\t\t}\n\t\tif len(t.Params) > 0 && !json.Valid(t.Params) {\n\t\t\treturn errors.New(\"params 必须是合法 JSON\")\n\t\t}\n\tcase system.TimedTaskExecutorHTTP:\n\t\tu, err := url.Parse(t.HttpUrl)\n\t\tif err != nil || (u.Scheme != \"http\" && u.Scheme != \"https\") || u.Host == \"\" {\n\t\t\treturn errors.New(\"httpUrl 必须是合法的 http/https 地址\")\n\t\t}\n\t\tif len(t.HttpHeader) > 0 {\n\t\t\tvar hdr map[string]string\n\t\t\tif err := json.Unmarshal(t.HttpHeader, &hdr); err != nil {\n\t\t\t\treturn errors.New(`httpHeader 必须是 {\"Key\":\"Value\"} 形式的 JSON 对象`)\n\t\t\t}\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"executorType 必须为 %s 或 %s\", system.TimedTaskExecutorMethod, system.TimedTaskExecutorHTTP)\n\t}\n\treturn nil\n}\n","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/service/system/sys_timed_task.go#L40-L76","documentation":"validateTask throws \"params 必须是合法 JSON\" when an executor of type TimedTaskExecutorMethod has a non-empty Params byte slice that fails json.Valid. Params are stored raw and parsed at execution time, so invalid JSON would break the runner.","triggerScenarios":"Creating/updating a method-type timed task with Params like `{invalid` or a bare string without quotes; client sending params as a form string instead of a JSON object; double-encoded JSON producing non-JSON bytes.","commonSituations":"Hand-editing task config in DB admin tools; frontend serializing an object twice (JSON.stringify of a string); copy-pasting params with trailing comments or trailing commas.","solutions":["Ensure Params is valid JSON, typically a JSON object like {\"key\":\"value\"}.","On the client, send the object itself and let JSON serialization handle it, not a pre-stringified string.","Run json.Valid (or JSON.parse) on the payload before calling the API.","If params are optional, send an empty value rather than malformed text."],"exampleFix":"// before\nparams := []byte(`{\"path\": /var/log}`) // invalid JSON\n\n// after\nparams, _ := json.Marshal(map[string]string{\"path\": \"/var/log\"})\nsvc.CreateTimedTask(ctx, &system.SysTimedTask{Name: \"clean\", Spec: \"@daily\", ExecutorType: system.TimedTaskExecutorMethod, MethodName: \"CleanLogs\", Params: params})","handlingStrategy":"validation","validationCode":"if len(task.Params) > 0 && !json.Valid(task.Params) {\n    return errors.New(\"params must be valid JSON before calling the API\")\n}","typeGuard":"func validJSONParams(p []byte) bool { return len(p) == 0 || json.Valid(p) }","tryCatchPattern":"if err := svc.CreateTimedTask(ctx, task); err != nil {\n    if strings.Contains(err.Error(), \"params 必须是合法 JSON\") {\n        http.Error(w, \"params must be a valid JSON object\", http.StatusBadRequest)\n        return\n    }\n    http.Error(w, err.Error(), http.StatusInternalServerError)\n}","preventionTips":["Build params as a Go/JS object and marshal once, not from strings","Avoid double JSON.stringify on the client","Test the payload with a JSON linter before submitting","Send empty rather than malformed when params are optional"],"tags":["validation","json","go","scheduled-task"],"backgroundTag":"invalid-json-payload","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}