Billionmail/BillionMail · error
failed to load contacts: %v
Error message
failed to load contacts: %v
What it means
preloadData fetches bm_contacts rows for all recipient emails to build the in-memory contact cache. If the SELECT ... WHERE email IN (...) on bm_contacts fails, it wraps the driver error as "failed to load contacts: %v". Missing contacts are not an error here; only an actual DB read failure triggers this message.
Source
Thrown at core/internal/service/batch_mail/api_mail_send.go:395
templateIds = append(templateIds, t.TemplateId)
}
// Batch query email templates
var emailTemplates []entity.EmailTemplate
err = g.DB().Model("email_templates").
WhereIn("id", templateIds).
Ctx(ctx).
Scan(&emailTemplates)
if err != nil {
return nil, fmt.Errorf("failed to load email templates: %v", err)
}
// Batch query contacts
var contacts []entity.Contact
err = g.DB().Model("bm_contacts").
WhereIn("email", recipientEmails).
Ctx(ctx).
Scan(&contacts)
if err != nil {
return nil, fmt.Errorf("failed to load contacts: %v", err)
}
// Build cache
cache := &CacheData{
ApiTemplates: make(map[int]entity.ApiTemplates),
EmailTemplates: make(map[int]entity.EmailTemplate),
Contacts: make(map[string]entity.Contact),
}
for _, t := range apiTemplates {
cache.ApiTemplates[t.Id] = t
}
for _, t := range emailTemplates {
cache.EmailTemplates[t.Id] = t
}
for _, c := range contacts {
cache.Contacts[c.Email] = c
}
View on GitHub (pinned to fc36c76c05)
Solutions
- Check the wrapped underlying error and DB health
- Chunk the recipient email list into smaller batches for the WHERE IN query
- Verify SELECT permission on bm_contacts and that the table schema matches the entity
- Add a timeout/lock diagnosis if the query times out on large lists
Example fix
// before: one huge WHERE IN
err = g.DB().Model("bm_contacts").WhereIn("email", recipientEmails).Ctx(ctx).Scan(&contacts)
// after: chunked loads
const chunk = 500
for i := 0; i < len(recipientEmails); i += chunk {
end := i + chunk
if end > len(recipientEmails) { end = len(recipientEmails) }
var part []entity.Contact
if err = g.DB().Model("bm_contacts").WhereIn("email", recipientEmails[i:end]).Ctx(ctx).Scan(&part); err != nil {
return nil, fmt.Errorf("failed to load contacts: %v", err)
}
contacts = append(contacts, part...)
} Defensive patterns
Strategy: validation
Validate before calling
const maxIn = 1000
if len(recipientEmails) > maxIn {
return nil, fmt.Errorf("recipient list too large for single query: %d", len(recipientEmails))
} Try / catch
cache, err := preloadData(ctx, apiIds)
if err != nil && strings.Contains(err.Error(), "failed to load contacts") {
// chunk recipients and retry, or fail the batch gracefully
return err
} Prevention
- Chunk WHERE IN clauses (a few hundred items per query)
- Normalize/validate emails before querying bm_contacts
- Ensure an index on bm_contacts.email for large lookups
When it happens
Trigger: ProcessApiMailQueue -> preloadData when the bm_contacts query errors: DB outage, prepared statement failure with a very large recipient list (e.g. WHERE IN with thousands of emails exceeding parameter limits), timeout, or permission denial.
Common situations: Very large recipient batches producing oversized WHERE IN clauses; DB connection dropped between the template and contact queries; stale indexes/locks slowing the query past timeout.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- failed to load API templates: %v
- failed to load email templates: %v
- failed to get task info: %w
- failed to get all domains: %w
- fail to check domain: %w
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/a43d268a981a4785.
Report an issue: GitHub.