Billionmail/BillionMail · error

Failed to update abnormal recipient: %w

Error message

Failed to update abnormal recipient: %w

What it means

Within BatchUpsertAbnormalRecipients, existing recipients are updated with count+1/description/add_type. If that UPDATE statement fails (deadlock, lock timeout, connection reset, constraint violation), this wrapped error aborts the remaining batch.

Source

Thrown at core/internal/service/abnormal_recipient/abnormal_recipient.go:115

	var existList []entity.AbnormalRecipient
	err := g.DB().Model("abnormal_recipient").WhereIn("recipient", recipients).Scan(&existList)
	if err != nil {
		return fmt.Errorf("Failed to query existing abnormal recipients: %w", err)
	}
	existMap := make(map[string]*entity.AbnormalRecipient)
	for _, r := range existList {
		existMap[r.Recipient] = &r
	}
	// 1. Update the existing one count+1
	for _, r := range existList {
		_, err := g.DB().Model("abnormal_recipient").Where("id", r.Id).Data(g.Map{
			"count":       r.Count + 1,
			"description": description,
			"add_type":    addType,
		}).Update()
		if err != nil {

			return fmt.Errorf("Failed to update abnormal recipient: %w", err)
		}

	}
	// 2. Inserting something that doesn't exist
	var insertList []g.Map
	for _, recipient := range recipients {
		if _, ok := existMap[recipient]; !ok {
			insertList = append(insertList, g.Map{
				"recipient":   recipient,
				"count":       1,
				"add_type":    addType,
				"description": description,
				"create_time": now,
			})
		}
	}
	if len(insertList) > 0 {

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Retry the whole batch on serialization/deadlock errors (SQLSTATE 40P01, 40001).
  2. Serialize concurrent writers or use a lock (advisory lock / SELECT FOR UPDATE).
  3. Verify schema columns count/description/add_type match the entity.
  4. Check connection pool settings for idle timeouts.

Example fix

// before
_ = abnormal_recipient.BatchUpsertAbnormalRecipients(ctx, recipients, addType, desc)
// after
err := abnormal_recipient.BatchUpsertAbnormalRecipients(ctx, recipients, addType, desc)
if err != nil && isRetryableSQLState(err) {
	err = abnormal_recipient.BatchUpsertAbnormalRecipients(ctx, recipients, addType, desc)
}
Defensive patterns

Strategy: retry

Try / catch

err := abnormal_recipient.BatchUpsertAbnormalRecipients(ctx, recs, addType, desc)
if err != nil {
	var pqErr *pq.Error
	if errors.As(err, &pqErr) && (pqErr.Code == "40P01" || pqErr.Code == "40001") {
		// deadlock/serialization: retry the whole batch once
	}
}

Prevention

When it happens

Trigger: Concurrent batch upserts updating the same rows (deadlock/serialization failure); DB connection dropped mid-loop; column mismatch after schema change.

Common situations: Two cron jobs (e.g. AbnormalRecipientAutoStat and a manual import) running simultaneously; long transactions holding row locks; postgres restart during a large import.

Related errors


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/7ae9ef12d4dbf8db. Report an issue: GitHub.