{"record":{"id":"0ac5f49e3f517b98","repo":"Billionmail/BillionMail","slug":"get-task-info-failed-w","errorCode":null,"errorMessage":"get task info failed: %w","messagePattern":"get task info failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/batch_mail/task_executor.go","lineNumber":1471,"sourceCode":"\t\t\"max_rate\":      e.rateController.GetMaxRate(),\n\t\t\"duration_sec\":  duration,\n\t}\n}\n\nfunc (e *TaskExecutor) UpdateTaskThreads(taskId int, threads int) error {\n\t// parameter validation\n\tif threads <= 0 {\n\t\treturn fmt.Errorf(\"threads must be greater than zero\")\n\t}\n\n\tif threads > 100 {\n\t\treturn fmt.Errorf(\"threads must be less than 100\")\n\t}\n\n\t// get task info\n\ttask, err := GetTaskInfo(context.Background(), taskId)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"get task info failed: %w\", err)\n\t}\n\n\tif task == nil || task.Id == 0 {\n\t\treturn fmt.Errorf(\"task %d not found\", taskId)\n\t}\n\n\t// record current pool status\n\tvar oldPoolSize int\n\tvar runningWorkers int\n\tif e.pool != nil {\n\t\toldPoolSize = e.pool.Cap()\n\t\trunningWorkers = e.pool.Running()\n\t}\n\n\t// new threads\n\tnewThreads := threads\n\t// calculate new rate limit - 20 emails per thread per second\n\ttargetSendPerThreadPerSecond := 20","sourceCodeStart":1453,"sourceCodeEnd":1489,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/batch_mail/task_executor.go#L1453-L1489","documentation":"After validating the thread count, UpdateTaskThreads loads the task via GetTaskInfo; if that lookup fails, the underlying error is wrapped with fmt.Errorf %w and returned as \"get task info failed: <cause>\". It indicates the task could not be fetched from the database/cache, and the root cause is preserved for errors.Is/As inspection.","triggerScenarios":"Calling UpdateTaskThreads while the database is unreachable, the task table query errors (connection refused, timeout, locked table), or GetTaskInfo's context is cancelled.","commonSituations":"PostgreSQL down or restarting during the call; network partition between app and DB; connection pool exhausted under load; misconfigured DB credentials after a deploy.","solutions":["Read the wrapped cause (%w) via errors.Is/As or the error string to identify the root failure.","Check database connectivity and credentials (psql/health check, docker logs for the postgres container).","Retry the operation once the DB is reachable; add retry with backoff for transient connection errors.","Verify GetTaskInfo's query/table state if the cause is a SQL error."],"exampleFix":"// before: opaque handling\nif err := e.UpdateTaskThreads(id, n); err != nil { log.Print(err) }\n// after\nif err := e.UpdateTaskThreads(id, n); err != nil {\n    var dbErr *pgconn.ConnectError\n    if errors.As(err, &dbErr) { /* alert on DB connectivity */ }\n    log.Printf(\"update threads: %v\", err)\n}","handlingStrategy":"retry","validationCode":"// Go: verify DB reachability before the operation\nif err := g.DB().PingMaster(); err != nil {\n    return fmt.Errorf(\"db unavailable: %w\", err)\n}","typeGuard":"func isDBConnectErr(err error) bool {\n    var netErr net.Error\n    return errors.As(err, &netErr) || strings.Contains(err.Error(), \"connect: \")\n}","tryCatchPattern":"err := executor.UpdateTaskThreads(taskId, threads)\nfor i := 0; i < 3 && isDBConnectErr(err); i++ {\n    time.Sleep(time.Second << i)\n    err = executor.UpdateTaskThreads(taskId, threads)\n}\nif err != nil { log.Printf(\"get task info failed: %v\", err) }","preventionTips":["Monitor PostgreSQL health and connection-pool saturation.","Use errors.Is/As on the wrapped cause instead of string matching alone.","Set sane DB timeouts so failures surface fast and retryable.","Verify credentials/config after every deploy that touches DB settings."],"tags":["database","wrapped-error","batch-mail"],"backgroundTag":"database-unavailable","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}