hashicorp/nomad · error
invalid PemKeyFile
Error message
invalid PemKeyFile
What it means
When the client assertion private key is given as a file (PemKeyFile), the path must be absolute. ErrInvalidClientAssertionKeyPath is wrapped (fmt.Errorf %w) with 'must be absolute; got: <path>' when a relative path is supplied, because the key file is read by agents whose working directory is not the operator's.
Source
Thrown at nomad/structs/acl.go:1842
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 != "" {
return ErrAmbiguousClientAssertionKeyView on GitHub (pinned to 482b49bf1a)
Solutions
- Change PemKeyFile to an absolute path like /etc/nomad/tls/client.key
- Expand ~ and relative segments in your config tooling before applying
- Verify with path.IsAbs in scripts that generate the config
Example fix
// before
key := &structs.OIDCClientAssertionKey{
PemKeyFile: "./tls/client.key",
}
// after
key := &structs.OIDCClientAssertionKey{
PemKeyFile: "/etc/nomad/tls/client.key",
} Defensive patterns
Strategy: validation
Validate before calling
if key.PemKeyFile != "" && !path.IsAbs(key.PemKeyFile) {
abs, err := filepath.Abs(key.PemKeyFile)
if err != nil { return err }
key.PemKeyFile = abs
} Try / catch
if err := key.Validate(); err != nil {
var wrapped error
if errors.As(err, &wrapped) && strings.Contains(err.Error(), ErrInvalidClientAssertionKeyPath.Error()) {
// convert to an absolute path and retry validation
}
return err
} Prevention
- Use absolute paths for all key/cert files in Nomad config
- Remember the agent's CWD differs from your shell (systemd, containers)
- Run filepath.Abs in config generation scripts
When it happens
Trigger: Validate() where k.PemKeyFile != "" and path.IsAbs(k.PemKeyFile) is false, e.g. "tls/client.key" or "./client.key".
Common situations: Configs written relative to a deploy directory; paths copied from a local dev shell; templating that emits ~ or relative refs; agents running under systemd with different WorkingDirectory.
Related errors
- invalid PemCertFile
- require only one of PemKey or PemKeyFile
- missing PemCert, PemCertFile, or KeyID
- require only one of PemCert, PemCertFile, or KeyID
- invalid KeyIDHeader
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/827b1b1e7ac51944.
Report an issue: GitHub.