router-for-me/CLIProxyAPI · error
private_key invalid pkcs8: %w
Error message
private_key invalid pkcs8: %w
What it means
From ensureRSAPrivateKey when the PEM block is typed 'PRIVATE KEY' (PKCS#8 generic) but x509.ParsePKCS8PrivateKey fails on its DER bytes (keyutil.go:98-101). The wrapper is fine; the inner ASN.1 payload is not parseable as any PKCS#8 key.
Source
Thrown at internal/auth/vertex/keyutil.go:101
return string(pem.EncodeToMemory(rsaBlock)), nil
}
func ensureRSAPrivateKey(block *pem.Block) (*pem.Block, error) {
if block == nil {
return nil, fmt.Errorf("pem block is nil")
}
if block.Type == "RSA PRIVATE KEY" {
if _, err := x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
return nil, fmt.Errorf("private_key invalid rsa: %w", err)
}
return block, nil
}
if block.Type == "PRIVATE KEY" {
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("private_key invalid pkcs8: %w", err)
}
rsaKey, ok := key.(*rsa.PrivateKey)
if !ok {
return nil, fmt.Errorf("private_key is not an RSA key")
}
der := x509.MarshalPKCS1PrivateKey(rsaKey)
return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: der}, nil
}
// Attempt auto-detection: try PKCS#1 first, then PKCS#8.
if rsaKey, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil {
der := x509.MarshalPKCS1PrivateKey(rsaKey)
return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: der}, nil
}
if key, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil {
if rsaKey, ok := key.(*rsa.PrivateKey); ok {
der := x509.MarshalPKCS1PrivateKey(rsaKey)
return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: der}, nilView on GitHub (pinned to 78f0c4079e)
Solutions
- Validate independently: openssl pkcs8 -in key.pem -nocrypt -noout; if it fails, the key file itself is bad
- Re-export an unencrypted PKCS#8 RSA key or, simplest, re-download the GCP service account JSON
- If the key is PBES2-encrypted, decrypt it first (openssl pkcs8 -passin ...) and store the plaintext in the secret manager
Example fix
# before: encrypted PKCS#8 stored raw -----BEGIN ENCRYPTED PRIVATE KEY----- # after: decrypt then store openssl pkcs8 -in enc.pem -passin file:pass.txt -nocrypt -out plain.pem
Defensive patterns
Strategy: validation
Validate before calling
block, _ := pem.Decode([]byte(pk))
if block != nil && block.Type == "PRIVATE KEY" {
if _, err := x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
return fmt.Errorf("PKCS#8 body unparseable; key corrupt or encrypted")
}
} Prevention
- Decrypt PBES2 keys before storing them as the service account key
- Validate with openssl pkcs8 -nocrypt during deployment
- Avoid byte-level edits of key material
When it happens
Trigger: Corrupted or truncated PKCS#8 DER body; encrypted PKCS#8 (PBES2) keys whose DER begins with encryption parameters Go parses but rejects as an unparseable plain key; mismatched base64 padding introduced by hand edits.
Common situations: Downloading keys through tools that mangle base64 line lengths; using encrypted export formats from other clouds; byte-level truncation in CI secret variables.
Related errors
- service account missing private_key
- private_key is not valid pem: %w
- private_key pem decode failed
- private_key invalid rsa: %w
- private_key is not an RSA key
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/e78902e1f052c77b.
Report an issue: GitHub.