grpc/grpc-go · error
unmarshal error
Error message
unmarshal error: %v
What it means
Returned by extractExpiration when json.Unmarshal of the decoded payload fails. The bytes decoded as base64 but are not valid JSON matching jwtClaims. The %v is the JSON decoder error. The reader only needs an `exp` field, so a well-formed JWT should never hit this; corruption or a non-JSON payload is the usual cause.
Solutions
- Confirm the token is a signed (JWS) JWT, not an encrypted (JWE) token; the gRPC reader cannot decrypt JWEs.
- Decode the payload manually (base64 -d) and confirm it is a JSON object containing an exp field.
- Re-issue the token through the intended ID-token flow.
Defensive patterns
Strategy: validation
Validate before calling
func claimsJSON(claimsSeg string) (map[string]any, error) {
b, err := base64.RawURLEncoding.DecodeString(claimsSeg)
if err != nil {
return nil, err
}
var m map[string]any
if err := json.Unmarshal(b, &m); err != nil {
return nil, err
}
return m, nil
} Prevention
- Confirm the token is a JWS (signed) JWT, not a JWE (encrypted).
- Decode and inspect the payload before deploying the token.
- Use a reputable issuer to avoid malformed payloads.
When it happens
Trigger: The base64-decoded payload is not a JSON object (e.g. a JWE-encrypted token whose payload is ciphertext, a malformed token, or binary garbage that happened to be base64-decodable).
Common situations: Using an encrypted JWT (JWE) where a signed JWT (JWS) is expected; binary content inadvertently placed in the token file; character-set corruption.
Related errors
- decode error
- expected 3 parts in token
- credentials: audience cannot be empty
- failed to unmarshal JWT call credentials config
- least-request: unable to unmarshal LBConfig
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/f40c05f109823c87.
Report an issue: GitHub.
Appendix: source
Thrown at credentials/jwt/file_reader.go:103
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")
}
return expTime, nil
}
View on GitHub (pinned to 0c51461d27)