grpc/grpc-go · error
unmarshal error: %v
Error message
unmarshal error: %v
What it means
After base64-decoding the claims segment, json.Unmarshal into jwtClaims fails and extractExpiration returns 'unmarshal error: %v' (file_reader.go:101-103). The decoded bytes are not valid JSON or not a JSON object containing the expected fields.
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 03255a9237)
Solutions
- Re-mint the token; do not hand-edit the payload.
- Decode the base64 payload yourself and pretty-print the JSON to find the syntax problem.
- Ensure the issuer emits canonical JSON (RFC 8259).
- If the payload legitimately contains fields jwtClaims ignores, that is fine — only structural errors fail Unmarshal.
Example fix
// before: payload decoded to malformed JSON
// {"exp": 1700000000,}
// after: re-issue so the payload is valid JSON
// {"iss":"...","exp":1700000000,"aud":"..."} Defensive patterns
Strategy: validation
Validate before calling
// Pre-validate that the decoded payload is a JSON object.
seg := strings.Split(tok, ".")[1]
b, err := base64.RawURLEncoding.DecodeString(seg)
if err != nil { return err }
if !json.Valid(b) {
return fmt.Errorf("claims payload is not valid JSON")
} Try / catch
_, _, err := r.readToken()
if err != nil && strings.Contains(err.Error(), "unmarshal error") {
// payload corrupt: re-mint the token; do not hand-edit.
return err
} Prevention
- Never hand-edit JWT payloads.
- Decode and pretty-print the payload to spot JSON errors.
- Ensure issuers emit canonical JSON.
- Re-mint corrupt tokens from a trusted source.
When it happens
Trigger: The decoded payload is truncated, is a JSON array/string instead of an object, contains a syntax error, or uses a JSON encoding Go's encoding/json rejects (e.g. duplicate keys with strict handling, trailing commas).
Common situations: Corrupt token, a payload that was modified after issuance, a base64 bug that decoded to the wrong bytes, or a non-standard issuer producing JSON5/relaxed JSON.
Related errors
- expected 3 parts in token
- decode error: %v
- invalid code: %d
- invalid code: %q
- credentials: audience cannot be empty
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/f40c05f109823c87.
Report an issue: GitHub.