hashicorp/nomad · error
require only one of PemCert, PemCertFile, or KeyID
Error message
require only one of PemCert, PemCertFile, or KeyID
What it means
Exactly one key-identification mechanism must be chosen for a client assertion. ErrAmbiguousClientAssertionKeyID (ErrMissingClientAssertionKeyID's sibling) is returned when more than one of PemCert, PemCertFile, or KeyID is set, since Nomad cannot decide which identifier to put in the JWT header.
Source
Thrown at nomad/structs/acl.go:1841
func (k *OIDCClientAssertionKey) Canonicalize() {
if k == nil {
return
}
if k.KeyIDHeader == "" {
if k.KeyID != "" {
k.KeyIDHeader = OIDCClientAssertionHeaderKid
}
if k.PemCert != "" || k.PemCertFile != "" {
k.KeyIDHeader = OIDCClientAssertionHeaderX5tS256
}
}
}
var (
ErrMissingClientAssertionKey = errors.New("missing PemKey or PemKeyFile")
ErrAmbiguousClientAssertionKey = errors.New("require only one of PemKey or PemKeyFile")
ErrMissingClientAssertionKeyID = errors.New("missing PemCert, PemCertFile, or KeyID")
ErrAmbiguousClientAssertionKeyID = errors.New("require only one of PemCert, PemCertFile, or KeyID")
ErrInvalidClientAssertionKeyPath = errors.New("invalid PemKeyFile")
ErrInvalidClientAssertionCertPath = errors.New("invalid PemCertFile")
ErrInvalidKeyIDHeader = errors.New("invalid KeyIDHeader")
)
// Validate ensures that one Key and one Cert or KeyID are provided,
// and that the key ID header is valid for the provided KeyID or cert.
func (k *OIDCClientAssertionKey) Validate() error {
if k == nil {
return nil
}
// mutually exclusive key fields
// must have key file or base64, but not both
if k.PemKey == "" && k.PemKeyFile == "" {
return ErrMissingClientAssertionKey
}
if k.PemKey != "" && k.PemKeyFile != "" {View on GitHub (pinned to 482b49bf1a)
Solutions
- Keep only one identifier: prefer PemCertFile for file-based setups
- If using a precomputed KeyID, clear PemCert and PemCertFile and set KeyIDHeader appropriately
- If using inline cert, clear PemCertFile and KeyID
Example fix
// before
key := &structs.OIDCClientAssertionKey{
PemCertFile: "/etc/nomad/tls/client.crt",
KeyID: "abc123",
KeyIDHeader: structs.OIDCClientAssertionHeaderKid,
}
// after
key := &structs.OIDCClientAssertionKey{
KeyID: "abc123",
KeyIDHeader: structs.OIDCClientAssertionHeaderKid,
} Defensive patterns
Strategy: validation
Validate before calling
set := 0
for _, v := range []string{key.PemCert, key.PemCertFile, key.KeyID} {
if v != "" { set++ }
}
if set > 1 { return errors.New("choose exactly one of PemCert, PemCertFile, KeyID") } Try / catch
if err := key.Validate(); err != nil {
if errors.Is(err, structs.ErrAmbiguousClientAssertionKeyID) {
// strip the redundant identifier fields
}
return err
} Prevention
- Pick one identification style per auth method and stick to it
- Clear removed fields when refactoring config (no stale leftovers)
- Prefer PemCertFile (abs path) or KeyID+kid; avoid inline certs
When it happens
Trigger: Validate() where PemCert is set together with PemCertFile or KeyID; or PemCertFile set together with PemCert or KeyID; or KeyID set together with PemCert or PemCertFile.
Common situations: Operator supplies the full chain in a file but also pastes a leaf cert inline; automation computes KeyID while the config still carries PemCertFile; gradual refactors leaving stale fields populated.
Related errors
- require only one of PemKey or PemKeyFile
- missing PemCert, PemCertFile, or KeyID
- invalid PemKeyFile
- invalid PemCertFile
- invalid KeyIDHeader
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/5224e778a185446d.
Report an issue: GitHub.