grpc/grpc-go · error

token file access error

Error message

token file access error

What it means

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.

Source

Thrown at credentials/jwt/file_reader.go:32

 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package jwt

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"strings"
	"time"
)

var (
	errTokenFileAccess = errors.New("token file access error")
	errJWTValidation   = errors.New("invalid JWT")
)

// jwtClaims represents the JWT claims structure for extracting expiration time.
type jwtClaims struct {
	Exp int64 `json:"exp"`
}

// jwtFileReader handles reading and parsing JWT tokens from files.
// It is safe to call methods on this type concurrently as no state is stored.
type jwtFileReader struct {
	tokenFilePath string
}

// readToken reads and parses a JWT token from the configured file.
// Returns the token string, expiration time, and any error encountered.
func (r *jwtFileReader) readToken() (string, time.Time, error) {
	tokenBytes, err := os.ReadFile(r.tokenFilePath)

View on GitHub (pinned to 03255a9237)

Solutions

  1. 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.
  2. If the path comes from an env var, print os.Getenv() of that var at startup to verify it is set and not empty.
  3. 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).
  4. Switch to an absolute path to avoid working-directory-dependent resolution failures.

Example fix

// before
creds := jwt.NewTokenFromFile(os.Getenv("MY_JWT_FILE")) // env unset -> ""
conn, _ := grpc.Dial(..., grpc.WithPerRPCCredentials(creds))

// after
p := os.Getenv("MY_JWT_FILE")
if fi, err := os.Stat(p); err != nil || fi.IsDir() {
    log.Fatalf("token file %q not usable: %v", p, err)
}
creds := jwt.NewTokenFromFile(p)
Defensive patterns

Strategy: validation

Validate before calling

// Validate the token file before constructing JWT credentials.
func validTokenFile(path string) error {
    fi, err := os.Stat(path)
    if err != nil {
        return fmt.Errorf("token file %q: %w", path, err)
    }
    if fi.IsDir() {
        return fmt.Errorf("token file %q is a directory", path)
    }
    // try a real read to catch permission issues
    if _, err := os.ReadFile(path); err != nil {
        return fmt.Errorf("token file %q unreadable: %w", path, err)
    }
    return nil
}

// usage
if err := validTokenFile(tokenPath); err != nil { log.Fatal(err) }

Try / catch

// jwt credentials surface read errors via GetRequestMetadata at call time;
// detect the sentinel and surface it clearly.
md, err := creds.GetRequestMetadata(ctx)
if err != nil {
    if errors.Is(err, errTokenFileAccess) {
        // token file is missing/unreadable; check path & permissions
    }
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/2eafd600d5ecddac. Report an issue: GitHub.