{"record":{"id":"9c163d1e88bb7353","repo":"hashicorp/nomad","slug":"invalid-claims-w","errorCode":null,"errorMessage":"invalid claims: %w","messagePattern":"invalid claims: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/encrypter.go","lineNumber":393,"sourceCode":"\t}\n\n\ttypedPubKey, err := pubKey.GetPublicKey()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclaims := structs.IdentityClaims{}\n\n\t// Validate the claims.\n\tif err := token.Claims(typedPubKey, &claims); err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid signature: %w\", err)\n\t}\n\n\t// COMPAT: Until we can guarantee there are no pre-1.7 JWTs in use, we can\n\t// only validate the signature and have no further expectations of the\n\t// claims.\n\tif err := claims.Validate(jwt.Expected{}); err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid claims: %w\", err)\n\t}\n\n\treturn &claims, nil\n}\n\n// AddUnwrappedKey stores the key in the keystore and creates a new cipher for\n// it. This is called in the RPC handlers on the leader and from the legacy\n// KeyringReplicator.\nfunc (e *Encrypter) AddUnwrappedKey(rootKey *structs.UnwrappedRootKey, isUpgraded bool) (*structs.RootKey, error) {\n\n\t// note: we don't lock the keyring here but inside addCipher\n\t// instead, so that we're not holding the lock while performing\n\t// local disk writes\n\tif err := e.addCipher(rootKey); err != nil {\n\t\treturn nil, err\n\t}\n\treturn e.wrapRootKey(rootKey, isUpgraded)\n}","sourceCodeStart":375,"sourceCodeEnd":411,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/encrypter.go#L375-L411","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: token from Nomad 1.6 verified by 1.7+ server\nclaims, err := e.VerifyClaim(pre17Token) // invalid claims\n// after: upgrade the issuing server and mint a fresh token\n$ nomad agent -server -version=1.7.x  # then re-run the workload","handlingStrategy":"validation","validationCode":"// decode payload and confirm expected claim fields before VerifyClaim\nimport \"encoding/base64\"\nimport \"encoding/json\"\nfunc hasExpectedClaimShape(token string) bool {\n  parts := strings.Split(token, \".\")\n  if len(parts) != 3 { return false }\n  raw, err := base64.RawURLEncoding.DecodeString(parts[1])\n  if err != nil { return false }\n  var m map[string]any\n  if json.Unmarshal(raw, &m) != nil { return false }\n  _, hasSub := m[\"sub\"]\n  return hasSub // adjust to IdentityClaims requirements\n}","typeGuard":null,"tryCatchPattern":"claims, err := encrypter.VerifyClaim(token)\nif err != nil && strings.Contains(err.Error(), \"invalid claims\") {\n  return fmt.Errorf(\"token claims incompatible with this server version — re-issue from a current Nomad server: %w\", err)\n}","preventionTips":["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"],"tags":["jwt","claims","validation","jose","go"],"backgroundTag":"jwt-claim-validation-failed","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}