Billionmail/BillionMail · error

failed to check alias existence: %v

Error message

failed to check alias existence: %v

What it means

setCatchall (called from Add and Update in domains/domains.go) queries the alias table for a row with the given address+domain before inserting or updating the catchall mapping; a database failure during this existence check is wrapped as 'failed to check alias existence: %v'. The %v carries the underlying GoFrame/PostgreSQL error.

Source

Thrown at core/internal/service/domains/domains.go:54

		result[i] = v1.BlacklistDetail{
			Blacklist: detail.Blacklist,
			Response:  detail.Response,
			Time:      detail.Time,
		}
	}
	return result
}

func setCatchall(ctx context.Context, domainName, catchall string) error {
	address := fmt.Sprintf("@%s", domainName)
	if catchall != "" {
		var count int
		count, err := g.DB().Model("alias").
			Where("address", address).
			Where("domain", domainName).
			Count()
		if err != nil {
			return fmt.Errorf("failed to check alias existence: %v", err)
		}
		if count > 0 {
			_, err = g.DB().Model("alias").
				Where("address", address).
				Where("domain", domainName).
				Data(g.Map{"goto": catchall, "active": 1, "update_time": time.Now().Unix()}).
				Update()
			if err != nil {
				return fmt.Errorf("failed to update alias: %v", err)
			}
		} else {
			_, err = g.DB().Model("alias").Data(g.Map{
				"address":     address,
				"goto":        catchall,
				"domain":      domainName,
				"active":      1,
				"create_time": time.Now().Unix(),
				"update_time": time.Now().Unix(),

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Check the wrapped error and PostgreSQL logs (docker logs / journalctl -u postgresql) for the root cause
  2. Verify DB connectivity and that the alias table exists with correct migrations applied
  3. Grant the app DB role SELECT/INSERT/UPDATE on the alias table
  4. Retry the operation once transient connection errors are resolved; check pool settings if saturated

Example fix

// before
count, err := g.DB().Model("alias").
	Where("address", address).
	Where("domain", domainName).
	Count()
if err != nil {
	return fmt.Errorf("failed to check alias existence: %v", err)
}
// after
count, err := g.DB().Model("alias").
	Where("address", address).
	Where("domain", domainName).
	Count()
if err != nil {
	return fmt.Errorf("failed to check alias existence (address=%s domain=%s): %w", address, domainName, err)
}
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight: DB reachable and alias table present
if err := g.DB().Ping(ctx); err != nil {
	return fmt.Errorf("database unreachable: %w", err)
}
if n, err := g.DB().Model("alias").Count(); err != nil {
	return fmt.Errorf("alias table not queryable (migrations applied?): %w", err)
} else { _ = n }

Try / catch

err := setCatchall(domainName, catchall)
if err != nil && strings.Contains(err.Error(), "failed to check alias existence") {
	// transient DB issue: back off and retry once
	time.Sleep(2 * time.Second)
	err = setCatchall(domainName, catchall)
}

Prevention

When it happens

Trigger: Add or Update of a domain with catchall enabled when the query g.DB().Model("alias").Where("address", address).Where("domain", domainName).Count() fails: database down, connection pool exhausted, permission denied on the alias table, table missing (migration not run), lock timeout, or invalid characters in address causing a driver error.

Common situations: PostgreSQL restarted or unreachable mid-request; schema migrations not applied so the alias table doesn't exist; DB user lacking SELECT on alias; connection saturation under load; deadlock/lock timeout from a concurrent alias update.

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


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