{"record":{"id":"2dffa86e72b69a05","repo":"Pumpkin-MC/Pumpkin","slug":"failed-to-add-world-resource-2dffa8","errorCode":null,"errorMessage":"failed to add world resource","messagePattern":"failed to add world resource","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/events/entity.rs","lineNumber":648,"sourceCode":"\n    fn from_wasm_event(event: Event, _state: &mut PluginHostState) -> Self {\n        match event {\n            Event::EntityTransformEvent(data) => Self {\n                entity_id: data.entity_id,\n                new_entity_id: data.new_entity_id,\n                transform_reason: data.transform_reason,\n                cancelled: data.cancelled,\n            },\n            _ => panic!(\"unexpected event type\"),\n        }\n    }\n}\n\nimpl ToFromWasmEvent for CreatureSpawnEvent {\n    fn to_wasm_event(&self, state: &mut PluginHostState) -> Event {\n        let target_world = state\n            .add_world(self.world.clone())\n            .expect(\"failed to add world resource\");\n        Event::CreatureSpawnEvent(CreatureSpawnEventData {\n            entity_id: self.entity_id,\n            entity_type: self.entity_type.clone(),\n            position: to_wasm_position(self.position),\n            target_world,\n            spawn_reason: self.spawn_reason.clone(),\n            cancelled: self.cancelled,\n        })\n    }\n\n    fn apply_wasm_event(&mut self, event: Event, state: &mut PluginHostState) {\n        cleanup_event(&event, state);\n        if let Event::CreatureSpawnEvent(data) = event {\n            self.cancelled = data.cancelled;\n        }\n    }\n\n    fn from_wasm_event(event: Event, state: &mut PluginHostState) -> Self {","sourceCodeStart":630,"sourceCodeEnd":666,"githubUrl":"https://github.com/Pumpkin-MC/Pumpkin/blob/8d4639e25a57c15e47448ec327c780d41bbf2356/crates/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/events/entity.rs#L630-L666","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","solutions":["Check whether the plugin is still loaded/active when this event fires; stop dispatching events to plugins mid-teardown","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","Recreate the plugin host state on reload so resource tables are consistent","Update the WASM runtime or raise resource limits if the table is exhausted"],"exampleFix":"// before\nlet target_world = state\n    .add_world(self.world.clone())\n    .expect(\"failed to add world resource\");\n// after: skip delivery instead of crashing the server\nlet Some(target_world) = state.add_world(self.world.clone()) else {\n    return Event::NoOp; // or log and skip this plugin\n};","handlingStrategy":"fallback","validationCode":"// before conversion, ensure the plugin host state can hold resources\nif state.is_torn_down() || state.resource_slots_remaining() == 0 {\n    return Event::NoOp; // skip this plugin safely\n}","typeGuard":"fn can_deliver(state: &PluginHostState, world: &World) -> bool {\n    !state.is_torn_down() && state.can_add_world(world)\n}","tryCatchPattern":"// replace expect with graceful degradation\nlet target_world = match state.add_world(self.world.clone()) {\n    Some(w) => w,\n    None => { log::warn!(\"plugin state unavailable; skipping event\"); return Event::NoOp; }\n};","preventionTips":["Stop dispatching events to plugins during teardown/reload","Recreate PluginHostState when a plugin reloads","Monitor WASM resource-table usage for exhaustion","Avoid .expect in event hot paths; prefer skip-and-log"],"tags":["rust","wasm","resource-table","plugin-lifecycle","panic"],"backgroundTag":"internal-invariant-violation","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"}