sipeed/picoclaw · error
credential: keygen: ed25519 key generation failed: %w
Error message
credential: keygen: ed25519 key generation failed: %w
What it means
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.
Source
Thrown at pkg/credential/keygen.go:35
home, err := os.UserHomeDir()
if err != nil {
return "", fmt.Errorf("credential: cannot determine home directory: %w", err)
}
return filepath.Join(home, ".ssh", "picoclaw_ed25519.key"), nil
}
// GenerateSSHKey generates an Ed25519 SSH key pair and writes the private key
// to path (permissions 0600) and the public key to path+".pub" (permissions 0644).
// The ~/.ssh/ directory is created with 0700 if it does not exist.
// If the files already exist they are overwritten.
func GenerateSSHKey(path string) error {
if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {
return fmt.Errorf("credential: keygen: cannot create directory %q: %w", filepath.Dir(path), err)
}
pubRaw, privRaw, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
return fmt.Errorf("credential: keygen: ed25519 key generation failed: %w", err)
}
// Marshal private key as OpenSSH PEM.
block, err := ssh.MarshalPrivateKey(privRaw, "")
if err != nil {
return fmt.Errorf("credential: keygen: marshal private key: %w", err)
}
privPEM := pem.EncodeToMemory(block)
if err = os.WriteFile(path, privPEM, 0o600); err != nil {
return fmt.Errorf("credential: keygen: write private key %q: %w", path, err)
}
// Marshal public key as authorized_keys line.
sshPub, err := ssh.NewPublicKey(pubRaw)
if err != nil {
return fmt.Errorf("credential: keygen: marshal public key: %w", err)
}View on GitHub (pinned to 49183d7e8d)
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
Example fix
// before: one-shot keygen
if err := credential.GenerateSSHKey(path); err != nil {
log.Fatal(err)
}
// after: bounded retry for transient entropy starvation
var genErr error
for i := 0; i < 3; i++ {
if genErr = credential.GenerateSSHKey(path); genErr == nil {
break
}
time.Sleep(500 * time.Millisecond)
}
if genErr != nil {
log.Fatal(genErr)
} Defensive patterns
Strategy: retry
Validate before calling
// Same entropy probe as for Encrypt - shared root cause.
func randOK() bool {
b := make([]byte, 32)
_, err := io.ReadFull(rand.Reader, b)
return err == nil
} Try / catch
err := credential.GenerateSSHKey(path)
for i := 0; i < 3 && err != nil && strings.Contains(err.Error(), "ed25519 key generation failed"); i++ {
time.Sleep(500 * time.Millisecond)
err = credential.GenerateSSHKey(path)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- credential: failed to generate nonce: %w
- credential: keygen: marshal private key: %w
- credential: keygen: marshal public key: %w
- credential: enc:// decryption failed (wrong passphrase or SS
- command unavailable: config not loaded
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/a5cfba25cbf2069c.
Report an issue: GitHub.