{"record":{"id":"bf70a0c1a0d14c9b","repo":"Billionmail/BillionMail","slug":"cannot-read-dkim-public-key-v","errorCode":null,"errorMessage":"Cannot read DKIM public key: %v","messagePattern":"Cannot read DKIM public key: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/domains/domains.go","lineNumber":645,"sourceCode":"\t\t\tif err != nil {\n\t\t\t\terr = fmt.Errorf(\"Failed to write DKIM sign config: %v\", err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Restart rspamd service\n\t\t\terr = dk.RestartContainerByName(context.Background(), consts.SERVICES.Rspamd)\n\t\t\tif err != nil {\n\t\t\t\terr = fmt.Errorf(\"Failed to restart rspamd container: %v\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\t// DKIM public key is typically stored in a specific location in the container or host\n\t// Assuming we use docker exec to read the DKIM public key from the rspamd container\n\tdkimPub, err := public.ReadFile(dkimPubPath)\n\tif err != nil {\n\t\terr = fmt.Errorf(\"Cannot read DKIM public key: %v\", err)\n\t\treturn\n\t}\n\n\t// Format DKIM record\n\t// Expected format is a pre-formatted TXT record value like \"v=DKIM1; k=rsa; p=MIIBIjANBg...\"\n\tdkimRecord := strings.TrimSpace(dkimPub)\n\n\t// If the raw public key is read, format it into DNS TXT record format\n\tif !strings.Contains(dkimRecord, \"v=DKIM1\") && !strings.Contains(dkimRecord, \"k=rsa\") && !strings.Contains(dkimRecord, \"p=\") {\n\t\t// Remove possible header/footer markers and newlines\n\t\tdkimRecord = strings.ReplaceAll(dkimRecord, \"-----BEGIN PUBLIC KEY-----\", \"\")\n\t\tdkimRecord = strings.ReplaceAll(dkimRecord, \"-----END PUBLIC KEY-----\", \"\")\n\t\tdkimRecord = strings.ReplaceAll(dkimRecord, \"\\n\", \"\")\n\t\tdkimRecord = strings.TrimSpace(dkimRecord)\n\t\tdkimRecord = fmt.Sprintf(\"v=DKIM1; k=rsa; p=%s\", dkimRecord)\n\t} else {\n\t\tvar ms [][]string\n\t\tms, err = gregex.MatchAllString(`\"([^\"\\r\\n]+)\"`, dkimRecord)","sourceCodeStart":627,"sourceCodeEnd":663,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/domains/domains.go#L627-L663","documentation":"Thrown when the DKIM public key file (dkimPubPath inside/on the rspamd container) cannot be read. The library needs the key's base64 body to assemble the DNS TXT record, so failure here aborts DKIM record generation.","triggerScenarios":"public.ReadFile(dkimPubPath) errors — the DKIM key file was never generated, path changed between rspamd versions, permissions deny read, or the file lives inside the container while the code reads a host path (or vice versa).","commonSituations":"Fresh domain where the keypair generation step was skipped or failed earlier, rspamd image update moving the key location, volume not mounted so the key file is absent on the host, wrong permissions after manual key regeneration.","solutions":["Confirm the DKIM key file exists at dkimPubPath (ls) and regenerate it via RepairDKIMSigningConfig if missing","Fix read permissions/ownership on the key file","Verify the rspamd data volume is mounted so the key path resolves on the host","Check the rspamd version/config for a changed dkim key path and update dkimPubPath accordingly"],"exampleFix":"// before: read fails silently for caller\nif _, err := os.Stat(dkimPubPath); os.IsNotExist(err) {\n    // regenerate keys first via RepairDKIMSigningConfig\n}\ndkimPub, err := public.ReadFile(dkimPubPath)","handlingStrategy":"validation","validationCode":"if fi, err := os.Stat(dkimPubPath); err != nil || fi.IsDir() || fi.Size() == 0 {\n    return fmt.Errorf(\"DKIM public key missing or empty at %s — run RepairDKIMSigningConfig\", dkimPubPath)\n}","typeGuard":"func dkimKeyExists(path string) bool {\n    fi, err := os.Stat(path)\n    return err == nil && fi.Mode().IsRegular() && fi.Size() > 0\n}","tryCatchPattern":"dkimPub, err := public.ReadFile(dkimPubPath)\nif err != nil {\n    log.Printf(\"DKIM public key unreadable at %s: %v — regenerate via RepairDKIMSigningConfig\", dkimPubPath, err)\n    return err\n}","preventionTips":["Generate DKIM keys as part of domain onboarding before exposing DNS record endpoints","Verify the rspamd data volume mapping matches dkimPubPath after image upgrades","Alert on empty or zero-length key files"],"tags":["filesystem","dkim","missing-file","rspamd"],"backgroundTag":"dkim-key-not-found","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"}