{"record":{"id":"5047a124f6042181","repo":"grpc/grpc-go","slug":"v-w","errorCode":null,"errorMessage":"%v: %w","messagePattern":"%v: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"credentials/jwt/file_reader.go","lineNumber":52,"sourceCode":")\n\n// jwtClaims represents the JWT claims structure for extracting expiration time.\ntype jwtClaims struct {\n\tExp int64 `json:\"exp\"`\n}\n\n// jwtFileReader handles reading and parsing JWT tokens from files.\n// It is safe to call methods on this type concurrently as no state is stored.\ntype jwtFileReader struct {\n\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","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/credentials/jwt/file_reader.go#L34-L70","documentation":"Returned by jwtFileReader.readToken when os.ReadFile fails to read the token file (the %v is the OS error and the wrapped sentinel is errTokenFileAccess). The call site in jwtTokenFileCallCreds converts this into a gRPC codes.Unavailable status, since the file (often a mounted token volume) is temporarily unreadable.","triggerScenarios":"The configured token file path does not exist; the process lacks read permission on the file; the file is on a volume that has not yet been mounted (Kubernetes projected service-account token) or has been rotated away; a path typo or wrong working directory.","commonSituations":"Kubernetes pod starting before the projected token volume is mounted; running as a user without read access to /var/run/secrets/...; relative path resolved against an unexpected working directory; NFS/containerd volume mount race.","solutions":["Check the exact token file path exists and is readable by the process user (ls -l, stat).","In Kubernetes, ensure the ServiceAccount token is projected and add an initContainer or readiness probe that waits for the file.","Use an absolute path for tokenFilePath.","Run the binary as a user/group that has read permission on the token file."],"exampleFix":"// before\ncreds, err := jwt.NewTokenFileCallCredentials(\"token.jwt\")\n// after\ncreds, err := jwt.NewTokenFileCallCredentials(\"/var/run/secrets/tokens/my-sa-token\")","handlingStrategy":"validation","validationCode":"// Validate readability before constructing the credential.\nfunc checkTokenFile(path string) error {\n    info, err := os.Stat(path)\n    if err != nil {\n        return fmt.Errorf(\"token file %q: %w\", path, err)\n    }\n    if info.Mode().Perm()&0400 == 0 {\n        return fmt.Errorf(\"token file %q not readable\", path)\n    }\n    return nil\n}\n\nif err := checkTokenFile(tokenPath); err != nil {\n    log.Fatal(err)\n}","typeGuard":null,"tryCatchPattern":"// The RPC surfaces codes.Unavailable; detect and fail fast on startup:\nif status.Code(err) == codes.Unavailable && strings.Contains(err.Error(), errTokenFileAccess.Error()) {\n    log.Fatal(\"token file unreadable; check path and permissions\")\n}","preventionTips":["Stat the token file at startup and fail fast.","Use absolute paths from a single config source.","In Kubernetes, ensure the projected token volume is mounted before the main container starts."],"tags":["grpc","jwt","filesystem","credentials","kubernetes"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}