hashicorp/nomad · error

invalid PemCertFile

Error message

invalid PemCertFile

What it means

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.

Source

Thrown at nomad/structs/acl.go:1843

		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 != "" {
		return ErrAmbiguousClientAssertionKey
	}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Use an absolute path such as /etc/nomad/tls/client.crt
  2. Resolve the path at deploy time (filepath.Abs / abspath) before writing config
  3. Ensure the file exists and is readable by the Nomad agent user

Example fix

// before
key := &structs.OIDCClientAssertionKey{
  PemCertFile: "./who-knows-where-this-might-be.cert",
}
// after
key := &structs.OIDCClientAssertionKey{
  PemCertFile: "/etc/nomad/tls/client.cert",
}
Defensive patterns

Strategy: validation

Validate before calling

if key.PemCertFile != "" && !path.IsAbs(key.PemCertFile) {
    abs, err := filepath.Abs(key.PemCertFile)
    if err != nil { return err }
    key.PemCertFile = abs
}

Try / catch

if err := key.Validate(); err != nil {
    if strings.Contains(err.Error(), structs.ErrInvalidClientAssertionCertPath.Error()) {
        // replace with absolute cert path and re-validate
    }
    return err
}

Prevention

When it happens

Trigger: Validate() where k.PemCertFile != "" and !path.IsAbs(k.PemCertFile), e.g. "./who-knows-where-this-might-be.cert".

Common situations: Relative or ~ paths in auth-method config; CI pipelines that resolve certs relative to the repo; operators copying paths from docs examples.

Related errors


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