Billionmail/BillionMail · error

query password failed: %w

Error message

query password failed: %w

What it means

PasswordPlainByEmail reads the mailbox row's password_encode column for the given username. A database error during that query (connection failure, table missing, SQL error) is wrapped as 'query password failed', keeping the original error via %w for errors.Is/As inspection.

Source

Thrown at core/internal/service/mail_service/sending.go:157

	es.Password, err = PasswordPlainByEmail(context.Background(), email)

	if err != nil {
		return
	}

	if !es.IsConfigured() {
		err = errors.New("Email Sender not configured")
		return
	}

	return
}

// PasswordPlainByEmail
func PasswordPlainByEmail(ctx context.Context, email string) (string, error) {
	val, err := g.DB().Model("mailbox").Where("username", email).Value("password_encode")
	if err != nil {
		return "", fmt.Errorf("query password failed: %w", err)
	}
	if val.IsEmpty() {
		return "", fmt.Errorf("password not found for %s", email)
	}
	rawHex, err := hex.DecodeString(val.String())
	if err != nil {
		return "", fmt.Errorf("hex decode failed: %w", err)
	}
	plainBytes, err := base64.StdEncoding.DecodeString(string(rawHex))
	if err != nil {
		return "", fmt.Errorf("base64 decode failed: %w", err)
	}
	return string(plainBytes), nil
}

// Close closes the SMTP connection
func (e *EmailSender) Close() {
	_ = e.Disconnect()

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Check DB connectivity and server logs; confirm Postgres is up.
  2. Run migrations to ensure the mailbox table exists with the password_encode column.
  3. Verify the app's DB credentials have SELECT permission on mailbox.
  4. Use errors.Is/errors.As on the wrapped cause to identify the driver-level error.

Example fix

// before
pass, err := PasswordPlainByEmail(ctx, email)
if err != nil { return err }
// after
pass, err := PasswordPlainByEmail(ctx, email)
if err != nil {
    var dbErr *pgconn.PgError
    if errors.As(err, &dbErr) {
        log.Printf("database error fetching mailbox password: %s", dbErr.Message)
    }
    return err
}
Defensive patterns

Strategy: retry

Validate before calling

hasTable, err := g.DB().Model("information_schema.tables").
    Where("table_name = 'mailbox'").Count()
if err != nil || hasTable == 0 {
    return errors.New("mailbox table missing — run migrations before sending")
}

Try / catch

pass, err := PasswordPlainByEmail(ctx, email)
if err != nil {
    var cause error
    errors.As(err, &cause) // wrapped with %w, inspect DB driver error
    if isTransient(cause) {
        time.Sleep(time.Second)
        pass, err = PasswordPlainByEmail(ctx, email)
    }
    return pass, err
}

Prevention

When it happens

Trigger: NewEmailSenderWithLocal → PasswordPlainByEmail when the mailbox table is unavailable, the DB connection is broken, or the query is rejected (permissions, schema mismatch).

Common situations: Postgres down or restarting; migrations not applied so `mailbox` table is absent; DB user lacks SELECT on mailbox; connection pool exhausted.

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/d458ba0a047e351c. Report an issue: GitHub.