{"record":{"id":"9af7234d98c9b919","repo":"grpc/grpc-go","slug":"credentials-failed-to-read-the-service-account-ke","errorCode":null,"errorMessage":"credentials: failed to read the service account key file: %v","messagePattern":"credentials: failed to read the service account key file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"credentials/oauth/oauth.go","lineNumber":78,"sourceCode":"// removeServiceNameFromJWTURI removes RPC service name from URI.\nfunc removeServiceNameFromJWTURI(uri string) (string, error) {\n\tparsed, err := url.Parse(uri)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tparsed.Path = \"/\"\n\treturn parsed.String(), nil\n}\n\ntype jwtAccess struct {\n\tjsonKey []byte\n}\n\n// NewJWTAccessFromFile creates PerRPCCredentials from the given keyFile.\nfunc NewJWTAccessFromFile(keyFile string) (credentials.PerRPCCredentials, error) {\n\tjsonKey, err := os.ReadFile(keyFile)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"credentials: failed to read the service account key file: %v\", err)\n\t}\n\treturn NewJWTAccessFromKey(jsonKey)\n}\n\n// NewJWTAccessFromKey creates PerRPCCredentials from the given jsonKey.\nfunc NewJWTAccessFromKey(jsonKey []byte) (credentials.PerRPCCredentials, error) {\n\treturn jwtAccess{jsonKey}, nil\n}\n\nfunc (j jwtAccess) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {\n\t// Remove RPC service name from URI that will be used as audience\n\t// in a self-signed JWT token. It follows https://google.aip.dev/auth/4111.\n\taud, err := removeServiceNameFromJWTURI(uri[0])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// TODO: the returned TokenSource is reusable. Store it in a sync.Map, with\n\t// uri as the key, to avoid recreating for every RPC.","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/credentials/oauth/oauth.go#L60-L96","documentation":"Returned by oauth.NewJWTAccessFromFile (oauth.go:78) when os.ReadFile(keyFile) fails. The function loads a Google service-account JSON key file to build self-signed JWT access credentials; without readable file contents it cannot proceed. The wrapped %v carries the underlying os PathError (open … no such file or directory / permission denied).","triggerScenarios":"Passing a non-existent, relative, or unreadable path to NewJWTAccessFromFile; the file exists but the process lacks read permission; path derived from a missing config flag.","commonSituations":"Service-account JSON not mounted in the container; typo in GOOGLE_APPLICATION_CREDENTIALS-style path; running as a different UID than the file owner; relative path interpreted from an unexpected working directory.","solutions":["Verify the path exists and is readable (os.Stat / ls -l) from the process's working directory.","Use an absolute path; mount the key file via the same mechanism (secret/configmap) the deployment uses.","Prefer NewJWTAccessFromKey([]byte) and pass already-loaded bytes if the path resolution is fragile."],"exampleFix":"// before\ncreds, err := oauth.NewJWTAccessFromFile(\"service-account.json\") // relative, cwd-dependent\n\n// after\nconst keyPath = \"/etc/secrets/sa/service-account.json\"\nif _, err := os.Stat(keyPath); err != nil {\n    log.Fatalf(\"key file: %v\", err)\n}\ncreds, err := oauth.NewJWTAccessFromFile(keyPath)","handlingStrategy":"validation","validationCode":"if keyPath == \"\" { return fmt.Errorf(\"service-account key path is empty\") }\nif _, err := os.Stat(keyPath); err != nil {\n    return fmt.Errorf(\"service-account key not found: %w\", err)\n}\ncreds, err := oauth.NewJWTAccessFromFile(keyPath)\nif err != nil { return err }","typeGuard":null,"tryCatchPattern":"creds, err := oauth.NewJWTAccessFromFile(keyPath)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to read the service account key file\") {\n        // surface actionable message: check path/permissions/mount\n    }\n    return err\n}","preventionTips":["Use absolute paths for service-account keys.","Mount keys via secrets/configmaps and assert readability in a startup probe.","Prefer NewJWTAccessFromKey with pre-loaded bytes when path resolution is fragile."],"tags":["oauth","jwt","file-io","configuration","go"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}