grpc/grpc-go · error
decode error: %v
Error message
decode error: %v
What it means
After splitting out the claims segment, base64.RawURLEncoding.DecodeString fails and extractExpiration returns 'decode error: %v' (file_reader.go:96-98). The library expects unpadded URL-safe base64 (RFC 7515 JWS encoding); standard base64 or padded URL-safe base64 will not decode.
Source
Thrown at credentials/jwt/file_reader.go:98
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.
if expTime.Before(time.Now()) {
return time.Time{}, fmt.Errorf("expired token")
}
View on GitHub (pinned to 03255a9237)
Solutions
- Re-mint the token from a standards-compliant issuer so the payload is raw URL-safe base64 without padding.
- If you control issuance, ensure the encoder uses base64.RawURLEncoding (Go) / base64url_NOPAD.
- Do not re-encode or re-wrap the token after issuance.
- Decode the middle segment manually with base64.RawURLEncoding to confirm before deploying.
Example fix
// before: issuer padded the payload // header.cGF5bG9hZA==.sig // after: raw URL-safe, no padding // header.cGF5bG9hZA.sig // (re-issue from the token producer using base64.RawURLEncoding)
Defensive patterns
Strategy: validation
Validate before calling
// Validate raw URL-safe base64 decode of the claims segment.
seg := strings.Split(tok, ".")[1]
if _, err := base64.RawURLEncoding.DecodeString(seg); err != nil {
return fmt.Errorf("claims segment is not raw URL-safe base64: %w", err)
} Try / catch
_, _, err := r.readToken()
if err != nil && strings.Contains(err.Error(), "decode error") {
// issuer emitted padded or standard-base64 payload; re-mint token.
return err
} Prevention
- Ensure issuers use base64.RawURLEncoding (no padding).
- Do not re-encode or re-wrap tokens after issuance.
- Decode the middle segment manually to confirm it is raw URL-safe base64.
- Avoid tokens that pass through tools that switch base64 alphabets.
When it happens
Trigger: The claims segment is not valid raw URL-safe base64: it uses '+'/'/' instead of '-','_', it has '=' padding, it contains non-base64 characters, or its length is wrong for the underlying JSON.
Common situations: A token minted by a library that emits padded base64 ('=' suffix), a token re-encoded through a tool that switched to standard alphabet, or manual editing that introduced illegal characters.
Related errors
- expected 3 parts in token
- unmarshal error: %v
- credentials: audience cannot be empty
- token file %q: %v: %w
- no expiration claims
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/f7036b960fe05d0b.
Report an issue: GitHub.