hashicorp/nomad · error
invalid claims: %w
Error message
invalid claims: %w
What it means
The JWT signature was valid, but claims.Validate(jwt.Expected{}) rejected the token — e.g. the claims payload could not unmarshal into structs.IdentityClaims or contains fields failing jose validation. COMPAT note: with empty Expected{}, most time-based checks are off, so this mostly indicates a malformed or unexpected claims body.
Source
Thrown at nomad/encrypter.go:393
}
typedPubKey, err := pubKey.GetPublicKey()
if err != nil {
return nil, err
}
claims := structs.IdentityClaims{}
// Validate the claims.
if err := token.Claims(typedPubKey, &claims); err != nil {
return nil, fmt.Errorf("invalid signature: %w", err)
}
// COMPAT: Until we can guarantee there are no pre-1.7 JWTs in use, we can
// only validate the signature and have no further expectations of the
// claims.
if err := claims.Validate(jwt.Expected{}); err != nil {
return nil, fmt.Errorf("invalid claims: %w", err)
}
return &claims, nil
}
// AddUnwrappedKey stores the key in the keystore and creates a new cipher for
// it. This is called in the RPC handlers on the leader and from the legacy
// KeyringReplicator.
func (e *Encrypter) AddUnwrappedKey(rootKey *structs.UnwrappedRootKey, isUpgraded bool) (*structs.RootKey, error) {
// note: we don't lock the keyring here but inside addCipher
// instead, so that we're not holding the lock while performing
// local disk writes
if err := e.addCipher(rootKey); err != nil {
return nil, err
}
return e.wrapRootKey(rootKey, isUpgraded)
}View on GitHub (pinned to 482b49bf1a)
Solutions
- Re-issue the token from the current Nomad server so the claims match structs.IdentityClaims
- Confirm issuer and verifier run compatible Nomad versions
- Decode the token payload (base64url of the middle segment) and inspect for unexpected fields
- Ensure the token wasn't modified between issuance and verification
Example fix
// before: token from Nomad 1.6 verified by 1.7+ server claims, err := e.VerifyClaim(pre17Token) // invalid claims // after: upgrade the issuing server and mint a fresh token $ nomad agent -server -version=1.7.x # then re-run the workload
Defensive patterns
Strategy: validation
Validate before calling
// decode payload and confirm expected claim fields before VerifyClaim
import "encoding/base64"
import "encoding/json"
func hasExpectedClaimShape(token string) bool {
parts := strings.Split(token, ".")
if len(parts) != 3 { return false }
raw, err := base64.RawURLEncoding.DecodeString(parts[1])
if err != nil { return false }
var m map[string]any
if json.Unmarshal(raw, &m) != nil { return false }
_, hasSub := m["sub"]
return hasSub // adjust to IdentityClaims requirements
} Try / catch
claims, err := encrypter.VerifyClaim(token)
if err != nil && strings.Contains(err.Error(), "invalid claims") {
return fmt.Errorf("token claims incompatible with this server version — re-issue from a current Nomad server: %w", err)
} Prevention
- Keep issuer and verifier Nomad versions aligned
- Accept tokens only from the Nomad claim issuer, not third-party JWTs
- Re-issue tokens after upgrades that change claim structure
- Reject tokens whose payload fails a basic shape check at ingress
When it happens
Trigger: VerifyClaim calls claims.Validate(jwt.Expected{}) after successful signature validation; a claims set that doesn't decode into IdentityClaims or violates expected registered claims triggers the wrap.
Common situations: Tokens minted by a much older Nomad version (pre-1.7 claim shape) or by a third-party issuer, hand-forged tokens with an unexpected payload, or corruption in transit that survived the base64 check but broke JSON decoding.
Related errors
- failed to parse signed token: %w
- invalid signature: %w
- node does not have a JWT identity token
- PluginID is required
- VolumeID is required
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/9c163d1e88bb7353.
Report an issue: GitHub.