flipped-aurora/gin-vue-admin · error
任务名 %s 已存在
Error message
任务名 %s 已存在
What it means
checkNameUnique enforces uniqueness of task names among active (non-soft-deleted) rows at the service layer, because the soft-delete design prevents a DB-level unique index. It counts matching names (excluding the current row id when updating) and returns this error if any exist.
Source
Thrown at server/service/system/sys_timed_task.go:88
}
default:
return fmt.Errorf("executorType 必须为 %s 或 %s", system.TimedTaskExecutorMethod, system.TimedTaskExecutorHTTP)
}
return nil
}
// checkNameUnique 软删除下不建 DB 唯一索引, 由服务层保证活跃行内唯一
func (s *TimedTaskService) checkNameUnique(ctx context.Context, name string, excludeID uint) error {
var count int64
db := global.GVA_DB.WithContext(ctx).Model(&system.SysTimedTask{}).Where("name = ?", name)
if excludeID > 0 {
db = db.Where("id <> ?", excludeID)
}
if err := db.Count(&count).Error; err != nil {
return err
}
if count > 0 {
return fmt.Errorf("任务名 %s 已存在", name)
}
return nil
}
// ScheduleTask 幂等调度: 先 Clear 再按 enabled 重新注册
func (s *TimedTaskService) ScheduleTask(t system.SysTimedTask) error {
name := timedTaskCronName(t.ID)
global.GVA_Timer.Clear(name)
if !t.Enabled {
return nil
}
taskCopy := t // 值拷贝, 供回调闭包持有(更新任务时会整体重调度, 不会读到旧配置)
fn := func() { s.RunTask(taskCopy, system.TimedTaskTriggerAuto) }
var err error
if t.WithSeconds {
_, err = global.GVA_Timer.AddTaskByFuncWithSecond(name, t.Spec, fn, t.Name)
} else {
_, err = global.GVA_Timer.AddTaskByFunc(name, t.Spec, fn, t.Name)View on GitHub (pinned to 3136500ef3)
Solutions
- Choose a different, unique task name before saving
- If the desired name belongs to a soft-deleted row, purge/rename that old row first or pick a fresh name
- For updates, ensure excludeID (the task's own id) is passed so renaming to its own current name does not collide with a different row
Example fix
// before
{"name":" nightly-sync", ...} // already used by another enabled task
// after
{"name":"nightly-sync-v2", ...} Defensive patterns
Strategy: validation
Validate before calling
var count int64
global.GVA_DB.Model(&system.SysTimedTask{}).
Where("name = ? AND id <> ?", proposedName, excludeID).
Count(&count)
if count > 0 {
// surface a friendly duplicate-name message before calling the API
} Try / catch
if err := svc.CreateTimedTask(ctx, req); err != nil {
if strings.Contains(err.Error(), "已存在") {
// show 'task name already in use' and prompt for a new name
return
}
return err
} Prevention
- Append a timestamp or id suffix when duplicating tasks
- Pre-check names with a lightweight existence query in the UI on blur
- Handle the TOCTOU race on the server (recheck before insert or use a serializable transaction)
When it happens
Trigger: CreateTimedTask with a name that another live task already uses, or UpdateTimedTask renaming a task to a name owned by a different live task (excludeID filters out the task's own row).
Common situations: Cloning/duplicating a task without renaming it; two admins creating similarly named tasks concurrently (TOCTOU race between count and insert); renaming after a soft-delete left the original name visible in an old UI list; seed/init data colliding with user-created tasks.
Related errors
AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31).
Data as JSON: /api/errors/5c3343ac36d43790.
Report an issue: GitHub.