{"record":{"id":"6e6a74c9c432d096","repo":"Billionmail/BillionMail","slug":"certificate-not-found-in-database-v","errorCode":null,"errorMessage":"certificate not found in database: %v","messagePattern":"certificate not found in database: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/mail_service/certificate.go","lineNumber":509,"sourceCode":"\t\tEndtime     int    `json:\"endtime\"`\n\t\tStatus      int    `json:\"status\"`\n\t\tSubject     string `json:\"subject\"`\n\t\tIssuer      string `json:\"issuer\"`\n\t\tNotAfter    string `json:\"not_after\"`\n\t\tNotBefore   string `json:\"not_before\"`\n\t\tDns         string `json:\"dns\"`\n\t}\n\n\terr = g.DB().Model(\"letsencrypts\").\n\t\tWhere(\"dns::jsonb ? $1\", public.FormatMX(domain)).\n\t\tWhere(\"status = 1\").\n\t\tWhere(\"endtime > ?\", time.Now().Unix()).\n\t\tOrder(\"endtime desc\").\n\t\tLimit(1).\n\t\tScan(&cert)\n\n\tif err != nil {\n\t\treturn certInfo, fmt.Errorf(\"certificate not found in database: %v\", err)\n\t}\n\n\tif cert.Certificate == \"\" {\n\t\treturn certInfo, fmt.Errorf(\"certificate content is empty in database\")\n\t}\n\n\t// Parse certificate information\n\terr = gconv.Struct(acme.GetCertInfo(cert.Certificate), &certInfo)\n\tif err != nil {\n\t\treturn certInfo, fmt.Errorf(\"failed to parse certificate info: %v\", err)\n\t}\n\n\t// Set certificate content\n\tcertInfo.CertPem = cert.Certificate\n\tcertInfo.KeyPem = cert.PrivateKey\n\n\treturn certInfo, nil\n}","sourceCodeStart":491,"sourceCodeEnd":527,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/mail_service/certificate.go#L491-L527","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ninfo, err := GetSSLInfo(ctx)\nif err != nil { return err }\n// after\ninfo, err := GetSSLInfo(ctx)\nif err != nil {\n    if strings.Contains(err.Error(), \"certificate not found in database\") {\n        return issueNewCertificate(ctx) // bootstrap: no cert yet\n    }\n    return err\n}","handlingStrategy":"fallback","validationCode":"var count int\nerr := g.DB().Model(\"certificates\").Where(\"endtime > ?\", time.Now().Unix()).Count(&count)\nif err != nil || count == 0 {\n    // no valid certificate yet — trigger issuance instead of reading\n}","typeGuard":null,"tryCatchPattern":"info, err := GetSSLInfo(ctx)\nif err != nil {\n    if strings.Contains(err.Error(), \"certificate not found in database\") {\n        return issueNewCertificate(ctx)\n    }\n    return err // real DB problem\n}","preventionTips":["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."],"tags":["database","ssl","certificate","mail-service"],"backgroundTag":"certificate-not-found","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}