grpc/grpc-go · error
expected 3 parts in token
Error message
expected 3 parts in token
What it means
Returned by extractClaimsRaw (via extractExpiration) when the token does not split into exactly three dot-separated parts (header.payload.signature). Without three parts the claims cannot be located, so parsing aborts. This is the most common JWT structural defect.
Solutions
- Confirm the file contains a single JWT with exactly two dots: printf '%s' "$TOKEN" | tr -cd '.' | wc -c should print 2.
- Switch the token source to one that emits a signed JWT (ID token) rather than an opaque access token.
- Strip any trailing newline/quotes from the file content.
Defensive patterns
Strategy: validation
Validate before calling
func isThreePartJWT(s string) bool {
return strings.Count(s, ".") == 2
} Type guard
func isJWT(v string) bool {
s := strings.TrimSpace(v)
return strings.Count(s, ".") == 2 && len(strings.Split(s, ".")[1]) > 0
} Prevention
- Before writing a token to the file, assert it has exactly two dots.
- Use a JWT library to generate tokens rather than hand-assembling strings.
- Strip trailing whitespace/newlines from the token.
When it happens
Trigger: The token is an opaque bearer string, a JSON document, a base64 blob, or a JWT with extra/missing dots; copy-paste truncation that dropped the signature segment.
Common situations: Writing an OAuth access token instead of an ID token; newline or trailing characters breaking the split; token truncated by a log/env var length limit.
Related errors
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/316eecff58d0fd39.
Report an issue: GitHub.
Appendix: source
Thrown at credentials/jwt/file_reader.go:94
if !ok { // no period found
return "", false
}
claims, s, ok := strings.Cut(s, tokenDelim)
if !ok { // only one period found
return "", false
}
_, _, ok = strings.Cut(s, tokenDelim)
if ok { // three periods found
return "", false
}
return claims, true
}
// extractExpiration parses the JWT token to extract the expiration time.
func (r *jwtFileReader) extractExpiration(token string) (time.Time, error) {
claimsRaw, ok := extractClaimsRaw(token)
if !ok {
return time.Time{}, fmt.Errorf("expected 3 parts in token")
}
payloadBytes, err := base64.RawURLEncoding.DecodeString(claimsRaw)
if err != nil {
return time.Time{}, fmt.Errorf("decode error: %v", err)
}
var claims jwtClaims
if err := json.Unmarshal(payloadBytes, &claims); err != nil {
return time.Time{}, fmt.Errorf("unmarshal error: %v", err)
}
if claims.Exp == 0 {
return time.Time{}, fmt.Errorf("no expiration claims")
}
expTime := time.Unix(claims.Exp, 0)
// Check if token is already expired.View on GitHub (pinned to 0c51461d27)