flipped-aurora/gin-vue-admin · error
缺少任务 ID
Error message
缺少任务 ID
What it means
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.
Source
Thrown at server/service/system/sys_timed_task.go:144
// CreateTimedTask 创建并按 enabled 调度
func (s *TimedTaskService) CreateTimedTask(ctx context.Context, t *system.SysTimedTask) error {
if err := s.validateTask(t); err != nil {
return err
}
if err := s.checkNameUnique(ctx, t.Name, 0); err != nil {
return err
}
if err := global.GVA_DB.WithContext(ctx).Create(t).Error; err != nil {
return err
}
return s.ScheduleTask(*t)
}
// UpdateTimedTask 更新并重新调度。Select 显式列 + Updates:
// 允许 enabled=false 等零值写入, 同时不碰 created_at/deleted_at。
func (s *TimedTaskService) UpdateTimedTask(ctx context.Context, t *system.SysTimedTask) error {
if t.ID == 0 {
return errors.New("缺少任务 ID")
}
if err := s.validateTask(t); err != nil {
return err
}
if err := s.checkNameUnique(ctx, t.Name, t.ID); err != nil {
return err
}
err := global.GVA_DB.WithContext(ctx).Model(&system.SysTimedTask{}).Where("id = ?", t.ID).
Select("name", "description", "spec", "with_seconds", "executor_type", "method_name",
"params", "http_url", "http_method", "http_header", "http_body", "http_allow_private", "enabled").
Updates(t).Error
if err != nil {
return err
}
return s.ScheduleTask(*t)
}
// DeleteTimedTask 先移出调度再软删View on GitHub (pinned to 3136500ef3)
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.
Example fix
// before
svc.UpdateTimedTask(ctx, &system.SysTimedTask{Name: "renamed"}) // ID == 0
// after
svc.UpdateTimedTask(ctx, &system.SysTimedTask{ID: existing.ID, Name: "renamed", Spec: existing.Spec, ExecutorType: existing.ExecutorType}) Defensive patterns
Strategy: validation
Validate before calling
if task.ID == 0 {
return errors.New("cannot update a timed task without a numeric ID")
}
// proceed with svc.UpdateTimedTask(ctx, task) Type guard
func hasID(t system.SysTimedTask) bool { return t.ID != 0 } Try / catch
if err := svc.UpdateTimedTask(ctx, task); err != nil {
if strings.Contains(err.Error(), "缺少任务 ID") {
http.Error(w, "id is required for update", http.StatusBadRequest)
return
}
http.Error(w, err.Error(), http.StatusInternalServerError)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31).
Data as JSON: /api/errors/6f21c6f547e9ac03.
Report an issue: GitHub.