{"record":{"id":"dbf61894cffc841b","repo":"Billionmail/BillionMail","slug":"failed-to-get-recipient-count-w","errorCode":null,"errorMessage":"failed to get recipient count: %w","messagePattern":"failed to get recipient count: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/warmup/warmup_with_campaigns.go","lineNumber":110,"sourceCode":"\t\tg.Log().Errorf(ctx, \"AssociateCampaignWithWarmup: failed to create association for task ID %d and warmup ID %d: %v\", taskId, warmupId, err)\n\t\treturn nil, err\n\t}\n\n\tresult := &CampaignWarmupAssociation{\n\t\tCampaignWarmup:   *newLink,\n\t\tEstimatedSeconds: estimatedSeconds,\n\t}\n\n\tg.Log().Infof(ctx, \"Successfully associated task ID %d with warmup ID %d (IP: %s). Estimated time: %d seconds.\", taskId, warmupId, senderIp, estimatedSeconds)\n\treturn result, nil\n}\n\n// CalculateEstimatedTime calculates the estimated sending time in seconds for a given task and IP.\nfunc (s *WarmupCampaignService) CalculateEstimatedTime(ctx context.Context, taskId int64, senderIp string) (int64, error) {\n\t// Get the total number of unsent recipients\n\tunsentCount, err := g.DB().Model(\"recipient_info\").Ctx(ctx).Where(\"task_id\", taskId).Where(\"is_sent\", 0).Count()\n\tif err != nil {\n\t\treturn -1, fmt.Errorf(\"failed to get recipient count: %w\", err)\n\t}\n\n\tif unsentCount == 0 {\n\t\treturn 0, nil\n\t}\n\n\t// Calculate the total hourly sending rate\n\ttotalHourlyRate := 0\n\tproviderGroups := []string{\n\t\tconsts.MailProviderGroupGmail,\n\t\tconsts.MailProviderGroupYahoo,\n\t\tconsts.MailProviderGroupOutlook,\n\t\tconsts.MailProviderGroupApple,\n\t\tconsts.MailProviderGroupProton,\n\t\tconsts.MailProviderGroupZoho,\n\t\tconsts.MailProviderGroupAmazon,\n\t\tconsts.MailProviderGroupOther,\n\t}","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/warmup/warmup_with_campaigns.go#L92-L128","documentation":"WarmupCampaignService.CalculateEstimatedTime counts unsent recipients with SELECT COUNT(*) on recipient_info WHERE task_id = ? AND is_sent = 0. If the count query fails — DB unreachable, bad credentials, missing table/column, or cancelled context — it returns -1 and wraps the cause as 'failed to get recipient count'. Called from AssociateCampaignWithWarmup, this blocks associating a campaign with a warmup task.","triggerScenarios":"recipient_info table missing or renamed, DB connection failure/timeout, context cancelled during the count, task_id column absent after schema drift.","commonSituations":"Deployments with un-run migrations, transient DB outages during warmup scheduling, pool exhaustion under load, wrong environment config pointing at a DB without the warmup schema.","solutions":["Inspect the wrapped error for the concrete DB cause (connection vs schema).","Verify recipient_info exists with task_id and is_sent columns; run migrations.","Test DB connectivity/credentials for the environment's config.","Check DB load/pool settings if it fails only under load.","Retry transient failures with backoff before failing campaign association."],"exampleFix":"// before\nunsentCount, err := g.DB().Model(\"recipient_info\").Ctx(ctx).Where(\"task_id\", taskId).Where(\"is_sent\", 0).Count()\nif err != nil {\n    return -1, fmt.Errorf(\"failed to get recipient count: %w\", err)\n}\n// after\nunsentCount, err := g.DB().Model(\"recipient_info\").Ctx(ctx).\n    Where(\"task_id\", taskId).Where(\"is_sent\", 0).Count()\nif err != nil {\n    return -1, fmt.Errorf(\"failed to get recipient count for task %d: %w\", taskId, err)\n}","handlingStrategy":"retry","validationCode":"// verify warmup schema before associating a campaign\nif _, err := g.DB().Ctx(ctx).Model(\"recipient_info\").Limit(1).One(); err != nil {\n    return fmt.Errorf(\"recipient_info table unavailable: %w\", err)\n}\nif err := g.DB().Ctx(ctx).Exec(\"SELECT 1\"); err != nil {\n    return fmt.Errorf(\"database unavailable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"secs, err := svc.CalculateEstimatedTime(ctx, taskId, senderIp)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to get recipient count\") {\n        // check ctx and DB health, retry transient failures\n        if ctx.Err() != nil {\n            return fmt.Errorf(\"cancelled: %w\", ctx.Err())\n        }\n    }\n    return err\n}\nif secs < 0 {\n    return errors.New(\"unexpected negative estimate\")\n}","preventionTips":["Ensure recipient_info migrations run before warmup features start","Validate taskId exists before calculating estimates","Watch for -1 sentinel returns and treat them as failures","Add retry/backoff around count queries during DB load spikes"],"tags":["database","sql","warmup","count-query"],"backgroundTag":"database-query-failed","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}