sipeed/picoclaw · error
credential: keygen: marshal private key: %w
Error message
credential: keygen: marshal private key: %w
What it means
ssh.MarshalPrivateKey(privRaw, "") encodes the just-generated Ed25519 private key as an OpenSSH PEM block. In x/crypto/ssh this only errors for key types it cannot serialize (e.g. PKCS1-dependent RSA signature hash configurations). Since the input is an Ed25519 key generated one line above, this branch is a defensive guard and is effectively unreachable.
Source
Thrown at pkg/credential/keygen.go:41
// 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)
}
pubLine := ssh.MarshalAuthorizedKey(sshPub)
pubPath := path + ".pub"
if err := os.WriteFile(pubPath, pubLine, 0o644); err != nil {
return fmt.Errorf("credential: keygen: write public key %q: %w", pubPath, err)
}View on GitHub (pinned to 49183d7e8d)
Solutions
- Treat as an internal invariant failure: report and abort, do not retry
- Verify the x/crypto module is unmodified: `go mod verify`
- Rebuild from a clean module cache (`go clean -modcache`) if a corrupted vendored copy is suspected
Defensive patterns
Strategy: try-catch
Try / catch
if err := credential.GenerateSSHKey(path); err != nil {
if strings.Contains(err.Error(), "marshal private key") {
return fmt.Errorf("internal keygen invariant violated, report upstream: %w", err)
}
return err
} Prevention
- Pin and verify the x/crypto module (`go mod verify`) so ssh.MarshalPrivateKey behaves as upstream
- Treat as a build/dependency-integrity problem, not a runtime one
When it happens
Trigger: No realistic runtime trigger: the private key comes straight from ed25519.GenerateKey, which always produces a marshalable key. Could only fire with a patched/vendored x/crypto/ssh or if GenerateSSHKey were modified to accept externally supplied key material.
Common situations: Essentially never in the wild. If observed, suspect a forked dependency or a broken vendor tree rather than a runtime condition.
Related errors
- credential: keygen: marshal public key: %w
- credential: HKDF expand failed: %w
- config is nil
- credential: keygen: cannot create directory %q: %w
- credential: keygen: ed25519 key generation failed: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/54819473344ef98d.
Report an issue: GitHub.