grpc/grpc-go · error
token file %q: %v: %w
Error message
token file %q: %v: %w
What it means
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.
Source
Thrown at credentials/jwt/file_reader.go:62
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)
if err != nil {
return "", time.Time{}, fmt.Errorf("%v: %w", err, errTokenFileAccess)
}
token := strings.TrimSpace(string(tokenBytes))
if token == "" {
return "", time.Time{}, fmt.Errorf("token file %q is empty: %w", r.tokenFilePath, errJWTValidation)
}
exp, err := r.extractExpiration(token)
if err != nil {
return "", time.Time{}, fmt.Errorf("token file %q: %v: %w", r.tokenFilePath, err, errJWTValidation)
}
return token, exp, nil
}
const tokenDelim = "."
// extractClaimsRaw returns the JWT's claims part as raw string. Even though the
// header and signature are not used, it still expects that the input string to
// be well-formed (ie comprised of exactly three parts, separated by a dot
// character).
func extractClaimsRaw(s string) (string, bool) {
_, s, ok := strings.Cut(s, tokenDelim)
if !ok { // no period found
return "", false
}
claims, s, ok := strings.Cut(s, tokenDelim)
if !ok { // only one period foundView on GitHub (pinned to 03255a9237)
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.
Example fix
// before: pointed at the wrong credential file
r := &jwtFileReader{tokenFilePath: "/etc/creds/oauth_access_token"}
// after: pointed at the ID-token file with a valid JWT
r := &jwtFileReader{tokenFilePath: "/etc/creds/id_token_jwt"} Defensive patterns
Strategy: validation
Validate before calling
// Pre-decode the JWT to fail with a clear message before the credential uses it.
if _, _, err := r.readToken(); err != nil {
return fmt.Errorf("token file contents are not a valid JWT: %w", err)
} Type guard
func isJWTValidationErr(err error) bool {
return errors.Is(err, errJWTValidation)
} Try / catch
_, _, err := r.readToken()
if err != nil {
if errors.Is(err, errJWTValidation) {
// see the inner %v for the specific JWT defect ([175]-[179]).
}
return err
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- credentials: audience cannot be empty
- no expiration claims
- credentials: ctx cannot be nil
- unsupported mode: %v
- %v: %w
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/5b499e470a11c0dd.
Report an issue: GitHub.