{"record":{"id":"5b499e470a11c0dd","repo":"grpc/grpc-go","slug":"token-file-q-v-w","errorCode":null,"errorMessage":"token file %q: %v: %w","messagePattern":"token file %q: (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"credentials/jwt/file_reader.go","lineNumber":62,"sourceCode":"\ttokenFilePath string\n}\n\n// readToken reads and parses a JWT token from the configured file.\n// Returns the token string, expiration time, and any error encountered.\nfunc (r *jwtFileReader) readToken() (string, time.Time, error) {\n\ttokenBytes, err := os.ReadFile(r.tokenFilePath)\n\tif err != nil {\n\t\treturn \"\", time.Time{}, fmt.Errorf(\"%v: %w\", err, errTokenFileAccess)\n\t}\n\n\ttoken := strings.TrimSpace(string(tokenBytes))\n\tif token == \"\" {\n\t\treturn \"\", time.Time{}, fmt.Errorf(\"token file %q is empty: %w\", r.tokenFilePath, errJWTValidation)\n\t}\n\n\texp, err := r.extractExpiration(token)\n\tif err != nil {\n\t\treturn \"\", time.Time{}, fmt.Errorf(\"token file %q: %v: %w\", r.tokenFilePath, err, errJWTValidation)\n\t}\n\n\treturn token, exp, nil\n}\n\nconst tokenDelim = \".\"\n\n// extractClaimsRaw returns the JWT's claims part as raw string. Even though the\n// header and signature are not used, it still expects that the input string to\n// be well-formed (ie comprised of exactly three parts, separated by a dot\n// character).\nfunc extractClaimsRaw(s string) (string, bool) {\n\t_, s, ok := strings.Cut(s, tokenDelim)\n\tif !ok { // no period found\n\t\treturn \"\", false\n\t}\n\tclaims, s, ok := strings.Cut(s, tokenDelim)\n\tif !ok { // only one period found","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/credentials/jwt/file_reader.go#L44-L80","documentation":"readToken wraps any failure of extractExpiration as 'token file %q: %v: %w' with the path, the inner JWT error, and the errJWTValidation sentinel (file_reader.go:60-63). It is the umbrella error for [175]–[179]: the file was readable and non-empty but its content is not a valid, unexpired JWT.","triggerScenarios":"extractExpiration returns a non-nil error — token is not three dot-separated parts, base64 decode fails, JSON unmarshal fails, no exp claim, or the exp claim is in the past. The inner %v identifies which sub-case.","commonSituations":"Wrong file used (OAuth access token instead of ID token, a raw key, a refresh token), a JWT minted without exp, a stale token whose exp passed, or copy/paste corruption of the token string.","solutions":["Inspect the inner %v to identify the specific failure ([175]–[179]) and apply the matching fix.","Confirm the file actually contains a JWT (header.payload.signature) and not another credential type.","Regenerate/refresh the token so it has a valid future exp claim.","Validate the file content with a JWT decoder (e.g. jwt.io or a local decoder) before pointing the credential at it."],"exampleFix":"// before: pointed at the wrong credential file\nr := &jwtFileReader{tokenFilePath: \"/etc/creds/oauth_access_token\"}\n\n// after: pointed at the ID-token file with a valid JWT\nr := &jwtFileReader{tokenFilePath: \"/etc/creds/id_token_jwt\"}","handlingStrategy":"validation","validationCode":"// Pre-decode the JWT to fail with a clear message before the credential uses it.\nif _, _, err := r.readToken(); err != nil {\n    return fmt.Errorf(\"token file contents are not a valid JWT: %w\", err)\n}","typeGuard":"func isJWTValidationErr(err error) bool {\n    return errors.Is(err, errJWTValidation)\n}","tryCatchPattern":"_, _, err := r.readToken()\nif err != nil {\n    if errors.Is(err, errJWTValidation) {\n        // see the inner %v for the specific JWT defect ([175]-[179]).\n    }\n    return err\n}","preventionTips":["Confirm the file contains a JWT, not an OAuth/refresh token or raw key.","Validate the token with a JWT decoder before pointing the credential at it.","Regenerate tokens whose exp has passed.","Watch the inner error string to route to [175]-[179] fixes."],"tags":["grpc","jwt","validation","credentials","configuration"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}