grpc/grpc-go · error
token file is empty
Error message
token file %q is empty: %w
What it means
Returned by jwtFileReader.readToken when the file was read successfully but contains only whitespace. The sentinel is errJWTValidation, which the call site maps to codes.Unauthenticated. An empty token file usually means an external token injector (e.g. sidecar, agent) has not yet written the token, or wrote it incorrectly.
Solutions
- Verify the token file has content: wc -c /path/to/token.
- Ensure the token injector (sidecar/init) runs to completion before the gRPC client reads the file; use a shared volume with proper ordering.
- Regenerate the token/Secret so it contains a valid JWT.
- Add a startup check that waits until the file is non-empty before dialing.
Defensive patterns
Strategy: validation
Validate before calling
func nonEmptyTokenFile(path string) error {
b, err := os.ReadFile(path)
if err != nil {
return err
}
if strings.TrimSpace(string(b)) == "" {
return fmt.Errorf("token file %q is empty", path)
}
return nil
} Prevention
- At startup, verify the token file is non-empty before dialing.
- Ensure the token injector (sidecar/init) completes before the gRPC client reads the file.
- Use a readiness probe that checks file content, not just existence.
When it happens
Trigger: The token file exists but is zero-byte or whitespace-only; a token-refresh agent created/truncated the file but crashed before writing; a ConfigMap/Secret mounted as an empty file.
Common situations: Token-injecting sidecar (Vault agent, gcp-creds) starting after the main container; Kubernetes Secret referenced but empty; CI copying a placeholder file.
Related errors
- token file access error
- %v: %w
- cannot send secure credentials on an insecure connection
- credentials: audience cannot be empty
- credentials: failed to read the service account key file
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/bd3c3693be38bbcb.
Report an issue: GitHub.
Appendix: source
Thrown at credentials/jwt/file_reader.go:57
}
// 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)
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)View on GitHub (pinned to 0c51461d27)