{"record":{"id":"b12265554d979e75","repo":"Billionmail/BillionMail","slug":"failed-to-generate-user-private-key","errorCode":null,"errorMessage":"Failed to generate user private key: {}","messagePattern":"Failed to generate user private key: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"core/internal/service/acme/acme.go","lineNumber":77,"sourceCode":"\n\tif public.FileExists(accountKeyPath) {\n\t\tkeyBytes, readErr := public.ReadFile(accountKeyPath)\n\t\tif readErr == nil {\n\t\t\tblock, _ := pem.Decode([]byte(keyBytes))\n\t\t\tif block != nil {\n\t\t\t\tparsedKey, parseErr := x509.ParseECPrivateKey(block.Bytes)\n\t\t\t\tif parseErr == nil {\n\t\t\t\t\tprivateKey = parsedKey\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif privateKey == nil {\n\t\t// Generate new private key if none exists\n\t\tprivateKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)\n\t\tif err != nil {\n\t\t\treturn nil, errors.New(public.LangCtx(ctx, \"Failed to generate user private key: {}\", err.Error()))\n\t\t}\n\n\t\t// Persist the key for future use\n\t\tkeyBytes, marshalErr := x509.MarshalECPrivateKey(privateKey)\n\t\tif marshalErr == nil {\n\t\t\tpemBlock := &pem.Block{\n\t\t\t\tType:  \"EC PRIVATE KEY\",\n\t\t\t\tBytes: keyBytes,\n\t\t\t}\n\t\t\tpemBytes := pem.EncodeToMemory(pemBlock)\n\n\t\t\tdir := filepath.Dir(accountKeyPath)\n\t\t\tif !public.FileExists(dir) {\n\t\t\t\tos.MkdirAll(dir, 0750)\n\t\t\t}\n\t\t\tpublic.WriteFile(accountKeyPath, string(pemBytes))\n\t\t}\n\t}","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/acme/acme.go#L59-L95","documentation":"GetMyUser loads the persisted ACME account ECDSA key, and if none exists generates a new P-256 key with ecdsa.GenerateKey. If crypto/rand fails, the error is wrapped via public.LangCtx into this localized message and returned, aborting the SSL flow (ApplySSLWithExistingServer) before any ACME client is created.","triggerScenarios":"ecdsa.GenerateKey returning an error — practically only when the OS cryptographic entropy source (/dev/urandom, getrandom) fails: sandboxed/restricted containers, seccomp filters blocking getrandom, or a heavily degraded kernel.","commonSituations":"Container with restricted seccomp profile blocking getrandom(2); unusual minimal distros lacking proper /dev/urandom; this message also appears when the account.key file could not be read/parsed (silently ignored) and generation then runs — check for a corrupted PEM file first.","solutions":["Check the container's seccomp/apparmor profile allows getrandom(2); loosen the profile or use a default Docker profile.","Verify /dev/urandom exists and is readable inside the container/host.","Inspect core/data/acme/account.key — if it exists but is corrupt, delete it so a fresh key is generated and persisted.","Upgrade the kernel/glibc on minimal hosts where getrandom is broken."],"exampleFix":"// before\nprivateKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)\nif err != nil {\n\treturn nil, errors.New(public.LangCtx(ctx, \"Failed to generate user private key: {}\", err.Error()))\n}\n// after\nprivateKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)\nif err != nil {\n\treturn nil, fmt.Errorf(\"generate ACME account key (check crypto/rand availability/seccomp): %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"// preflight before ApplySSL\nf, err := os.OpenFile(\"/dev/urandom\", os.O_RDONLY, 0)\nif err != nil { return fmt.Errorf(\"entropy source unavailable: %w\", err) }\nf.Close()","typeGuard":"func hasUsableAccountKey(pemBytes []byte) bool {\n\tblock, _ := pem.Decode(pemBytes)\n\tif block == nil { return false }\n\t_, err := x509.ParseECPrivateKey(block.Bytes)\n\treturn err == nil\n}","tryCatchPattern":"u, err := acme.GetMyUser(ctx, email)\nif err != nil {\n\tif strings.Contains(err.Error(), \"Failed to generate user private key\") {\n\t\treturn fmt.Errorf(\"crypto/rand unavailable — check container seccomp/dev/urandom: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Use default (unrestricted) seccomp profiles in containers","Delete corrupt core/data/acme/account.key files instead of silently ignoring parse errors","Persist generated keys with error handling (currently marshalErr/write errors are swallowed)"],"tags":["crypto","acme","entropy","tls"],"backgroundTag":"crypto-rand-failure","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"}