Pumpkin-MC/Pumpkin · error · AuthError

JSON parse error

Error message

JSON parse error: {0}

What it means

This error is produced by the JWT error enum in pumpkin-auth when parsing JSON data fails during Minecraft Web/Telemetry-style token (Mojang public key / profile key) verification. It wraps serde_json::Error via #[from], so any serde deserialization failure on a JWT header or payload surfaces as this variant. It typically means the token segments are not valid JSON after Base64 decoding.

Solutions

  1. Log the underlying serde_json::Error source (use {:?} or the source chain) to see the exact parse failure location
  2. Reject the connection: this token is untrustworthy, so return the auth failure to the client instead of retrying
  3. Verify you are decoding the correct JWT segment (header/payload) with URL-safe Base64 without padding before JSON parsing
  4. Confirm the client is a legitimate Minecraft client version; malformed tokens usually indicate tampering or a broken proxy

Example fix

// before
let claims: PlayerClaims = serde_json::from_slice(&decoded)?;
// after
let claims: PlayerClaims = serde_json::from_slice(&decoded).map_err(|e| {
    log::warn!(" rejecting client: invalid token JSON: {e}");
    AuthError::JsonParse(e)
})?;
Defensive patterns

Strategy: try-catch

Validate before calling

// validate token shape before parsing
fn token_segments_look_valid(token: &str) -> bool {
    let parts: Vec<&str> = token.split('.').collect();
    parts.len() == 3 && parts.iter().take(2).all(|p| !p.is_empty())
}

Type guard

fn is_valid_jwt_shape(token: &str) -> bool {
    token.split('.').count() == 3
}

Try / catch

match jwt::parse(&token) {
    Err(jwt::Error::JsonParse(e)) => {
        log::warn!("malformed token JSON, rejecting client: {e}");
        // disconnect client
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calling JWT parsing/verification functions (e.g. decoding a player's public key token) where the Base64-decoded header or claims string is malformed JSON: truncated tokens, clients sending corrupted or hand-crafted tokens, or decoding the wrong segment.

Common situations: Modified or hacked clients sending malformed chat/session tokens; proxy software mangling token payloads; treating non-JSON strings (raw binary or double-encoded Base64) as token segments.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of Pumpkin-MC/Pumpkin@8d4639e25a (2026-09-09). Data as JSON: /api/errors/bf5e6f013c312a35. Report an issue: GitHub.

Appendix: source

Thrown at crates/pumpkin-auth/src/jwt/mod.rs:42

    pub uuid: String,
    /// The player's Xbox User ID (XUID).
    pub xuid: String,
}

/// Represents the possible errors that can occur during JWT verification.
#[derive(Debug, Error)]
pub enum AuthError {
    /// Indicates that a JWT token has an invalid format (not enough parts).
    #[error("Invalid token format")]
    InvalidTokenFormat,
    /// Indicates that the 'x5u' (X.509 URL) header parameter is missing from a token.
    #[error("x5u not found in header")]
    MissingX5U,
    /// Indicates a failure in Base64 decoding.
    #[error("Base64 decoding failed: {0}")]
    Base64Decode(#[from] base64::DecodeError),
    /// Indicates a failure in parsing JSON data.
    #[error("JSON parse error: {0}")]
    JsonParse(#[from] serde_json::Error),
    /// Indicates a failure in building a public key from its representation.
    #[error("Public key build failed: {0}")]
    PublicKeyBuild(String),
    /// Indicates that the token was not signed by the trusted Mojang public key.
    #[error("Token not signed by trusted Mojang key")]
    MojangKeyMismatch,
    /// Indicates that the token's signature is invalid.
    #[error("Invalid signature")]
    InvalidSignature,
    /// Indicates an error related to ECDSA signature operations.
    #[error("ECDSA signature error: {0}")]
    Ecdsa(#[from] ecdsa::Error),
}

/// Decodes a Base64 URL-safe encoded string with no padding.
///
/// # Arguments

View on GitHub (pinned to 8d4639e25a)