{"record":{"id":"9b49cd461b96b3eb","repo":"Billionmail/BillionMail","slug":"fail-to-check-domain-w","errorCode":null,"errorMessage":"fail to check domain: %w","messagePattern":"fail to check domain: %w","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/controller/domains/domains_v1_set_ssl.go","lineNumber":19,"sourceCode":"package domains\n\nimport (\n\t\"billionmail-core/internal/consts\"\n\t\"billionmail-core/internal/service/domains\"\n\t\"billionmail-core/internal/service/mail_service\"\n\t\"billionmail-core/internal/service/public\"\n\t\"context\"\n\t\"fmt\"\n\n\t\"billionmail-core/api/domains/v1\"\n)\n\nfunc (c *ControllerV1) SetSSL(ctx context.Context, req *v1.SetSSLReq) (res *v1.SetSSLRes, err error) {\n\tres = &v1.SetSSLRes{}\n\n\tif ex, err1 := domains.Exists(ctx, req.Domain); !ex {\n\t\tif err1 != nil {\n\t\t\tres.SetError(fmt.Errorf(\"fail to check domain: %w\", err1))\n\t\t\treturn\n\t\t}\n\n\t\tres.SetError(fmt.Errorf(\"domain %s does not exist\", req.Domain))\n\t\treturn\n\t}\n\n\tcrt := mail_service.NewCertificate()\n\n\tdefer crt.Close()\n\n\terr = crt.SetSNI(public.FormatMX(req.Domain), req.Certificate, req.Key)\n\n\tif err != nil {\n\t\tres.SetError(fmt.Errorf(\"fail to set ssl: %w\", err))\n\t\treturn\n\t}\n","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/controller/domains/domains_v1_set_ssl.go#L1-L37","documentation":"SetSSL wraps an error returned by domains.Exists(ctx, req.Domain) with 'fail to check domain: %w'. This is distinct from the 'domain does not exist' branch: it fires only when the existence check itself errored (usually a database failure), so the operation aborts before touching SSL config.","triggerScenarios":"domains.Exists(ctx, req.Domain) returns (ex=false, err1 != nil) — e.g. the SELECT against the domains table fails due to DB unavailability, timeout, or schema mismatch while handling a SetSSL request.","commonSituations":"Postgres down or unreachable during an SSL setup; wrong DB config after migration; query timeout on a large domains table; transient network error between app and database in Compose deployments.","solutions":["Inspect the wrapped cause for the actual DB error and fix that first (connectivity, credentials, schema).","Verify the database is healthy and reachable before retrying the SetSSL call.","Confirm the domains table exists and migrations are current.","Retry the request once the DB issue is resolved; the check is transient-failure prone, not a request-shape problem."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// pre-flight DB check\nif err := gdb.Config().Master.Ping(); err != nil {\n\treturn fmt.Errorf(\"database unreachable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"_, err := client.SetSSL(ctx, req)\nif err != nil {\n\tif strings.Contains(err.Error(), \"fail to check domain\") {\n\t\treturn backoff.Retry(func() error {\n\t\t\t_, err = client.SetSSL(ctx, req)\n\t\t\treturn err\n\t\t}, backoff.WithMaxRetries(backoff.NewExponentialBackOff(), 3))\n\t}\n\treturn err\n}","preventionTips":["Check DB connectivity before SSL operations","Ensure migrations keep the domains table schema current","Distinguish 'check failed' from 'domain not found' when triaging","Add retry with backoff for transient DB errors in domain checks"],"tags":["database","ssl","domains","postgresql"],"backgroundTag":"database-query-failed","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"}