Pumpkin-MC/Pumpkin · error
failed to add world resource
Error message
failed to add world resource
What it means
SpawnChangeEvent::to_wasm_event calls PluginHostState::add_world, which pushes a WorldResource into the wasmtime component resource table, and unwraps the result with expect(). The only failure path is the wasmtime ResourceTable push failing (e.g. the table's resource limit is exhausted or its internal store is corrupt), so this panic means the plugin host could not register a handle for the event's world.
Solutions
- Audit plugin event handling so world/chunk resources pushed into the table are consumed and dropped via the WIT resource-drop path, preventing table exhaustion
- Restart the affected plugin instance (recreate PluginHostState) to get a fresh resource table
- Update wasmtime / pumpkin to a version with resource-limit fixes, or raise the component resource limits in the wasmtime store configuration
- Check server logs for earlier table/store errors indicating a corrupted PluginHostState
Example fix
// before
let world = state
.add_world(self.world.clone())
.expect("failed to add world resource");
// after
let world = state.add_world(self.world.clone()).map_err(|e| {
log::error!("failed to add world resource: {e}");
e
})?; Defensive patterns
Strategy: try-catch
Validate before calling
// before dispatching events to plugins, confirm the host state is usable
fn can_push_resources(state: &PluginHostState) -> bool {
// wasmtime ResourceTable grows dynamically; failure indicates store corruption
!state.is_poisoned()
} Type guard
fn is_valid_wasm_host_state(state: &PluginHostState) -> bool {
!state.is_poisoned()
} Try / catch
// host side: never expect(); convert to Result and quarantine the plugin
match state.add_world(world.clone()) {
Ok(res) => /* continue building event */,
Err(e) => {
log::error!("wasm host resource push failed: {e}");
disable_plugin(instance_id);
}
} Prevention
- Always drop WIT world/chunk resources from plugin event handlers so table entries are reclaimed
- Monitor resource-table growth for long-running servers
- Replace expect() in host event conversion with Result propagation
- Restart plugin instances periodically or on resource-limit warnings
When it happens
Trigger: A spawn-position-change event is being converted to a WIT event for a plugin while PluginHostState.resource_table cannot accept a new WorldResource entry — wasmtime's resource table is at capacity (leaked world/chunk resources never consumed) or the table is in a broken state.
Common situations: Long-running servers with many plugins where world resources are pushed per event but plugin instances leak them until the table's rep limit is hit; a wasmtime store/table that failed mid-lifetime; hosting an unusually large number of simultaneous plugin instances sharing one state.
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
- failed to add player resource
- failed to add player resource
- failed to add world resource
- 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/83b4ac1b2e7c9624.
Report an issue: GitHub.
Appendix: source
Thrown at crates/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/events/world.rs:28
},
pumpkin::plugin::event::{
ChunkLoadEventData, ChunkSaveEventData, ChunkSendEventData, Event,
SpawnChangeEventData, ThunderChangeEventData, WeatherChangeEventData,
WorldLoadEventData, WorldUnloadEventData,
},
},
},
world::{
chunk_load::ChunkLoad, chunk_save::ChunkSave, chunk_send::ChunkSend,
spawn_change::SpawnChangeEvent,
},
};
impl ToFromWasmEvent for SpawnChangeEvent {
fn to_wasm_event(&self, state: &mut PluginHostState) -> Event {
let world = state
.add_world(self.world.clone())
.expect("failed to add world resource");
Event::SpawnChangeEvent(SpawnChangeEventData {
target_world: world,
previous_position: to_wasm_block_position(self.previous_position),
previous_yaw: self.previous_yaw,
previous_pitch: self.previous_pitch,
new_position: to_wasm_block_position(self.new_position),
new_yaw: self.new_yaw,
new_pitch: self.new_pitch,
})
}
fn from_wasm_event(event: Event, state: &mut PluginHostState) -> Self {
match event {
Event::SpawnChangeEvent(data) => Self {
world: consume_world(state, &data.target_world),
previous_position: from_wasm_block_position(data.previous_position),
previous_yaw: data.previous_yaw,View on GitHub (pinned to 8d4639e25a)