JuliusBrussee/caveman · error
githubapp: private key is not RSA
Error message
githubapp: private key is not RSA
What it means
Thrown by parseRSAPrivateKey (githubapp.go:411): the PEM payload parsed successfully as PKCS#8, but the resulting key is not an *rsa.PrivateKey - it is an EC, Ed25519, or other algorithmic type. GitHub App JWT signing uses RS256, so only RSA keys are accepted; the type assertion parsed.(*rsa.PrivateKey) fails and this error returns.
Source
Thrown at shared/platform/githubapp/githubapp.go:411
// parseRSAPrivateKey accepts a PKCS#1 ("RSA PRIVATE KEY") or PKCS#8
// ("PRIVATE KEY") PEM — GitHub Apps download PKCS#1, but Cloud KMS / openssl
// conversions emit PKCS#8, so we accept both.
func parseRSAPrivateKey(pemBytes []byte) (*rsa.PrivateKey, error) {
block, _ := pem.Decode(pemBytes)
if block == nil {
return nil, fmt.Errorf("githubapp: private key is not valid PEM")
}
if key, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil {
return key, nil
}
parsed, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("githubapp: private key is neither PKCS#1 nor PKCS#8 RSA: %w", err)
}
key, ok := parsed.(*rsa.PrivateKey)
if !ok {
return nil, fmt.Errorf("githubapp: private key is not RSA")
}
return key, nil
}
// snippet trims an error body so we never echo a large/secret-bearing response.
func snippet(b []byte) string {
const max = 256
s := strings.TrimSpace(string(b))
if len(s) > max {
return s[:max] + "…"
}
return s
}
View on GitHub (pinned to 27d5a3981a)
Solutions
- Generate an RSA key instead: openssl genrsa -out app.pem 2048 (GitHub accepts 2048/4096).
- Re-upload the new public key to the GitHub App settings (App settings -> 'Generate a private key' also produces RSA directly).
- If policy requires EC keys, that conflicts with GitHub App RS256 signing - use an RSA key dedicated to this app.
- Verify: openssl pkey -in app.pem -noout -text should print 'Private-Key: (2048 bit...'.
Example fix
# before openssl genpkey -algorithm ed25519 -out app.pem # after openssl genrsa -out app.pem 2048 # then upload/re-download via GitHub App settings
Defensive patterns
Strategy: type-guard
Validate before calling
if _, err := x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
parsed, err8 := x509.ParsePKCS8PrivateKey(block.Bytes)
if err8 == nil {
if _, ok := parsed.(*rsa.PrivateKey); !ok {
return errors.New("key is not RSA; GitHub App signing requires RSA")
}
}
} Type guard
func isRSAPrivateKey(b []byte) bool {
block, _ := pem.Decode(b)
if block == nil { return false }
if _, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil { return true }
k, err := x509.ParsePKCS8PrivateKey(block.Bytes)
return err == nil && strings.Contains(fmt.Sprintf("%T", k), "rsa")
} Try / catch
if err := loadAppKey(pem); err != nil {
return fmt.Errorf("github app key: %w", err) // regenerate as RSA 2048+ and re-upload
} Prevention
- Standardize app key generation on openssl genrsa 2048.
- Add an integration test that signs and verifies a JWT with the provisioned key before deploy.
- Document that EC/Ed25519 keys cannot be used for GitHub App RS256.
When it happens
Trigger: The private key was generated as EC (openssl ecparam -name prime256v1 ...) or Ed25519 (openssl genpkey -algorithm ed25519), stored as PKCS#8 -----BEGIN PRIVATE KEY-----, and passed to the GitHub App client. Parse succeeds; the RSA type check does not.
Common situations: A security team mandated EC keys org-wide; a KMS export defaulted to EC; openssl command copied from a modern tutorial that generates Ed25519; the same key reused for two integrations where the other one accepted EC.
Related errors
- githubapp: private key is not valid PEM
- githubapp: private key is neither PKCS#1 nor PKCS#8 RSA: %w
- cachebench: nil corpus reader
- message exceeds byte limit
- tool message requires tool_call_id
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/c9d48c799d49271d.
Report an issue: GitHub.