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

  1. Re-mint the token from a standards-compliant issuer so the payload is raw URL-safe base64 without padding.
  2. If you control issuance, ensure the encoder uses base64.RawURLEncoding (Go) / base64url_NOPAD.
  3. Do not re-encode or re-wrap the token after issuance.
  4. 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

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


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