grpc/grpc-go · error

decode error

Error message

decode error: %v

What it means

Returned by extractExpiration when base64.RawURLEncoding.DecodeString fails on the claims segment. The header/signature split was correct (two dots present) but the payload is not valid unpadded URL-safe base64. The %v is the base64 decoder error.

Solutions

  1. Regenerate the token with a JWT library that emits unpadded URL-safe base64 (the JWT spec default).
  2. Verify the payload segment length is a multiple of 4 after removing padding, or that it has no '='.
  3. Replace any '+'/'/' characters and strip '=' to test whether encoding is the cause.
Defensive patterns

Strategy: validation

Validate before calling

func claimsDecode(claimsSeg string) ([]byte, error) {
    // Mirror the reader: RawURLEncoding (no padding).
    return base64.RawURLEncoding.DecodeString(claimsSeg)
}

Prevention

When it happens

Trigger: The payload segment contains characters outside the URL-safe base64 alphabet, has incorrect padding (the library uses RawURLEncoding so padding must be absent), or was corrupted/truncated.

Common situations: Token generated by a library that emits padded base64 (with '=') or standard base64 ('+'/'/') instead of URL-safe; manual editing of the token; encoding mismatch between issuer and gRPC jwt reader.

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/f7036b960fe05d0b. Report an issue: GitHub.

Appendix: 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 0c51461d27)