{"record":{"id":"f40c05f109823c87","repo":"grpc/grpc-go","slug":"unmarshal-error-v","errorCode":null,"errorMessage":"unmarshal error: %v","messagePattern":"unmarshal error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"credentials/jwt/file_reader.go","lineNumber":103,"sourceCode":"\t\treturn \"\", false\n\t}\n\treturn claims, true\n}\n\n// extractExpiration parses the JWT token to extract the expiration time.\nfunc (r *jwtFileReader) extractExpiration(token string) (time.Time, error) {\n\tclaimsRaw, ok := extractClaimsRaw(token)\n\tif !ok {\n\t\treturn time.Time{}, fmt.Errorf(\"expected 3 parts in token\")\n\t}\n\tpayloadBytes, err := base64.RawURLEncoding.DecodeString(claimsRaw)\n\tif err != nil {\n\t\treturn time.Time{}, fmt.Errorf(\"decode error: %v\", err)\n\t}\n\n\tvar claims jwtClaims\n\tif err := json.Unmarshal(payloadBytes, &claims); err != nil {\n\t\treturn time.Time{}, fmt.Errorf(\"unmarshal error: %v\", err)\n\t}\n\n\tif claims.Exp == 0 {\n\t\treturn time.Time{}, fmt.Errorf(\"no expiration claims\")\n\t}\n\n\texpTime := time.Unix(claims.Exp, 0)\n\n\t// Check if token is already expired.\n\tif expTime.Before(time.Now()) {\n\t\treturn time.Time{}, fmt.Errorf(\"expired token\")\n\t}\n\n\treturn expTime, nil\n}\n","sourceCodeStart":85,"sourceCodeEnd":119,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/credentials/jwt/file_reader.go#L85-L119","documentation":"Returned by extractExpiration when json.Unmarshal of the decoded payload fails. The bytes decoded as base64 but are not valid JSON matching jwtClaims. The %v is the JSON decoder error. The reader only needs an `exp` field, so a well-formed JWT should never hit this; corruption or a non-JSON payload is the usual cause.","triggerScenarios":"The base64-decoded payload is not a JSON object (e.g. a JWE-encrypted token whose payload is ciphertext, a malformed token, or binary garbage that happened to be base64-decodable).","commonSituations":"Using an encrypted JWT (JWE) where a signed JWT (JWS) is expected; binary content inadvertently placed in the token file; character-set corruption.","solutions":["Confirm the token is a signed (JWS) JWT, not an encrypted (JWE) token; the gRPC reader cannot decrypt JWEs.","Decode the payload manually (base64 -d) and confirm it is a JSON object containing an exp field.","Re-issue the token through the intended ID-token flow."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"func claimsJSON(claimsSeg string) (map[string]any, error) {\n    b, err := base64.RawURLEncoding.DecodeString(claimsSeg)\n    if err != nil {\n        return nil, err\n    }\n    var m map[string]any\n    if err := json.Unmarshal(b, &m); err != nil {\n        return nil, err\n    }\n    return m, nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Confirm the token is a JWS (signed) JWT, not a JWE (encrypted).","Decode and inspect the payload before deploying the token.","Use a reputable issuer to avoid malformed payloads."],"tags":["grpc","jwt","json","parsing","validation"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}