Pumpkin-MC/Pumpkin · error · LicenseError

Marketplace HTTP error

Error message

Marketplace HTTP error: {0}

What it means

LicenseError::Http wraps any HttpError (#[from]) raised while communicating with the marketplace's license/verification REST API. It means the license check could not complete due to an HTTP-level failure (request failed, non-2xx status, or unreadable body), not a licensing decision.

Solutions

  1. Read the inner HttpError ({0}) to distinguish request-failure vs bad status vs body-read.
  2. Verify marketplace base URL and credentials in plugin configuration.
  3. Confirm network reachability to the marketplace endpoint (curl/ping).
  4. Check marketplace service status; retry with backoff if transient.
  5. Implement offline/grace behavior around the license check using the library's cached lease instead of failing hard.

Example fix

// before
let license = manager.verify()?; // Http bubbles up
// after
let license = match manager.verify() {
    Ok(l) => l,
    Err(LicenseError::Http(e)) => { tracing::error!("marketplace unreachable: {e}"); manager.cached_lease().ok_or(e)? }
    Err(e) => return Err(e),
};
Defensive patterns

Strategy: fallback

Validate before calling

// Pre-flight reachability + config sanity before license verification
assert!(!marketplace_base_url.is_empty(), "marketplace URL configured");
let reachable = reqwest::blocking::get(format!("{base}/health")).is_ok();
if !reachable { return offline_mode(); }

Type guard

fn is_http_failure(e: &LicenseError) -> bool {
    matches!(e, LicenseError::Http(_))
}

Try / catch

match manager.verify() {
    Ok(license) => activate(license),
    Err(LicenseError::Http(e)) => {
        tracing::warn!("marketplace HTTP failure: {e}; using cached lease");
        manager.cached_lease().unwrap_or_else(fallback_unlicensed)
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling license verification functions (e.g. LicenseManager check/verify paths) when the marketplace endpoint is unreachable, returns an error status (HttpError::BadStatus), or its response body cannot be read (HttpError::BodyRead); the HttpError is auto-converted via #[from].

Common situations: Marketplace API downtime or maintenance; wrong marketplace URL/base configuration; invalid or missing API credentials causing 401/403; DNS or firewall blocking the endpoint; offline server attempting an online license check.

Related errors


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

Appendix: source

Thrown at crates/pumpkin-plugin-utils/src/license.rs:18

//! License validation, leasing, and offline grace periods.

use crate::{
    http::{HttpClient, HttpError},
    models::{CheckLicenseResponse, LicenseLease, LicenseStatus, PumpkinMetadata},
};
use std::{
    path::{Path, PathBuf},
    time::{Duration, SystemTime, UNIX_EPOCH},
};
use thiserror::Error;
use tracing::{debug, info};

/// License checking and verification errors.
#[derive(Debug, Error)]
pub enum LicenseError {
    /// HTTP communication error with marketplace.
    #[error("Marketplace HTTP error: {0}")]
    Http(#[from] HttpError),
    /// Metadata validation error (e.g. missing license on paid plugin).
    #[error("License metadata mismatch: {0}")]
    MetadataMismatch(String),
    /// License revoked or refunded by marketplace.
    #[error("License was revoked or refunded: {0}")]
    Revoked(String),
    /// License is expired.
    #[error("License has expired on {0}")]
    Expired(String),
    /// I/O error reading/writing license cache.
    #[error("I/O error with license storage: {0}")]
    Io(#[from] std::io::Error),
    /// JSON serialization error.
    #[error("JSON serialization error: {0}")]
    Json(#[from] serde_json::Error),
    /// Plugin is unsigned or missing marketplace metadata.
    #[error("Plugin is unsigned or missing marketplace metadata")]

View on GitHub (pinned to 8d4639e25a)