hashicorp/nomad · error

require only one of PemKey or PemKeyFile

Error message

require only one of PemKey or PemKeyFile

What it means

Nomad's OIDCClientAssertionKey.Validate() requires the private key for a client assertion to be supplied in exactly one way: inline via PemKey or via a file path with PemKeyFile. This sentinel error (ErrAmbiguousClientAssertionKey) is returned when both fields are set, because the library cannot tell which source is authoritative.

Source

Thrown at nomad/structs/acl.go:1839

}

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

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Remove either the PemKey inline value or the PemKeyFile path so exactly one is set
  2. Keep PemKeyFile for production (secret stays on disk) and clear PemKey
  3. Keep PemKey for in-memory/template-injected setups and clear PemKeyFile

Example fix

// before
key := &structs.OIDCClientAssertionKey{
  PemKey: string(pemBytes),
  PemKeyFile: "/etc/nomad/tls/client.key",
}
// after
key := &structs.OIDCClientAssertionKey{
  PemKeyFile: "/etc/nomad/tls/client.key",
}
Defensive patterns

Strategy: validation

Validate before calling

if key.PemKey != "" && key.PemKeyFile != "" {
    // drop one before calling Validate()
    key.PemKey = ""
}
if err := key.Validate(); err != nil { return err }

Try / catch

if err := key.Validate(); err != nil {
    if errors.Is(err, structs.ErrAmbiguousClientAssertionKey) {
        // fix config: keep exactly one of PemKey / PemKeyFile
    }
    return err
}

Prevention

When it happens

Trigger: Calling Validate() (directly or via ACLAuthMethod upsert/validation endpoints) on an OIDCClientAssertionKey where both PemKey != "" and PemKeyFile != "".

Common situations: Config templates or HCL/JSON job files where an operator pasted both an inline PEM block and a path; tooling that renders both fields from a vault/secret reference; copy-paste from examples that show both options.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/465a454e90e564b1. Report an issue: GitHub.