Pumpkin-MC/Pumpkin · error
failed to add player resource
Error message
failed to add player resource
What it means
In `ToFromWasmEvent::to_wasm_event` for `PlayerRecipeBookClickEvent`, `state.add_player(self.player.clone()).expect("failed to add player resource")` panics when the host cannot register the player resource in PluginHostState. add_player returns Option/Result and the expect treats None as unrecoverable: the outgoing WASM event requires a valid player resource handle.
Solutions
- Check player existence before building the event and skip/consume the event if the player is gone.
- Make add_player failure a logged skip rather than a panic (match on None/Err and drop the event).
- Clear queued events for a player during disconnect handling so stale events never convert.
- Fix any code path that clears PluginHostState while events referencing players are still pending.
Example fix
// before
let player = state
.add_player(self.player.clone())
.expect("failed to add player resource");
// after
let Some(player) = state.add_player(self.player.clone()) else {
tracing::warn!("skipping PlayerRecipeBookClickEvent: player resource unavailable");
return Event::NoOp; // or skip emission
}; Defensive patterns
Strategy: validation
Validate before calling
if !state.contains_player(&self.player) {
tracing::warn!("player gone; skipping recipe-book-click event");
return;
} Type guard
fn player_available(state: &PluginHostState, p: &PlayerRef) -> bool { state.contains_player(p) } Try / catch
match state.add_player(self.player.clone()) {
Ok(player) => build_event(player),
Err(e) => tracing::warn!("failed to add player resource: {e:?}"),
} Prevention
- Remove queued events for players at disconnect
- Never convert events after PluginHostState teardown
- Log add_player failures instead of expecting
- Test plugin event pipeline under player connect/disconnect churn
When it happens
Trigger: add_player fails to insert/lookup the player — e.g. the player entity no longer exists in host state (left the server mid-event), the resource table is at capacity, or the player key stored on the Rust-side event is stale.
Common situations: Player disconnects between event capture and WASM conversion; a plugin race where events queue for players removed from PluginHostState; host bugs clearing the resource table before pending events flush.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- unexpected event type
- Cannot construct CampfireStartEvent from WASM
- Cannot construct CauldronLevelChangeEvent from WASM
- failed to add player resource
- failed to add world resource
AI-assisted analysis of Pumpkin-MC/Pumpkin@8d4639e25a (2026-09-09).
Data as JSON: /api/errors/5bd7a0ed9ce17b72.
Report an issue: GitHub.
Appendix: source
Thrown at crates/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/events/player.rs:2369
}
fn from_wasm_event(event: Event, state: &mut PluginHostState) -> Self {
match event {
Event::PlayerPickupArrowEvent(data) => Self {
player: consume_player(state, &data.player),
arrow_id: data.arrow_id,
cancelled: data.cancelled,
},
_ => panic!("unexpected event type"),
}
}
}
impl ToFromWasmEvent for PlayerRecipeBookClickEvent {
fn to_wasm_event(&self, state: &mut PluginHostState) -> Event {
let player = state
.add_player(self.player.clone())
.expect("failed to add player resource");
Event::PlayerRecipeBookClickEvent(PlayerRecipeBookClickEventData {
player,
recipe_id: self.recipe_id.clone(),
make_all: self.make_all,
cancelled: self.cancelled,
})
}
fn apply_wasm_event(&mut self, event: Event, state: &mut PluginHostState) {
cleanup_event(&event, state);
if let Event::PlayerRecipeBookClickEvent(data) = event {
self.cancelled = data.cancelled;
self.recipe_id = data.recipe_id;
self.make_all = data.make_all;
}
}
fn from_wasm_event(event: Event, state: &mut PluginHostState) -> Self {View on GitHub (pinned to 8d4639e25a)