Pumpkin-MC/Pumpkin · error

failed to add world resource

Error message

failed to add world resource

What it means

This `.expect("failed to add world resource")` fires in CreatureSpawnEvent's `to_wasm_event` when `state.add_world(self.world.clone())` fails to register the event's world as a host-side resource for the plugin. `add_world` returning None/Err means the plugin's resource table could not accept the world handle, so the event cannot be exported to WASM and the host panics instead of sending a broken event.

Solutions

  1. Check whether the plugin is still loaded/active when this event fires; stop dispatching events to plugins mid-teardown
  2. Inspect add_world in wasm_host to see what causes it to fail and add a graceful skip (drop the event for that plugin) instead of expect
  3. Recreate the plugin host state on reload so resource tables are consistent
  4. Update the WASM runtime or raise resource limits if the table is exhausted

Example fix

// before
let target_world = state
    .add_world(self.world.clone())
    .expect("failed to add world resource");
// after: skip delivery instead of crashing the server
let Some(target_world) = state.add_world(self.world.clone()) else {
    return Event::NoOp; // or log and skip this plugin
};
Defensive patterns

Strategy: fallback

Validate before calling

// before conversion, ensure the plugin host state can hold resources
if state.is_torn_down() || state.resource_slots_remaining() == 0 {
    return Event::NoOp; // skip this plugin safely
}

Type guard

fn can_deliver(state: &PluginHostState, world: &World) -> bool {
    !state.is_torn_down() && state.can_add_world(world)
}

Try / catch

// replace expect with graceful degradation
let target_world = match state.add_world(self.world.clone()) {
    Some(w) => w,
    None => { log::warn!("plugin state unavailable; skipping event"); return Event::NoOp; }
};

Prevention

When it happens

Trigger: `PluginHostState.add_world` fails while converting a CreatureSpawnEvent for delivery to a WASM plugin — typically when the plugin instance's resource table is exhausted, already torn down, or the state handle belongs to a different plugin instance than the event pipeline assumes.

Common situations: Plugin being unloaded/disabled while events are still being dispatched to it; resource-table limits in the WASM runtime; host state created fresh per event batch but shared world Arc assumptions broken after a 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/2dffa86e72b69a05. Report an issue: GitHub.

Appendix: source

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

    fn from_wasm_event(event: Event, _state: &mut PluginHostState) -> Self {
        match event {
            Event::EntityTransformEvent(data) => Self {
                entity_id: data.entity_id,
                new_entity_id: data.new_entity_id,
                transform_reason: data.transform_reason,
                cancelled: data.cancelled,
            },
            _ => panic!("unexpected event type"),
        }
    }
}

impl ToFromWasmEvent for CreatureSpawnEvent {
    fn to_wasm_event(&self, state: &mut PluginHostState) -> Event {
        let target_world = state
            .add_world(self.world.clone())
            .expect("failed to add world resource");
        Event::CreatureSpawnEvent(CreatureSpawnEventData {
            entity_id: self.entity_id,
            entity_type: self.entity_type.clone(),
            position: to_wasm_position(self.position),
            target_world,
            spawn_reason: self.spawn_reason.clone(),
            cancelled: self.cancelled,
        })
    }

    fn apply_wasm_event(&mut self, event: Event, state: &mut PluginHostState) {
        cleanup_event(&event, state);
        if let Event::CreatureSpawnEvent(data) = event {
            self.cancelled = data.cancelled;
        }
    }

    fn from_wasm_event(event: Event, state: &mut PluginHostState) -> Self {

View on GitHub (pinned to 8d4639e25a)