Billionmail/BillionMail · error
certificate not found in database: %v
Error message
certificate not found in database: %v
What it means
getSSLInfoFromDatabase queries the certificate table for a non-expired certificate (endtime > now, newest first). Any DB error (connection failure, missing table, query error) is wrapped as 'certificate not found in database'. Note this conflates real DB errors with the no-row case, since Scan returns nil error when zero rows match.
Source
Thrown at core/internal/service/mail_service/certificate.go:509
Endtime int `json:"endtime"`
Status int `json:"status"`
Subject string `json:"subject"`
Issuer string `json:"issuer"`
NotAfter string `json:"not_after"`
NotBefore string `json:"not_before"`
Dns string `json:"dns"`
}
err = g.DB().Model("letsencrypts").
Where("dns::jsonb ? $1", public.FormatMX(domain)).
Where("status = 1").
Where("endtime > ?", time.Now().Unix()).
Order("endtime desc").
Limit(1).
Scan(&cert)
if err != nil {
return certInfo, fmt.Errorf("certificate not found in database: %v", err)
}
if cert.Certificate == "" {
return certInfo, fmt.Errorf("certificate content is empty in database")
}
// Parse certificate information
err = gconv.Struct(acme.GetCertInfo(cert.Certificate), &certInfo)
if err != nil {
return certInfo, fmt.Errorf("failed to parse certificate info: %v", err)
}
// Set certificate content
certInfo.CertPem = cert.Certificate
certInfo.KeyPem = cert.PrivateKey
return certInfo, nil
}View on GitHub (pinned to fc36c76c05)
Solutions
- Check DB connectivity and that the certificate table exists (run migrations).
- Issue/obtain a certificate first (via the SSL issuance flow) so a row with future endtime exists.
- Read the wrapped %v error to distinguish a DB failure from genuinely no certificate.
- Verify the query's Where('endtime > ?') isn't filtering out an expired cert that should be renewed.
Example fix
// before
info, err := GetSSLInfo(ctx)
if err != nil { return err }
// after
info, err := GetSSLInfo(ctx)
if err != nil {
if strings.Contains(err.Error(), "certificate not found in database") {
return issueNewCertificate(ctx) // bootstrap: no cert yet
}
return err
} Defensive patterns
Strategy: fallback
Validate before calling
var count int
err := g.DB().Model("certificates").Where("endtime > ?", time.Now().Unix()).Count(&count)
if err != nil || count == 0 {
// no valid certificate yet — trigger issuance instead of reading
} Try / catch
info, err := GetSSLInfo(ctx)
if err != nil {
if strings.Contains(err.Error(), "certificate not found in database") {
return issueNewCertificate(ctx)
}
return err // real DB problem
} Prevention
- Ensure a certificate is issued during initial setup before status checks.
- Run DB migrations as part of deployment.
- Alert on certificates nearing endtime so rows never go stale/absent.
When it happens
Trigger: Calling GetSSLInfo when the certificate table is missing/unreachable, or the query itself errors. Called during SSL status checks and before sending mail that needs the current certificate.
Common situations: Fresh install where no certificate has ever been issued; database down or credentials wrong; schema migration not applied so the cert table doesn't exist.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- certificate content is empty in database
- fail to check domain: %w
- fail to set ssl: %w
- Failed to create directory: {}
- Failed to save certificate file: {}
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/6e6a74c9c432d096.
Report an issue: GitHub.