{"record":{"id":"a5cfba25cbf2069c","repo":"sipeed/picoclaw","slug":"credential-keygen-ed25519-key-generation-failed","errorCode":null,"errorMessage":"credential: keygen: ed25519 key generation failed: %w","messagePattern":"credential: keygen: ed25519 key generation failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/credential/keygen.go","lineNumber":35,"sourceCode":"\thome, err := os.UserHomeDir()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"credential: cannot determine home directory: %w\", err)\n\t}\n\treturn filepath.Join(home, \".ssh\", \"picoclaw_ed25519.key\"), nil\n}\n\n// GenerateSSHKey generates an Ed25519 SSH key pair and writes the private key\n// to path (permissions 0600) and the public key to path+\".pub\" (permissions 0644).\n// The ~/.ssh/ directory is created with 0700 if it does not exist.\n// If the files already exist they are overwritten.\nfunc GenerateSSHKey(path string) error {\n\tif err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {\n\t\treturn fmt.Errorf(\"credential: keygen: cannot create directory %q: %w\", filepath.Dir(path), err)\n\t}\n\n\tpubRaw, privRaw, err := ed25519.GenerateKey(rand.Reader)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"credential: keygen: ed25519 key generation failed: %w\", err)\n\t}\n\n\t// Marshal private key as OpenSSH PEM.\n\tblock, err := ssh.MarshalPrivateKey(privRaw, \"\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"credential: keygen: marshal private key: %w\", err)\n\t}\n\tprivPEM := pem.EncodeToMemory(block)\n\n\tif err = os.WriteFile(path, privPEM, 0o600); err != nil {\n\t\treturn fmt.Errorf(\"credential: keygen: write private key %q: %w\", path, err)\n\t}\n\n\t// Marshal public key as authorized_keys line.\n\tsshPub, err := ssh.NewPublicKey(pubRaw)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"credential: keygen: marshal public key: %w\", err)\n\t}","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/credential/keygen.go#L17-L53","documentation":"ed25519.GenerateKey(rand.Reader) failed during key generation. Ed25519 keygen's only failure mode is the randomness reader erroring, so this is the keygen twin of the crypto/rand failures seen in Encrypt: the OS entropy source was unavailable at the moment the private key was being produced.","triggerScenarios":"GenerateSSHKey(path) when crypto/rand.Reader errors: getrandom(2) blocked by container seccomp policy, early-boot entropy not initialized, old kernel without getrandom and no readable /dev/urandom, or fd exhaustion.","commonSituations":"Same class as the Encrypt nonce failure: hardened containers, gVisor/old runtimes, very early boot, exotic sandboxes. Rarely seen on normal modern Linux/macOS hosts.","solutions":["Verify randomness availability inside the same environment (`head -c 32 /dev/urandom` and a Go crypto/rand probe)","Allow the getrandom syscall in the container's seccomp profile or update the runtime","Check fd limits (`ulimit -n`) if /dev/urandom fallback is involved","Retry key generation after a short delay - entropy starvation at boot resolves itself"],"exampleFix":"// before: one-shot keygen\nif err := credential.GenerateSSHKey(path); err != nil {\n    log.Fatal(err)\n}\n\n// after: bounded retry for transient entropy starvation\nvar genErr error\nfor i := 0; i < 3; i++ {\n    if genErr = credential.GenerateSSHKey(path); genErr == nil {\n        break\n    }\n    time.Sleep(500 * time.Millisecond)\n}\nif genErr != nil {\n    log.Fatal(genErr)\n}","handlingStrategy":"retry","validationCode":"// Same entropy probe as for Encrypt - shared root cause.\nfunc randOK() bool {\n    b := make([]byte, 32)\n    _, err := io.ReadFull(rand.Reader, b)\n    return err == nil\n}","typeGuard":null,"tryCatchPattern":"err := credential.GenerateSSHKey(path)\nfor i := 0; i < 3 && err != nil && strings.Contains(err.Error(), \"ed25519 key generation failed\"); i++ {\n    time.Sleep(500 * time.Millisecond)\n    err = credential.GenerateSSHKey(path)\n}","preventionTips":["Verify getrandom availability in container seccomp profiles before deploying","Check entropy availability during early-boot provisioning steps","Retry keygen only; never proceed with partial or reused key material"],"tags":["crypto","entropy","keygen","runtime","containers"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}