Billionmail/BillionMail · error
task %d not found
Error message
task %d not found
What it means
UpdateTaskThreads checks the task returned by GetTaskInfo and rejects the update with "task %d not found" when the record is nil or has Id == 0. This distinguishes a successful lookup with no matching row from a hard database failure.
Source
Thrown at core/internal/service/batch_mail/task_executor.go:1475
func (e *TaskExecutor) UpdateTaskThreads(taskId int, threads int) error {
// parameter validation
if threads <= 0 {
return fmt.Errorf("threads must be greater than zero")
}
if threads > 100 {
return fmt.Errorf("threads must be less than 100")
}
// get task info
task, err := GetTaskInfo(context.Background(), taskId)
if err != nil {
return fmt.Errorf("get task info failed: %w", err)
}
if task == nil || task.Id == 0 {
return fmt.Errorf("task %d not found", taskId)
}
// record current pool status
var oldPoolSize int
var runningWorkers int
if e.pool != nil {
oldPoolSize = e.pool.Cap()
runningWorkers = e.pool.Running()
}
// new threads
newThreads := threads
// calculate new rate limit - 20 emails per thread per second
targetSendPerThreadPerSecond := 20
newRate := newThreads * targetSendPerThreadPerSecond * 60
// create new rate controller
e.rateController = NewSimpleRateController(newRate)View on GitHub (pinned to fc36c76c05)
Solutions
- Verify the taskId exists (query the tasks table or refresh the task list).
- In the caller, validate taskId > 0 and handle 'not found' by reloading current tasks before updating.
- If the task was deleted, recreate it or drop the pending update rather than retrying.
- Check for soft-delete/tenant filters in GetTaskInfo that may hide the row legitimately.
Example fix
// before: no existence check client-side
await api.updateTaskThreads(deletedTaskId, 10)
// after
const task = tasks.value.find(t => t.id === taskId)
if (!task) { message.error('Task no longer exists'); return }
await api.updateTaskThreads(task.id, 10) Defensive patterns
Strategy: validation
Validate before calling
// Go: confirm the task exists before updating
task, err := GetTaskInfo(context.Background(), taskId)
if err != nil { return err }
if task == nil || task.Id == 0 {
return fmt.Errorf("task %d not found; refresh task list", taskId)
} Type guard
func taskExists(taskId int, tasks []*model.Task) bool {
return taskId > 0 && slices.ContainsFunc(tasks, func(t *model.Task) bool { return t.Id == taskId })
} Try / catch
if err := executor.UpdateTaskThreads(taskId, threads); err != nil {
if strings.Contains(err.Error(), fmt.Sprintf("task %d not found", taskId)) {
// reload tasks in UI / remove stale entry; do not retry blindly
return ErrTaskGone
}
return err
} Prevention
- Refresh task lists after deletions and before issuing updates.
- Validate taskId > 0 at the handler (a missing param decodes to 0).
- Treat 'not found' as terminal: never auto-retry with the same id.
- Check soft-delete filters if a task should exist but is reported missing.
When it happens
Trigger: Calling UpdateTaskThreads with a taskId that does not exist in the tasks table, references a deleted task, or where GetTaskInfo returns an empty struct for an id-only filter miss.
Common situations: Stale UI list showing a task deleted by another admin; off-by-one or wrong-type ids (string id parsed to 0) from client requests; tasks removed by a cleanup job while an update was in flight.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- JWT missing group_token claim
- end_time must greater than start_time
- threads must be greater than zero
- threads must be less than 100
- required column 'email' not found
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/677df0224722eba1.
Report an issue: GitHub.