{"record":{"id":"6f21c6f547e9ac03","repo":"flipped-aurora/gin-vue-admin","slug":"id-6f21c6","errorCode":null,"errorMessage":"缺少任务 ID","messagePattern":"缺少任务 ID","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/service/system/sys_timed_task.go","lineNumber":144,"sourceCode":"// CreateTimedTask 创建并按 enabled 调度\nfunc (s *TimedTaskService) CreateTimedTask(ctx context.Context, t *system.SysTimedTask) error {\n\tif err := s.validateTask(t); err != nil {\n\t\treturn err\n\t}\n\tif err := s.checkNameUnique(ctx, t.Name, 0); err != nil {\n\t\treturn err\n\t}\n\tif err := global.GVA_DB.WithContext(ctx).Create(t).Error; err != nil {\n\t\treturn err\n\t}\n\treturn s.ScheduleTask(*t)\n}\n\n// UpdateTimedTask 更新并重新调度。Select 显式列 + Updates:\n// 允许 enabled=false 等零值写入, 同时不碰 created_at/deleted_at。\nfunc (s *TimedTaskService) UpdateTimedTask(ctx context.Context, t *system.SysTimedTask) error {\n\tif t.ID == 0 {\n\t\treturn errors.New(\"缺少任务 ID\")\n\t}\n\tif err := s.validateTask(t); err != nil {\n\t\treturn err\n\t}\n\tif err := s.checkNameUnique(ctx, t.Name, t.ID); err != nil {\n\t\treturn err\n\t}\n\terr := global.GVA_DB.WithContext(ctx).Model(&system.SysTimedTask{}).Where(\"id = ?\", t.ID).\n\t\tSelect(\"name\", \"description\", \"spec\", \"with_seconds\", \"executor_type\", \"method_name\",\n\t\t\t\"params\", \"http_url\", \"http_method\", \"http_header\", \"http_body\", \"http_allow_private\", \"enabled\").\n\t\tUpdates(t).Error\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn s.ScheduleTask(*t)\n}\n\n// DeleteTimedTask 先移出调度再软删","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/service/system/sys_timed_task.go#L126-L162","documentation":"UpdateTimedTask throws \"缺少任务 ID\" when SysTimedTask.ID is zero. Updates are keyed on the primary key, so an update without an ID is ambiguous and rejected before validation or persistence.","triggerScenarios":"Calling UpdateTimedTask with a struct built client-side but never populated with the record's ID; binding a PUT body that omits the id field; using a create-style payload (no id) on the update endpoint.","commonSituations":"Frontend editing a task fetched via a list that didn't select id; int/uint type mismatch so JSON id decodes to 0 (e.g. string \"12\" into a uint field); new form rows submitted as updates.","solutions":["Populate t.ID with the existing record's primary key before calling UpdateTimedTask.","Ensure the request body includes the numeric id field matching the binding tag.","If the id arrives as a string, convert to uint client-side or fix the JSON type.","Verify the list/detail API actually returns and the frontend retains the id field."],"exampleFix":"// before\nsvc.UpdateTimedTask(ctx, &system.SysTimedTask{Name: \"renamed\"}) // ID == 0\n\n// after\nsvc.UpdateTimedTask(ctx, &system.SysTimedTask{ID: existing.ID, Name: \"renamed\", Spec: existing.Spec, ExecutorType: existing.ExecutorType})","handlingStrategy":"validation","validationCode":"if task.ID == 0 {\n    return errors.New(\"cannot update a timed task without a numeric ID\")\n}\n// proceed with svc.UpdateTimedTask(ctx, task)","typeGuard":"func hasID(t system.SysTimedTask) bool { return t.ID != 0 }","tryCatchPattern":"if err := svc.UpdateTimedTask(ctx, task); err != nil {\n    if strings.Contains(err.Error(), \"缺少任务 ID\") {\n        http.Error(w, \"id is required for update\", http.StatusBadRequest)\n        return\n    }\n    http.Error(w, err.Error(), http.StatusInternalServerError)\n}","preventionTips":["Always carry the id from the fetch step into the edit form","Ensure list/detail endpoints include id in the response","Send numeric ids, not numeric-looking strings","Never reuse create payloads on update endpoints"],"tags":["validation","go","primary-key","scheduled-task"],"backgroundTag":"missing-entity-id","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}