Pumpkin-MC/Pumpkin · error · LicenseError

Plugin-utils has not been initialized (call…

Error message

Plugin-utils has not been initialized (call pumpkin_plugin_utils::init(context) first)

What it means

LicenseError::NotInitialized means the plugin called a license API before pumpkin_plugin_utils::init(context) ran, so the LicenseManager has no plugin context to operate with. It is a pure ordering bug in the plugin's startup sequence, not an environmental failure.

Solutions

  1. Call pumpkin_plugin_utils::init(context) before any license API usage, ideally first in the plugin's load/enable hook.
  2. Move license verification out of the constructor into a post-init lifecycle callback.
  3. Ensure init's Result is checked — a failed init leaves the manager unusable.
  4. Verify the same context/plugin instance used for init is the one performing checks.
  5. If init runs in async setup, await/complete it before license calls.

Example fix

// before
impl Plugin for MyPlugin {
    fn new() -> Self { Self { license: verify_license() } } // too early
}
// after
impl Plugin for MyPlugin {
    fn on_enable(&mut self, ctx: &Context) -> Result<()> {
        pumpkin_plugin_utils::init(ctx)?;
        self.license = verify_license()?;
        Ok(())
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Guard: only call license APIs after explicit init
static INITED: AtomicBool = AtomicBool::new(false);
fn ensure_inited() -> Result<(), LicenseError> {
    if INITED.load(Ordering::Acquire) { Ok(()) }
    else { Err(LicenseError::NotInitialized) }
}

Type guard

fn is_not_initialized(e: &LicenseError) -> bool {
    matches!(e, LicenseError::NotInitialized)
}

Try / catch

match manager.verify() {
    Err(LicenseError::NotInitialized) => {
        tracing::error!("init before license check: pumpkin_plugin_utils::init(ctx)");
        return Err(anyhow!("plugin-utils not initialized"));
    }
    other => other.map(|_| ()),
}

Prevention

When it happens

Trigger: Calling LicenseManager methods (verify, cached lease access, etc.) on the plugin's construction or before the init(context) call completes; init skipped entirely; init called on a different plugin instance/context than the one being checked.

Common situations: Performing license checks in the plugin constructor instead of the enabled/loaded lifecycle hook; refactoring moved license code earlier in startup; multiple plugins sharing a static manager initialized by only one of them; early-return/panic in init leaving it uninitialized.

Related errors


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

Appendix: source

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

    #[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 {
        let folder = data_folder.as_ref().to_path_buf();
        Self {
            data_folder: folder,

View on GitHub (pinned to 8d4639e25a)