{"record":{"id":"8a6016037fd0b225","repo":"Pumpkin-MC/Pumpkin","slug":"plugin-must-be-initialized-with-register-plugin-be","errorCode":null,"errorMessage":"PLUGIN must be initialized with register_plugin before use","messagePattern":"PLUGIN must be initialized with register_plugin before use","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/pumpkin-plugin-api/src/lib.rs","lineNumber":494,"sourceCode":"#[doc(hidden)]\npub fn register_plugin(build_plugin: fn() -> Box<dyn Plugin>) {\n    let _ = tracing::subscriber::set_global_default(WitSubscriber::new());\n    assert!(\n        PLUGIN.set(build_plugin()).is_ok(),\n        \"register_plugin must only be called once\"\n    );\n}\n\n/// Returns a reference to the currently loaded plugin instance.\n///\n/// # Panics\n/// If called before [`register_plugin`] has initialized `PLUGIN`.\nfn plugin() -> &'static dyn Plugin {\n    #[allow(clippy::expect_used)]\n    PLUGIN\n        .get()\n        .map(Box::as_ref)\n        .expect(\"PLUGIN must be initialized with register_plugin before use\")\n}\n\n/// The singleton plugin instance, initialised by [`register_plugin`].\nstatic PLUGIN: OnceLock<Box<dyn Plugin>> = OnceLock::new();\n\n/// Registers the provided type as a Pumpkin plugin.\n///\n/// This macro generates the WebAssembly export entry point that the server uses to\n/// instantiate the plugin. The type must implement the [`Plugin`] trait.\n///\n/// # Example\n/// ```rust,ignore\n/// register_plugin!(MyPlugin);\n/// ```\n#[macro_export]\nmacro_rules! register_plugin {\n    ($plugin_type:ty) => {\n        #[unsafe(export_name = \"init-plugin\")]","sourceCodeStart":476,"sourceCodeEnd":512,"githubUrl":"https://github.com/Pumpkin-MC/Pumpkin/blob/8d4639e25a57c15e47448ec327c780d41bbf2356/crates/pumpkin-plugin-api/src/lib.rs#L476-L512","documentation":"`plugin()` returns the global singleton plugin instance stored in a `OnceLock`, which is only populated by `register_plugin`. If `plugin()` is called before registration, `OnceLock::get()` returns `None` and the `.expect` panics with this message. It protects against using plugin services (logging, config access) before the runtime has finished constructing the plugin.","triggerScenarios":"Calling `pumpkin_plugin_api::plugin()` (directly or via helpers like logging/config accessors) from a `#[no_setup]`/static initializer, a `static`/`lazy` evaluated at load time, or any code path executed before the host calls the plugin's setup/register entry point.","commonSituations":"Logging during DLL/SO load (`static` initializers or `ctor`-style hooks); spawning a thread in a static initializer that calls `plugin()`; using a `OnceLock`/`LazyLock` of derived state that reads the plugin at module init; calling plugin helpers from `extern \"C\"` callbacks invoked before registration.","solutions":["Move the `plugin()` call into plugin methods that only run after registration (event handlers, `on_load`).","Ensure `register_plugin!` (or `register_plugin`) runs in the crate's designated entry point exactly as the plugin template shows.","Replace eager static initialization with lazy per-call access inside handlers.","If you need pre-registration state, capture it in your own globals rather than via `plugin()`."],"exampleFix":"// before\nstatic STATE: LazyLock<String> = LazyLock::new(|| plugin().name().to_string()); // panics at load\n// after\nfn state() -> String {\n    plugin().name().to_string() // called from within event handlers\n}","handlingStrategy":"try-catch","validationCode":"// Guard before calling helpers that use plugin():\nfn plugin_available() -> bool { PLUGIN.get().is_some() } // or defer all access to post-registration hooks","typeGuard":"fn try_plugin() -> Option<&'static dyn Plugin> { PLUGIN.get().map(Box::as_ref) }","tryCatchPattern":"// Rust panic is not catchable idiomatically; use the safe accessor:\nif let Some(p) = try_plugin() { /* use p */ } else { /* defer until registered */ }","preventionTips":["Call plugin() only from event handlers or on_load, never in static initializers.","Ensure register_plugin! runs in the crate entry point per the plugin template.","Avoid LazyLock/global state that eagerly reads the plugin at load time.","Never spawn threads in static constructors that touch plugin services."],"tags":["panic","initialization-order","plugin-api","singleton"],"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"}