Pumpkin-MC/Pumpkin · error

failed to add player resource

Error message

failed to add player resource

What it means

When converting a PacketReceivedEvent into its WIT representation, to_wasm_event calls state.add_player(...) to expose the player as a WASM resource. If add_player returns an Err (e.g. resource table limits exceeded or an internal store failure), .expect panics with 'failed to add player resource'. The plugin host cannot represent the player in the WASM resource table, so event delivery is aborted.

Solutions

  1. Check PluginHostState's resource table for leaks (players never removed) that exhaust table capacity.
  2. Ensure player resources are removed/reclaimed on player disconnect and plugin unload.
  3. Upgrade wasmtime if the failure stems from a known resource-table bug.
  4. Replace .expect with graceful error handling that skips plugin delivery instead of panicking the host.

Example fix

// before
let player_res = state.add_player(self.player.clone())
    .expect("failed to add player resource");
// after
let player_res = state.add_player(self.player.clone())
    .map_err(|e| { log::error!("add_player failed: {e}"); e })?;
Defensive patterns

Strategy: try-catch

Validate before calling

// before dispatching the event to plugins
if state.resource_table_size() >= state.resource_table_limit() {
    skip_plugin_delivery();
}

Type guard

fn player_resource_addable(state: &PluginHostState, player: &Arc<Player>) -> bool {
    !state.contains_player(player) && state.resource_table_size() < state.resource_table_limit()
}

Try / catch

match state.add_player(self.player.clone()) {
    Ok(res) => res,
    Err(e) => { log::error!("add_player failed: {e}"); return; }
}

Prevention

When it happens

Trigger: A packet is received from a player and the event is forwarded to a WASM plugin while state.add_player fails — typically due to WASM resource-table exhaustion, a duplicate/invalid player handle, or a corrupted PluginHostState.

Common situations: Servers with very many plugins/players hitting wasmtime resource-table limits; a plugin holding stale player resources causing table collisions; internal state bugs after plugin reload.

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


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

Appendix: source

Thrown at crates/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/events/server.rs:33

        },
    },
    server::{
        list_ping::ServerListPingEvent,
        map_initialize::MapInitializeEvent,
        packet::{PacketReceivedEvent, PacketSentEvent},
        server_broadcast::ServerBroadcastEvent,
        server_command::ServerCommandEvent,
        server_load::{LoadType, ServerLoadEvent},
        server_tick_end::ServerTickEndEvent,
        server_tick_start::ServerTickStartEvent,
    },
};

impl ToFromWasmEvent for PacketReceivedEvent {
    fn to_wasm_event(&self, state: &mut PluginHostState) -> Event {
        let player_res = state
            .add_player(self.player.clone())
            .expect("failed to add player resource");

        let packet = match self.player.client.as_ref() {
            ClientPlatform::Java(client) => {
                let version = client.version.load();
                generated_packets::deserialize_java_serverbound_packet(
                    self.packet_id,
                    &self.payload,
                    version,
                )
                .map_or(ServerboundPacket::Unknown, ServerboundPacket::Java)
            }
            ClientPlatform::Bedrock(_) => {
                generated_packets::deserialize_bedrock_serverbound_packet(
                    self.packet_id,
                    &self.payload,
                )
                .map_or(ServerboundPacket::Unknown, ServerboundPacket::Bedrock)
            }

View on GitHub (pinned to 8d4639e25a)