Pumpkin-MC/Pumpkin · error · TelemetryVerificationError
Signature verification failed
Error message
Signature verification failed: {0} What it means
TelemetryVerificationError::VerificationFailed(String), produced when the Ed25519 cryptographic signature does not verify against the given public key and message. The key and signature parsed fine, but the signature was not made by the matching secret key over the exact verified payload.
Solutions
- Ensure the client signs the exact byte string the server verifies — agree on a canonical payload (timestamp included)
- Confirm the verifying key corresponds to the client's current signing key (sync key rotation)
- Log which payload bytes were verified on both sides and diff them
- Check that proxies/gateways are not rewriting the request body or timestamp before verification
Example fix
// before
let msg = format!("{payload}{timestamp}"); // client order differs from server
// after
let msg = format!("{timestamp}{payload}"); // use one agreed canonical format on both sides Defensive patterns
Strategy: try-catch
Try / catch
match telemetry::verify(&key, &sig, &msg, now) {
Err(TelemetryVerificationError::VerificationFailed(m)) => {
log::warn!("telemetry signature mismatch: {m}");
// reject request / rotate keys if this spikes
}
Ok(()) => { /* proceed */ }
Err(e) => return Err(e.into()),
} Prevention
- Pin one canonical payload format shared by signer and verifier (include the timestamp string verbatim)
- Keep client signing keys in sync with server verifying keys; document key rotation
- Alert on spikes of VerificationFailed — it may indicate tampering or a botched deploy
When it happens
Trigger: Calling telemetry::verify with a signature produced over different bytes than what the server verifies (e.g. different timestamp string, reordered fields, different serialization), a mismatched key/signature pair, or an attacker-tampered payload.
Common situations: Client and server canonicalize the payload differently (whitespace, field order, timestamp normalization); key rotation on the server without updating clients; MITM/replay attempts on telemetry endpoints.
Related errors
- Failed to verify Ed25519 signature
- Invalid public key hex encoding
- Invalid public key bytes
- Invalid signature bytes
- too large
AI-assisted analysis of Pumpkin-MC/Pumpkin@8d4639e25a (2026-09-09).
Data as JSON: /api/errors/d399679ab7b91982.
Report an issue: GitHub.
Appendix: source
Thrown at crates/pumpkin/src/telemetry.rs:135
/// Errors that can occur during telemetry request signature verification.
#[derive(Debug, thiserror::Error, PartialEq, Eq)]
pub enum TelemetryVerificationError {
#[error("Invalid timestamp string format")]
InvalidTimestamp,
#[error(
"Timestamp drift exceeded: drift was {drift}s (max allowed is {MAX_CLOCK_DRIFT_SECS}s)"
)]
ClockDriftExceeded { drift: u64 },
#[error("Invalid public key hex encoding")]
InvalidPublicKeyHex,
#[error("Invalid public key bytes: {0}")]
InvalidPublicKey(String),
#[error("Invalid signature hex encoding")]
InvalidSignatureHex,
#[error("Invalid signature bytes: {0}")]
InvalidSignature(String),
#[error("Signature verification failed: {0}")]
VerificationFailed(String),
}
/// Verifies a signed telemetry request against an Ed25519 public key and timestamp.
///
/// Ensures clock drift between `current_time_secs` and `timestamp_str` does not exceed `±300` seconds.
pub fn verify_telemetry_request(
pubkey_hex: &str,
sig_hex: &str,
timestamp_str: &str,
body_bytes: &[u8],
current_time_secs: u64,
) -> Result<(), TelemetryVerificationError> {
let ts: u64 = timestamp_str
.parse()
.map_err(|_| TelemetryVerificationError::InvalidTimestamp)?;
let drift = current_time_secs.abs_diff(ts);View on GitHub (pinned to 8d4639e25a)