Pumpkin-MC/Pumpkin · error
failed to add text-component resource
Error message
failed to add text-component resource
What it means
Panic raised inside ServerBroadcastEvent::to_wasm_event when the host tries to insert the broadcast's message TextComponent into the wasmtime resource table via PluginHostState::add_text_component. The underlying `resource_table.push` returned an Err, meaning the WASM component instance's resource table rejected the new resource. Because the conversion runs on the host side inside an `.expect`, any table failure aborts the whole server thread rather than surfacing a recoverable error to the plugin.
Solutions
- Audit plugin handlers for ServerBroadcastEvent and ensure they consume/release the message and sender text-component resources so the table does not grow unbounded.
- Replace the `.expect(...)` with proper error propagation (return Result and use `?`) so a failing table push surfaces as a plugin dispatch error instead of a host panic.
- Verify the plugin instance is still alive/loaded when the event fires; skip dispatch for instances currently being unloaded.
- Update wasmtime and check resource-table limits; confirm no rep/insertion bug in PluginHostState::add_text_component.
Example fix
// before
let message = state
.add_text_component(self.message.clone())
.expect("failed to add text-component resource");
// after
let message = state
.add_text_component(self.message.clone())
.map_err(|e| anyhow::anyhow!("failed to add text-component resource: {e}"))?; Defensive patterns
Strategy: fallback
Validate before calling
// host-side check before dispatch
if plugin_is_unloading(plugin_id) {
tracing::warn!("skipping broadcast dispatch to unloading plugin {plugin_id}");
return;
} Type guard
fn is_table_healthy(state: &PluginHostState) -> bool {
// table push only fails on exhausted/invalid tables; probe cheaply
state.resource_table.iter().count() < RESOURCE_TABLE_SOFT_LIMIT
} Try / catch
// replace expect with recoverable dispatch
match state.add_text_component(self.message.clone()) {
Ok(msg) => { /* build event */ }
Err(e) => {
tracing::error!("broadcast dispatch failed: {e}");
return Err(e.into());
}
} Prevention
- Always consume or drop text-component resources in plugin event handlers; never leak them.
- Prefer `?`/Result propagation over `.expect` in host event conversion code.
- Skip event dispatch for plugin instances mid-shutdown.
- Monitor resource table size per plugin instance in production.
When it happens
Trigger: Calling to_wasm_event for a ServerBroadcastEvent while the wasmtime component resource table push fails — typically when the table is full (resource limit exhausted), the table belongs to a torn-down/plugin instance being unloaded, or a stored resource rep collided/was invalid. Triggered whenever a server broadcast event is dispatched to a WASM plugin and state.resource_table.push(TextComponentResource) errors.
Common situations: Dispatching chat/broadcast events to many WASM plugins that leak text-component resources (never consuming/releasing them), exhausting the per-instance resource table; firing the event during plugin shutdown while the instance table is already invalidated; host bugs or wasmtime resource-limit configuration issues.
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 world resource
- Cannot construct BlockFertilizeEvent from WASM
- unexpected event type
- Cannot construct BlockMultiPlaceEvent from WASM
AI-assisted analysis of Pumpkin-MC/Pumpkin@8d4639e25a (2026-09-09).
Data as JSON: /api/errors/03d43e195504a189.
Report an issue: GitHub.
Appendix: source
Thrown at crates/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/events/server.rs:151
})
}
fn from_wasm_event(event: Event, _state: &mut PluginHostState) -> Self {
match event {
Event::ServerCommandEvent(data) => Self {
command: data.command,
cancelled: data.cancelled,
},
_ => panic!("unexpected event type"),
}
}
}
impl ToFromWasmEvent for ServerBroadcastEvent {
fn to_wasm_event(&self, state: &mut PluginHostState) -> Event {
let message = state
.add_text_component(self.message.clone())
.expect("failed to add text-component resource");
let sender = state
.add_text_component(self.sender.clone())
.expect("failed to add text-component resource");
Event::ServerBroadcastEvent(ServerBroadcastEventData {
message,
sender,
cancelled: self.cancelled,
})
}
fn from_wasm_event(event: Event, state: &mut PluginHostState) -> Self {
match event {
Event::ServerBroadcastEvent(data) => Self {
message: consume_text_component(state, &data.message),
sender: consume_text_component(state, &data.sender),
cancelled: data.cancelled,
},View on GitHub (pinned to 8d4639e25a)