{"record":{"id":"9a3d7c7b6a9ee1cc","repo":"Billionmail/BillionMail","slug":"failed-to-generate-dkim-key-pair-v","errorCode":null,"errorMessage":"Failed to generate DKIM key pair: %v","messagePattern":"Failed to generate DKIM key pair: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/domains/domains.go","lineNumber":556,"sourceCode":"\n\tvar dk *docker.DockerAPI\n\n\tdk, err = docker.NewDockerAPI()\n\tif err != nil {\n\t\terr = fmt.Errorf(\"Failed to connect to Docker API: %v\", err)\n\t\treturn\n\t}\n\tdefer dk.Close()\n\n\t// Generate new keys if they don't exist\n\tif !public.FileExists(dkimPriPath) || !public.FileExists(dkimPubPath) {\n\t\tmutex.Lock()\n\t\tdefer mutex.Unlock()\n\n\t\tvar res *v2.ExecResult\n\t\tres, err = dk.ExecCommandByName(context.Background(), consts.SERVICES.Rspamd, []string{\"rspamadm\", \"dkim_keygen\", \"-s\", selector, \"-b\", fmt.Sprintf(\"%d\", keySize), \"-d\", domain, \"-k\", fmt.Sprintf(\"/var/lib/rspamd/dkim/%s/%s.private\", domain, selector)}, \"root\")\n\t\tif err != nil {\n\t\t\terr = fmt.Errorf(\"Failed to generate DKIM key pair: %v\", err)\n\t\t\treturn\n\t\t}\n\n\t\tif res != nil {\n\t\t\t_, err = public.WriteFile(dkimPubPath, res.Output)\n\t\t\tif err != nil {\n\t\t\t\terr = fmt.Errorf(\"Failed to write DKIM public key: %v\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\t// update dkim private key file permission to 0644\n\t\terr = os.Chmod(dkimPriPath, 0644)\n\t\tif err != nil {\n\t\t\terr = fmt.Errorf(\"Failed to change DKIM private key permissions: %v\", err)\n\t\t\treturn\n\t\t}\n","sourceCodeStart":538,"sourceCodeEnd":574,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/domains/domains.go#L538-L574","documentation":"When DKIM keys don't exist on disk, getDKIMRecordWithKeySize execs `rspamadm dkim_keygen` in the Rspamd container to generate a key pair of the requested size for the domain. This error wraps the Docker exec failure. Note the mutex is held (defer Unlock), so callers fail cleanly but generation must be retried.","triggerScenarios":"GetDKIMRecord / GetDKIMShortRecord / RepairDKIMSigningConfig for a domain with no existing key files, when ExecCommandByName(ctx, Rspamd, [rspamadm dkim_keygen ...]) fails — Rspamd container not running, rspamadm binary missing, bad keySize argument, or exec exits non-zero (e.g. unwritable /var/lib/rspamd/dkim).","commonSituations":"Rspamd container stopped or OOM-killed; DKIM directory volume not mounted so keygen cannot write; invalid keySize passed (not 1024/2048); container image updated without rspamadm on PATH.","solutions":["Check Rspamd container is up: docker ps and docker logs <rspamd>","Exec manually to see the real error: docker exec <rspamd> rspamadm dkim_keygen -s <selector> -b 2048 -d <domain> -k /var/lib/rspamd/dkim/<domain>/<selector>.private","Ensure /var/lib/rspamd/dkim is a writable mounted volume","Retry GetDKIMRecord after the container is healthy — key generation is idempotent when keys are missing"],"exampleFix":"// before\nres, err = dk.ExecCommandByName(context.Background(), consts.SERVICES.Rspamd, []string{\"rspamadm\",\"dkim_keygen\",\"-s\",selector,\"-b\",fmt.Sprintf(\"%d\",keySize),...}, \"root\")\nif err != nil { err = fmt.Errorf(\"Failed to generate DKIM key pair: %v\", err); return }\n// after\nres, err = dk.ExecCommandByName(context.Background(), consts.SERVICES.Rspamd, keygenArgs, \"root\")\nif err != nil { err = fmt.Errorf(\"Failed to generate DKIM key pair (is %s running and rspamadm available?): %v\", consts.SERVICES.Rspamd, err); return }\nif res != nil && res.ExitCode != 0 { err = fmt.Errorf(\"rspamadm dkim_keygen exited %d: %s\", res.ExitCode, res.Output); return }","handlingStrategy":"retry","validationCode":"running, err := dk.IsContainerRunning(ctx, consts.SERVICES.Rspamd)\nif err != nil || !running { return errors.New(\"rspamd container must be running for DKIM keygen\") }\n_, err = dk.ExecCommandByName(ctx, consts.SERVICES.Rspamd, []string{\"which\", \"rspamadm\"}, \"root\")\nif err != nil { return errors.New(\"rspamadm not available in rspamd image\") }","typeGuard":null,"tryCatchPattern":"err := retry.Do(3, 3*time.Second, func() error {\n    res, err := dk.ExecCommandByName(ctx, consts.SERVICES.Rspamd, keygenArgs, \"root\")\n    if err != nil { return err }\n    if res == nil || res.Output == \"\" { return errors.New(\"empty keygen output\") }\n    return nil\n})\nif err != nil { return fmt.Errorf(\"Failed to generate DKIM key pair: %v\", err) }","preventionTips":["Keep rspamd container healthy and supervised (restart: always)","Validate keySize is 1024 or 2048 before exec","Ensure /var/lib/rspamd/dkim is a writable persistent volume","Unlock the mutex path quickly so failed keygen doesn't stall other domains"],"tags":["docker","dkim","rspamd","key-generation","exec"],"backgroundTag":"dkim-keygen-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"}