{"record":{"id":"6da8b62f9a609d41","repo":"hashicorp/nomad","slug":"error-parsing-s-w","errorCode":null,"errorMessage":"error parsing %s: %w","messagePattern":"error parsing (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/auth/oidc/client_assertion.go","lineNumber":142,"sourceCode":"\tif k.PemKeyFile != \"\" {\n\t\tsource = \"PemKeyFile\"\n\t\tbts, err = os.ReadFile(k.PemKeyFile)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error reading %s: %w\", source, err)\n\t\t}\n\t}\n\t// or pem string\n\tif k.PemKey != \"\" {\n\t\tsource = \"PemKey\"\n\t\tbts = []byte(k.PemKey)\n\t}\n\n\t// ensure newlines around pem header/footer\n\tbts = newlineHeaders(bts)\n\n\tkey, err = gojwt.ParseRSAPrivateKeyFromPEM(bts)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error parsing %s: %w\", source, err)\n\t}\n\tif err := key.Validate(); err != nil {\n\t\treturn nil, fmt.Errorf(\"error validating %s: %w\", source, err)\n\t}\n\treturn key, nil\n}\n\n// getCassCert parses the structs.OIDCClientAssertionKey PemCertFile\n// or PemCert, depending on which is set.\nfunc getCassCert(k *structs.OIDCClientAssertionKey) (*x509.Certificate, error) {\n\tvar bts []byte\n\tvar err error\n\tvar source string // for informative error messages\n\n\t// pem file on disk\n\tif k.PemCertFile != \"\" {\n\t\tsource = \"PemCertFile\"\n\t\tbts, err = os.ReadFile(k.PemCertFile)","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/lib/auth/oidc/client_assertion.go#L124-L160","documentation":"getCassPrivateKey could not parse the PEM bytes into an RSA private key; gojwt.ParseRSAPrivateKeyFromPEM rejected the content (wrapped as %w). The source string tells whether the bytes came from PemKeyFile or PemKey.","triggerScenarios":"BuildClientAssertionJWT → getCassPrivateKey after successfully reading the key bytes, when the content is not a valid PEM RSA private key (wrong key type, ECDSA key, corrupt base64, truncated file).","commonSituations":"EC or Ed25519 key supplied where RSA is required; certificate pasted instead of the key; key file truncated by a bad copy-paste; PKCS#8 vs PKCS#1 edge cases in older parsers.","solutions":["Confirm the key is an RSA private key: `openssl rsa -in key.pem -check`; generate RSA if needed with `openssl genrsa 2048`.","Ensure the PEM has intact `-----BEGIN/END RSA PRIVATE KEY-----` (or PRIVATE KEY) headers and full base64 body.","Verify the file contains the key, not the certificate or public key; if EC key, reissue as RSA."],"exampleFix":"// before: EC key\nPemKey: \"-----BEGIN EC PRIVATE KEY-----\\n...\"\n// after: RSA key\nPemKey: \"-----BEGIN RSA PRIVATE KEY-----\\n...\"","handlingStrategy":"validation","validationCode":"func validateRSAPrivateKeyPEM(pemStr string) error {\n  key, err := gojwt.ParseRSAPrivateKeyFromPEM([]byte(pemStr))\n  if err != nil { return fmt.Errorf(\"not a valid RSA private key PEM: %w\", err) }\n  return key.Validate()\n}\n// run against PemKey/PemKeyFile content before configuring","typeGuard":"func isRSAPrivateKeyPEM(s string) bool {\n  blk, _ := pem.Decode([]byte(s))\n  return blk != nil && strings.Contains(blk.Type, \"PRIVATE KEY\")\n}","tryCatchPattern":"key, err := getCassPrivateKey(k)\nif err != nil && strings.Contains(err.Error(), \"error parsing\") {\n  return fmt.Errorf(\"configured key is not an RSA private key PEM: %w\", err)\n}","preventionTips":["Verify with `openssl rsa -in key.pem -check -noout` before upload.","Ensure the IdP client is registered with an RSA key (not EC).","Escape newlines correctly when embedding keys in JSON/HCL."],"tags":["oidc","client-assertion","pem","rsa","key-parsing"],"backgroundTag":"invalid-pem-key","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}