{"record":{"id":"2eafd600d5ecddac","repo":"grpc/grpc-go","slug":"token-file-access-error","errorCode":null,"errorMessage":"token file access error","messagePattern":"token file access error","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"credentials/jwt/file_reader.go","lineNumber":32,"sourceCode":" * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\npackage jwt\n\nimport (\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n)\n\nvar (\n\terrTokenFileAccess = errors.New(\"token file access error\")\n\terrJWTValidation   = errors.New(\"invalid JWT\")\n)\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)","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/credentials/jwt/file_reader.go#L14-L50","documentation":"errTokenFileAccess is returned by jwtFileReader.readToken() (credentials/jwt/file_reader.go:52) when os.ReadFile(r.tokenFilePath) fails. The jwt package reads a JWT from a file to supply per-RPC call credentials; if the underlying OS file read returns an error, the library wraps it with this sentinel. The wrapped error preserves the original OS error (e.g. 'no such file or directory', 'permission denied') via %w so errors.Is(err, errTokenFileAccess) can match it.","triggerScenarios":"Constructing or using JWT-based per-RPC credentials that point at a tokenFilePath which os.ReadFile cannot open — path missing, file unreadable, path is a directory, or the configured path string is empty/garbage. It surfaces at the first readToken() call (e.g. when GetRequestMetadata is invoked for the first RPC).","commonSituations":"Misconfigured GOOGLE_APPLICATION_TOKEN_FILE / token path env var; in Kubernetes/Docker the service-account JWT volume or secret not mounted at the expected path; wrong working directory making a relative path resolve incorrectly; file owned by another user with mode 0600; symlink pointing to a nonexistent target.","solutions":["Confirm the path resolves to a real readable file: run ls -l <tokenFilePath> and check it is a regular file readable by the process user.","If the path comes from an env var, print os.Getenv() of that var at startup to verify it is set and not empty.","In containers, verify the secret/projected volume is mounted at the same path the credentials config points to (check the mounted volume, not just the pod spec).","Switch to an absolute path to avoid working-directory-dependent resolution failures."],"exampleFix":"// before\ncreds := jwt.NewTokenFromFile(os.Getenv(\"MY_JWT_FILE\")) // env unset -> \"\"\nconn, _ := grpc.Dial(..., grpc.WithPerRPCCredentials(creds))\n\n// after\np := os.Getenv(\"MY_JWT_FILE\")\nif fi, err := os.Stat(p); err != nil || fi.IsDir() {\n    log.Fatalf(\"token file %q not usable: %v\", p, err)\n}\ncreds := jwt.NewTokenFromFile(p)","handlingStrategy":"validation","validationCode":"// Validate the token file before constructing JWT credentials.\nfunc validTokenFile(path string) error {\n    fi, err := os.Stat(path)\n    if err != nil {\n        return fmt.Errorf(\"token file %q: %w\", path, err)\n    }\n    if fi.IsDir() {\n        return fmt.Errorf(\"token file %q is a directory\", path)\n    }\n    // try a real read to catch permission issues\n    if _, err := os.ReadFile(path); err != nil {\n        return fmt.Errorf(\"token file %q unreadable: %w\", path, err)\n    }\n    return nil\n}\n\n// usage\nif err := validTokenFile(tokenPath); err != nil { log.Fatal(err) }","typeGuard":null,"tryCatchPattern":"// jwt credentials surface read errors via GetRequestMetadata at call time;\n// detect the sentinel and surface it clearly.\nmd, err := creds.GetRequestMetadata(ctx)\nif err != nil {\n    if errors.Is(err, errTokenFileAccess) {\n        // token file is missing/unreadable; check path & permissions\n    }\n}","preventionTips":["Use absolute paths for the token file to avoid working-directory dependence.","In containers, validate the mounted secret volume path at process start.","Centralize credential construction in one function that stat-checks files first."],"tags":["go","grpc","security","jwt","filesystem","credentials"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}