Pumpkin-MC/Pumpkin · error
PLUGIN must be initialized with register_plugin before use
Error message
PLUGIN must be initialized with register_plugin before use
What it means
`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.
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()`.
Example fix
// before
static STATE: LazyLock<String> = LazyLock::new(|| plugin().name().to_string()); // panics at load
// after
fn state() -> String {
plugin().name().to_string() // called from within event handlers
} Defensive patterns
Strategy: try-catch
Validate before calling
// Guard before calling helpers that use plugin():
fn plugin_available() -> bool { PLUGIN.get().is_some() } // or defer all access to post-registration hooks Type guard
fn try_plugin() -> Option<&'static dyn Plugin> { PLUGIN.get().map(Box::as_ref) } Try / catch
// Rust panic is not catchable idiomatically; use the safe accessor:
if let Some(p) = try_plugin() { /* use p */ } else { /* defer until registered */ } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- failed to add player resource
- failed to add player resource
- unexpected event type
- valid enchantment ID
- invalid text-component resource handle
AI-assisted analysis of Pumpkin-MC/Pumpkin@8d4639e25a (2026-09-09).
Data as JSON: /api/errors/8a6016037fd0b225.
Report an issue: GitHub.
Appendix: source
Thrown at crates/pumpkin-plugin-api/src/lib.rs:494
#[doc(hidden)]
pub fn register_plugin(build_plugin: fn() -> Box<dyn Plugin>) {
let _ = tracing::subscriber::set_global_default(WitSubscriber::new());
assert!(
PLUGIN.set(build_plugin()).is_ok(),
"register_plugin must only be called once"
);
}
/// Returns a reference to the currently loaded plugin instance.
///
/// # Panics
/// If called before [`register_plugin`] has initialized `PLUGIN`.
fn plugin() -> &'static dyn Plugin {
#[allow(clippy::expect_used)]
PLUGIN
.get()
.map(Box::as_ref)
.expect("PLUGIN must be initialized with register_plugin before use")
}
/// The singleton plugin instance, initialised by [`register_plugin`].
static PLUGIN: OnceLock<Box<dyn Plugin>> = OnceLock::new();
/// Registers the provided type as a Pumpkin plugin.
///
/// This macro generates the WebAssembly export entry point that the server uses to
/// instantiate the plugin. The type must implement the [`Plugin`] trait.
///
/// # Example
/// ```rust,ignore
/// register_plugin!(MyPlugin);
/// ```
#[macro_export]
macro_rules! register_plugin {
($plugin_type:ty) => {
#[unsafe(export_name = "init-plugin")]View on GitHub (pinned to 8d4639e25a)