{"record":{"id":"bba09a5cd390489b","repo":"hashicorp/nomad","slug":"failed-to-parse-signed-token-w","errorCode":null,"errorMessage":"failed to parse signed token: %w","messagePattern":"failed to parse signed token: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/encrypter.go","lineNumber":362,"sourceCode":"\t\t\treturn \"\", \"\", err\n\t\t}\n\t}\n\n\traw, err := jwt.Signed(sig).Claims(claims).CompactSerialize()\n\tif err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\n\treturn raw, cs.rootKey.Meta.KeyID, nil\n}\n\n// VerifyClaim accepts a previously signed encoded claim and validates\n// it before returning the claim.\nfunc (e *Encrypter) VerifyClaim(tokenString string) (*structs.IdentityClaims, error) {\n\n\ttoken, err := jwt.ParseSigned(tokenString)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse signed token: %w\", err)\n\t}\n\n\t// Find the Key ID\n\tkeyID, err := joseutil.KeyID(token)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Find the key material\n\tpubKey, err := e.waitForPublicKey(keyID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttypedPubKey, err := pubKey.GetPublicKey()\n\tif err != nil {\n\t\treturn nil, err\n\t}","sourceCodeStart":344,"sourceCodeEnd":380,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/encrypter.go#L344-L380","documentation":"Fires in Encrypter.VerifyClaim when jwt.ParseSigned cannot parse the presented token string — the token is malformed/truncated or not a valid JWS compact serialization, so signature verification never starts.","triggerScenarios":"Encrypter.VerifyClaim(tokenString) is called with an empty, truncated, base64-corrupt, or non-JWT string; parse fails before any key lookup.","commonSituations":"Workload passes a truncated NOMAD_TOKEN-style value, a config template captured only part of the token, whitespace/newlines injected by a secret template, or a caller passes an opaque ACL token where a signed identity claim was expected.","solutions":["Regenerate the token (nomad alloc status / job re-submit) rather than repairing it","Verify the full compact JWT (three dot-separated base64url segments) reaches VerifyClaim — no truncation or whitespace","Confirm the caller is passing a signed workload identity claim, not an ACL secret ID","Check secret templates for rendering bugs that cut the token"],"exampleFix":"// before: template truncates token\nNOMAD_JWT = \"{{ with secret \"nomad/vars/foo\" }}{{ .Data.token | truncate 60 \"\" }}{{ end }}\"\n// after: render the full value\nNOMAD_JWT = \"{{ with secret \"nomad/vars/foo\" }}{{ .Data.token }}{{ end }}\"","handlingStrategy":"validation","validationCode":"import \"strings\"\n// quick shape check before VerifyClaim\nfunc looksLikeCompactJWT(tok string) bool {\n  parts := strings.Split(strings.TrimSpace(tok), \".\")\n  return len(parts) == 3 && len(parts[0]) > 0 && len(parts[1]) > 0 && len(parts[2]) > 0\n}","typeGuard":"func isProbablyJWS(s string) bool {\n  s = strings.TrimSpace(s)\n  parts := strings.Split(s, \".\")\n  if len(parts) != 3 { return false }\n  for _, p := range parts {\n    if p == \"\" { return false }\n    for _, c := range p {\n      ok := c == '-' || c == '_' || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')\n      if !ok { return false }\n    }\n  }\n  return true\n}","tryCatchPattern":"claims, err := encrypter.VerifyClaim(token)\nif err != nil && strings.Contains(err.Error(), \"failed to parse signed token\") {\n  return fmt.Errorf(\"token malformed (got %d chars) — re-issue the workload token: %w\", len(token), err)\n}","preventionTips":["Pass tokens verbatim — no trimming, truncation, or template post-processing","Store the full token in templates and env vars (watch for line-wrapping in files)","Distinguish ACL secret IDs from signed identity claims in code","Validate token shape at the boundary where the token is received"],"tags":["jwt","jose","parsing","go"],"backgroundTag":"jwt-parse-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"}