{"record":{"id":"55dc4948a0c79aaa","repo":"Pumpkin-MC/Pumpkin","slug":"plugin-utils-has-not-been-initialized-call-pumpki","errorCode":null,"errorMessage":"Plugin-utils has not been initialized (call pumpkin_plugin_utils::init(context) first)","messagePattern":"Plugin-utils has not been initialized \\(call pumpkin_plugin_utils::init\\(context\\) first\\)","errorType":"exception","errorClass":"LicenseError","httpStatus":null,"severity":"error","filePath":"crates/pumpkin-plugin-utils/src/license.rs","lineNumber":39,"sourceCode":"    #[error(\"License metadata mismatch: {0}\")]\n    MetadataMismatch(String),\n    /// License revoked or refunded by marketplace.\n    #[error(\"License was revoked or refunded: {0}\")]\n    Revoked(String),\n    /// License is expired.\n    #[error(\"License has expired on {0}\")]\n    Expired(String),\n    /// I/O error reading/writing license cache.\n    #[error(\"I/O error with license storage: {0}\")]\n    Io(#[from] std::io::Error),\n    /// JSON serialization error.\n    #[error(\"JSON serialization error: {0}\")]\n    Json(#[from] serde_json::Error),\n    /// Plugin is unsigned or missing marketplace metadata.\n    #[error(\"Plugin is unsigned or missing marketplace metadata\")]\n    UnsignedPlugin,\n    /// Plugin has not been initialized.\n    #[error(\n        \"Plugin-utils has not been initialized (call pumpkin_plugin_utils::init(context) first)\"\n    )]\n    NotInitialized,\n}\n\n/// Manages license checks, cached leases, and offline grace periods.\npub struct LicenseChecker {\n    data_folder: PathBuf,\n    http_client: HttpClient,\n}\n\nimpl LicenseChecker {\n    /// Creates a new `LicenseChecker` instance for the given data folder.\n    #[must_use]\n    pub fn new(data_folder: impl AsRef<Path>) -> Self {\n        let folder = data_folder.as_ref().to_path_buf();\n        Self {\n            data_folder: folder,","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/Pumpkin-MC/Pumpkin/blob/8d4639e25a57c15e47448ec327c780d41bbf2356/crates/pumpkin-plugin-utils/src/license.rs#L21-L57","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Call pumpkin_plugin_utils::init(context) before any license API usage, ideally first in the plugin's load/enable hook.","Move license verification out of the constructor into a post-init lifecycle callback.","Ensure init's Result is checked — a failed init leaves the manager unusable.","Verify the same context/plugin instance used for init is the one performing checks.","If init runs in async setup, await/complete it before license calls."],"exampleFix":"// before\nimpl Plugin for MyPlugin {\n    fn new() -> Self { Self { license: verify_license() } } // too early\n}\n// after\nimpl Plugin for MyPlugin {\n    fn on_enable(&mut self, ctx: &Context) -> Result<()> {\n        pumpkin_plugin_utils::init(ctx)?;\n        self.license = verify_license()?;\n        Ok(())\n    }\n}","handlingStrategy":"try-catch","validationCode":"// Guard: only call license APIs after explicit init\nstatic INITED: AtomicBool = AtomicBool::new(false);\nfn ensure_inited() -> Result<(), LicenseError> {\n    if INITED.load(Ordering::Acquire) { Ok(()) }\n    else { Err(LicenseError::NotInitialized) }\n}","typeGuard":"fn is_not_initialized(e: &LicenseError) -> bool {\n    matches!(e, LicenseError::NotInitialized)\n}","tryCatchPattern":"match manager.verify() {\n    Err(LicenseError::NotInitialized) => {\n        tracing::error!(\"init before license check: pumpkin_plugin_utils::init(ctx)\");\n        return Err(anyhow!(\"plugin-utils not initialized\"));\n    }\n    other => other.map(|_| ()),\n}","preventionTips":["Call pumpkin_plugin_utils::init(context) as the first line of the enable hook.","Never run license checks in the plugin constructor.","Always unwrap/propagate init's Result.","Add a startup-order integration test."],"tags":["initialization","lifecycle","license","rust"],"backgroundTag":"module-init-failed","analyzedSha":"8d4639e25a57c15e47448ec327c780d41bbf2356","analyzedAt":"2026-09-09T15:32:22.916Z","contentChangedAt":"2026-09-09T15:32:22.916Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}