{"record":{"id":"a4a7edf9e3e1019c","repo":"Billionmail/BillionMail","slug":"failed-to-query-relay-domain-mappings-v","errorCode":null,"errorMessage":"failed to query relay domain mappings: %v","messagePattern":"failed to query relay domain mappings: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/domains/domains.go","lineNumber":376,"sourceCode":"\n\treturn domains, err\n}\n\n// GetRelayDomains returns a set of domains that have active SMTP relay mappings.\n// These domains should be excluded from local DKIM signing since the relay provider\n// (e.g. SES, SendGrid) adds its own DKIM signature.\nfunc GetRelayDomains(ctx context.Context) (map[string]bool, error) {\n\ttype mapping struct {\n\t\tSenderDomain string `json:\"sender_domain\"`\n\t}\n\tvar mappings []mapping\n\terr := g.DB().Model(\"bm_relay_domain_mapping rdm\").\n\t\tLeftJoin(\"bm_relay_config rc\", \"rc.id = rdm.relay_id\").\n\t\tWhere(\"rc.active\", 1).\n\t\tFields(\"rdm.sender_domain\").\n\t\tScan(&mappings)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to query relay domain mappings: %v\", err)\n\t}\n\n\tresult := make(map[string]bool, len(mappings))\n\tfor _, m := range mappings {\n\t\tdomain := strings.TrimPrefix(m.SenderDomain, \"@\")\n\t\tif domain != \"\" {\n\t\t\tresult[domain] = true\n\t\t}\n\t}\n\treturn result, nil\n}\n\nfunc Exists(ctx context.Context, domainName string) (bool, error) {\n\tcount, err := g.DB().Model(\"domain\").\n\t\tCtx(ctx).\n\t\tWhere(\"domain\", domainName).\n\t\tCount()\n","sourceCodeStart":358,"sourceCodeEnd":394,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/domains/domains.go#L358-L394","documentation":"GetRelayDomains queries bm_relay_domain_mapping joined to bm_relay_config to list sender domains with an active relay config, returning a set used to skip DKIM signing setup for relay-mapped domains. This error wraps the SQL Scan failure. Callers (getDKIMRecordWithKeySize, RepairDKIMSigningConfig) receive nil and must handle the degraded state.","triggerScenarios":"Any DKIM record/repair flow touching a domain when the SELECT rdm.sender_domain FROM bm_relay_domain_mapping rdm LEFT JOIN bm_relay_config rc ... fails — table missing (schema not migrated), DB down, or malformed query/column rename.","commonSituations":"Older deployments missing bm_relay_* tables; failed migration; DB credentials expired; column renamed in an upgrade causing SQL syntax error.","solutions":["Check the wrapped %v error for 'relation does not exist' → run the schema migrations for bm_relay_domain_mapping / bm_relay_config","Verify PostgreSQL connectivity and credentials","Confirm both tables and the rc.active and rdm.sender_domain columns exist with expected names","As a stopgap, treat relay lookup failure as non-fatal for DKIM reads and log a warning"],"exampleFix":"// before\nif err != nil { return nil, fmt.Errorf(\"failed to query relay domain mappings: %v\", err) }\n// after\nif err != nil {\n    logger.Warnf(ctx, \"relay domain lookup failed: %v — assuming no relay domains\", err)\n    return map[string]bool{}, nil // degrade gracefully for DKIM read paths\n}","handlingStrategy":"fallback","validationCode":"exists, err := g.DB().Model(\"information_schema.tables\").Where(\"table_name\", \"bm_relay_domain_mapping\").Count()\nif err != nil || exists == 0 { return map[string]bool{}, nil } // schema not migrated yet","typeGuard":null,"tryCatchPattern":"relayDomains, relayErr := GetRelayDomains(ctx)\nif relayErr != nil {\n    logger.Warnf(ctx, \"relay lookup failed, assuming empty: %v\", relayErr)\n    relayDomains = map[string]bool{}\n}","preventionTips":["Run schema migrations for bm_relay_* tables before enabling DKIM features","Add the relay query to DB connectivity smoke tests","Treat relay lookup as advisory on read paths, required on repair paths","Keep table/column names in one consts/model layer to avoid drift"],"tags":["database","sql","relay","dkim","migration"],"backgroundTag":"sql-query-failed","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}