{"record":{"id":"bc996cdac2996665","repo":"router-for-me/CLIProxyAPI","slug":"private-key-is-not-an-rsa-key","errorCode":null,"errorMessage":"private_key is not an RSA key","messagePattern":"private_key is not an RSA key","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"internal/auth/vertex/keyutil.go","lineNumber":105,"sourceCode":"\tif block == nil {\n\t\treturn nil, fmt.Errorf(\"pem block is nil\")\n\t}\n\n\tif block.Type == \"RSA PRIVATE KEY\" {\n\t\tif _, err := x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"private_key invalid rsa: %w\", err)\n\t\t}\n\t\treturn block, nil\n\t}\n\n\tif block.Type == \"PRIVATE KEY\" {\n\t\tkey, err := x509.ParsePKCS8PrivateKey(block.Bytes)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"private_key invalid pkcs8: %w\", err)\n\t\t}\n\t\trsaKey, ok := key.(*rsa.PrivateKey)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"private_key is not an RSA key\")\n\t\t}\n\t\tder := x509.MarshalPKCS1PrivateKey(rsaKey)\n\t\treturn &pem.Block{Type: \"RSA PRIVATE KEY\", Bytes: der}, nil\n\t}\n\n\t// Attempt auto-detection: try PKCS#1 first, then PKCS#8.\n\tif rsaKey, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil {\n\t\tder := x509.MarshalPKCS1PrivateKey(rsaKey)\n\t\treturn &pem.Block{Type: \"RSA PRIVATE KEY\", Bytes: der}, nil\n\t}\n\tif key, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil {\n\t\tif rsaKey, ok := key.(*rsa.PrivateKey); ok {\n\t\t\tder := x509.MarshalPKCS1PrivateKey(rsaKey)\n\t\t\treturn &pem.Block{Type: \"RSA PRIVATE KEY\", Bytes: der}, nil\n\t\t}\n\t}\n\treturn nil, fmt.Errorf(\"private_key uses unsupported format\")\n}","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/auth/vertex/keyutil.go#L87-L123","documentation":"From ensureRSAPrivateKey when a 'PRIVATE KEY' (PKCS#8) block parses successfully but the resulting key is not an *rsa.PrivateKey (keyutil.go:102-106). Vertex signing requires RSA; an ECDSA or Ed25519 key inside a PKCS#8 wrapper triggers this error.","triggerScenarios":"User configures an EC (prime256v1) or Ed25519 service-account-style key as the Vertex credential; key generated with openssl ecparam or genkey -algorithm ed25519 instead of RSA; GCP always issues RSA, so this usually means a custom/homemade key.","commonSituations":"Organizations minting their own keys for private Vertex-compatible endpoints; converting existing EC TLS keys for signing experiments; misunderstanding that the field must be RSA.","solutions":["Regenerate the key as RSA of at least 2048 bits: openssl genrsa -out key.pem 2048, then rebuild the service account JSON","Or use an official GCP-issued service account key, which is always RSA","Verify the algorithm: openssl pkey -in key.pem -noout -text | head -1 (should say RSA)"],"exampleFix":"# before\nopenssl ecparam -name prime256v1 -genkey -out key.pem\n# after\nopenssl genrsa -out key.pem 2048","handlingStrategy":"type-guard","validationCode":"key, err := x509.ParsePKCS8PrivateKey(block.Bytes)\nif err == nil && !isRSA(key) {\n    return fmt.Errorf(\"key algorithm is %T; RSA required\", key)\n}","typeGuard":"func isRSAKey(any) bool\n// Go:\nfunc isRSAKey(k any) bool {\n    _, ok := k.(*rsa.PrivateKey)\n    return ok\n}","tryCatchPattern":null,"preventionTips":["Generate signing keys with openssl genrsa (>=2048 bits)","Prefer GCP-issued service account keys, which are always RSA","Assert algorithm early in key onboarding pipelines"],"tags":["vertex","rsa","key-algorithm","crypto"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}