Pumpkin-MC/Pumpkin · error · LicenseError

Plugin is unsigned or missing marketplace metadata

Error message

Plugin is unsigned or missing marketplace metadata

What it means

LicenseError::UnsignedPlugin is a fieldless variant indicating the plugin carries no signature or is missing marketplace metadata entirely, so license verification cannot even identify it. Unlike MetadataMismatch (metadata present but wrong), this fires when the required marketplace/signature data is absent.

Solutions

  1. Install the plugin from the official marketplace so signed metadata is present.
  2. Rebuild with the official publishing toolchain that embeds signing/marketplace metadata.
  3. Do not repackage/rezip the plugin jar, which can drop metadata.
  4. Verify the correct plugin file is license-gated; unsigned free plugins should skip license checks.
  5. If you believe the plugin is signed, verify the jar's manifest contains the marketplace metadata keys.

Example fix

// before (manual repackage)
zip -r myplugin.jar extracted/           // metadata lost -> UnsignedPlugin
// after
mvn pumpkin:publish && install dist/myplugin-1.2.0.jar  // signed build
Defensive patterns

Strategy: validation

Validate before calling

// Verify the packaged plugin carries marketplace metadata before enabling license flow
let jar = std::fs::File::open("plugins/myplugin.jar")?;
let mut archive = zip::ZipArchive::new(jar)?;
let manifest = archive.by_name("META-INF/MANIFEST.MF")?;
let text = std::io::read_to_string(manifest)?;
if !text.contains("Marketplace-Id") {
    panic!("plugin jar lacks marketplace metadata — rebuild via official pipeline");
}

Type guard

fn is_unsigned(e: &LicenseError) -> bool {
    matches!(e, LicenseError::UnsignedPlugin)
}

Try / catch

match manager.verify() {
    Err(LicenseError::UnsignedPlugin) => {
        tracing::error!("plugin is unsigned; install official marketplace build");
        disable_paid_features();
    }
    other => other.map(|_| ()),
}

Prevention

When it happens

Trigger: Running license checks on a plugin built locally or distributed outside the marketplace without embedded signing/marketplace metadata; metadata stripped by repackaging; loading a jar whose manifest lacks the expected marketplace entries.

Common situations: Developer testing an in-development build through the paid-plugin flow; third-party mirror site download with metadata stripped; unzip/rezip of the plugin losing manifest entries; mixing up a free unsigned plugin with a license-gated one.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

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

    #[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")]
    UnsignedPlugin,
    /// Plugin has not been initialized.
    #[error(
        "Plugin-utils has not been initialized (call pumpkin_plugin_utils::init(context) first)"
    )]
    NotInitialized,
}

/// Manages license checks, cached leases, and offline grace periods.
pub struct LicenseChecker {
    data_folder: PathBuf,
    http_client: HttpClient,
}

impl LicenseChecker {
    /// Creates a new `LicenseChecker` instance for the given data folder.
    #[must_use]
    pub fn new(data_folder: impl AsRef<Path>) -> Self {

View on GitHub (pinned to 8d4639e25a)