{"record":{"id":"3a300eca37dac513","repo":"hashicorp/nomad","slug":"invalid-pemcertfile","errorCode":null,"errorMessage":"invalid PemCertFile","messagePattern":"invalid PemCertFile","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/acl.go","lineNumber":1843,"sourceCode":"\t\treturn\n\t}\n\tif k.KeyIDHeader == \"\" {\n\t\tif k.KeyID != \"\" {\n\t\t\tk.KeyIDHeader = OIDCClientAssertionHeaderKid\n\t\t}\n\t\tif k.PemCert != \"\" || k.PemCertFile != \"\" {\n\t\t\tk.KeyIDHeader = OIDCClientAssertionHeaderX5tS256\n\t\t}\n\t}\n}\n\nvar (\n\tErrMissingClientAssertionKey      = errors.New(\"missing PemKey or PemKeyFile\")\n\tErrAmbiguousClientAssertionKey    = errors.New(\"require only one of PemKey or PemKeyFile\")\n\tErrMissingClientAssertionKeyID    = errors.New(\"missing PemCert, PemCertFile, or KeyID\")\n\tErrAmbiguousClientAssertionKeyID  = errors.New(\"require only one of PemCert, PemCertFile, or KeyID\")\n\tErrInvalidClientAssertionKeyPath  = errors.New(\"invalid PemKeyFile\")\n\tErrInvalidClientAssertionCertPath = errors.New(\"invalid PemCertFile\")\n\tErrInvalidKeyIDHeader             = errors.New(\"invalid KeyIDHeader\")\n)\n\n// Validate ensures that one Key and one Cert or KeyID are provided,\n// and that the key ID header is valid for the provided KeyID or cert.\nfunc (k *OIDCClientAssertionKey) Validate() error {\n\tif k == nil {\n\t\treturn nil\n\t}\n\n\t// mutually exclusive key fields\n\t// must have key file or base64, but not both\n\tif k.PemKey == \"\" && k.PemKeyFile == \"\" {\n\t\treturn ErrMissingClientAssertionKey\n\t}\n\tif k.PemKey != \"\" && k.PemKeyFile != \"\" {\n\t\treturn ErrAmbiguousClientAssertionKey\n\t}","sourceCodeStart":1825,"sourceCodeEnd":1861,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/acl.go#L1825-L1861","documentation":"Like the key path, PemCertFile must be an absolute path. ErrInvalidClientAssertionCertPath is wrapped with 'must be absolute; got: <path>' because the certificate file must be readable by Nomad agents regardless of their working directory.","triggerScenarios":"Validate() where k.PemCertFile != \"\" and !path.IsAbs(k.PemCertFile), e.g. \"./who-knows-where-this-might-be.cert\".","commonSituations":"Relative or ~ paths in auth-method config; CI pipelines that resolve certs relative to the repo; operators copying paths from docs examples.","solutions":["Use an absolute path such as /etc/nomad/tls/client.crt","Resolve the path at deploy time (filepath.Abs / abspath) before writing config","Ensure the file exists and is readable by the Nomad agent user"],"exampleFix":"// before\nkey := &structs.OIDCClientAssertionKey{\n  PemCertFile: \"./who-knows-where-this-might-be.cert\",\n}\n// after\nkey := &structs.OIDCClientAssertionKey{\n  PemCertFile: \"/etc/nomad/tls/client.cert\",\n}","handlingStrategy":"validation","validationCode":"if key.PemCertFile != \"\" && !path.IsAbs(key.PemCertFile) {\n    abs, err := filepath.Abs(key.PemCertFile)\n    if err != nil { return err }\n    key.PemCertFile = abs\n}","typeGuard":null,"tryCatchPattern":"if err := key.Validate(); err != nil {\n    if strings.Contains(err.Error(), structs.ErrInvalidClientAssertionCertPath.Error()) {\n        // replace with absolute cert path and re-validate\n    }\n    return err\n}","preventionTips":["Keep certs under a fixed absolute directory like /etc/nomad/tls/","Expand ~ and relative refs at deploy time","Check file existence and permissions along with absoluteness"],"tags":["nomad","oidc","client-assertion","file-path"],"backgroundTag":"relative-path-not-allowed","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"}