Pumpkin-MC/Pumpkin · error · LoginError

JWT chain validation failed

Error message

JWT chain validation failed: {0}

What it means

This is the LoginError::ChainValidationFailed variant of Pumpkin's Bedrock login error enum. It wraps an AuthError produced while validating the client's JWT identity chain during the Bedrock edition login handshake. The library throws it because the Xbox Live / Mojang certificate chain sent in the Login packet failed cryptographic or structural validation, so the client's identity cannot be trusted.

Solutions

  1. Have the client sign out and back into Xbox Live so a fresh, unexpired JWT chain is issued
  2. Update the server (and its bundled Mojang/Xbox public keys) so the trusted key set matches current Mojang certificates
  3. If the client is modified, revert to a vanilla client that presents a genuine certificate chain
  4. Check middleware/proxies between client and server for packet corruption of the login payload

Example fix

// before: accepting any login without inspecting the wrapped cause
match login_result { Err(e) => warn!("login failed"), }
// after: log the underlying AuthError to see why the chain was rejected
match login_result {
    Err(LoginError::ChainValidationFailed(auth_err)) => {
        warn!("JWT chain rejected: {auth_err}; client should re-authenticate with Xbox Live");
    }
    Err(e) => warn!("login failed: {e}"),
    Ok(_) => {}
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Before treating login as success, verify chain presence and freshness client-side
fn precheck_chain(jwt_chain: &[String]) -> Result<(), String> {
    if jwt_chain.is_empty() { return Err("empty JWT chain".into()); }
    if jwt_chain.iter().any(|j| j.is_empty()) { return Err("blank JWT in chain".into()); }
    Ok(())
}

Type guard

fn is_chain_validation_failed(e: &LoginError) -> bool {
    matches!(e, LoginError::ChainValidationFailed(_))
}

Try / catch

match login_result {
    Err(LoginError::ChainValidationFailed(auth)) => {
        // transient auth problems: prompt re-login; do not retry the same packet
        disconnect_with("Please re-authenticate with Xbox Live and reconnect")
    }
    Err(e) => disconnect_with(&format!("Login failed: {e}")),
    Ok(p) => admit(p),
}

Prevention

When it happens

Trigger: A Bedrock client sends a Login packet whose JWT chain (xbox live -> xsts -> mojang certificates) fails AuthError validation — e.g. an expired XSTS token, a chain with missing or reordered links, a signature that doesn't verify, or a chain signed by an untrusted key.

Common situations: Clients with stale Xbox Live sessions, modified/unofficial clients presenting forged certificates, servers whose trusted root keys are outdated after a Mojang key rotation, or proxy setups that strip or mangle the chain.

Related errors


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

Appendix: source

Thrown at crates/pumpkin/src/net/bedrock/login/mod.rs:34

};
use pumpkin_protocol::bedrock::{
    client::{resource_pack_stack::PackInstanceId, resource_packs_info::PackInfoData},
    server::{login::ClientData, resource_pack_client_response::SResourcePackClientResponse},
};
use pumpkin_util::version::BedrockMinecraftVersion;
use pumpkin_world::{CURRENT_BEDROCK_MC_PROTOCOL, CURRENT_BEDROCK_MC_VERSION};
use serde::{Deserialize, de::Error};
use serde_repr::Deserialize_repr;
use std::sync::Arc;
use thiserror::Error;
use tracing::debug;
use uuid::Uuid;

#[derive(Debug, Error)]
pub enum LoginError {
    #[error("Login packet data is not valid JSON")]
    InvalidTokenFormat(#[from] serde_json::Error),
    #[error("JWT chain validation failed: {0}")]
    ChainValidationFailed(#[from] AuthError),
    #[error("The validated username is invalid")]
    InvalidUsername,
    #[error("Could not parse UUID from validated token")]
    InvalidUuid,
    #[error("Cannot accept self-signed token. Authentication is enforced by server config.")]
    SelfSignedNotAllowed,
    #[error("Got a guest/splitscreen login request. Currently unimplemented.")]
    GuestUnimplemented,
    #[error("Failed to decode extra using decode_b64_url_nopad.")]
    DecodeExtraError,
}

#[derive(Deserialize_repr)]
#[repr(u8)]
enum AuthenticationType {
    Full,
    Guest,

View on GitHub (pinned to 8d4639e25a)