Pumpkin-MC/Pumpkin · error

Cannot construct CampfireStartEvent from WASM

Error message

Cannot construct CampfireStartEvent from WASM

What it means

This is an intentional `panic!` in `CampfireStartEvent::from_wasm_event`. Converting a campfire-start event FROM the WASM side back into a native event is not a supported direction — the host produces this event natively and plugins only receive it, never send it. If this arm is reached, the dispatch is trying to do something the API forbids, so the library aborts loudly.

Solutions

  1. Do not emit `CampfireStartEvent` from plugin code — it is host-to-plugin only; emit only plugin-originated events the WIT allows
  2. Rebuild the plugin against the matching pumpkin-api version to get correct event direction metadata
  3. Check custom macro usage that generates event dispatch and ensure read-only events are excluded from send paths
  4. File a bug against pumpkin-api-macros if generated code routes this event backwards

Example fix

// before (plugin code)
let ev = Event::CampfireStartEvent(data);
host.send_event(ev); // panics host-side
// after
// only respond to CampfireStartEvent in the handler; never construct/send it
fn on_campfire_start(&self, ev: CampfireStartEvent) { /* react only */ }
Defensive patterns

Strategy: type-guard

Validate before calling

// plugin side: never send host-originated events
const SENDING_ALLOWED: bool = false; // CampfireStartEvent is host->plugin only
if SENDING_ALLOWED { host.send_event(event); }

Type guard

fn is_plugin_originated(event: &Event) -> bool {
    !matches!(event, Event::CampfireStartEvent(_))
}

Try / catch

// host bridge: refuse reverse conversion gracefully instead of panicking
if matches!(event, Event::CampfireStartEvent(_)) {
    log::error!("plugin attempted to send host-only CampfireStartEvent; rejected");
    return;
}

Prevention

When it happens

Trigger: A WASM plugin (or a macro-generated `plugin_method` bridge) attempts to raise/return `Event::CampfireStartEvent` back to the host, invoking `CampfireStartEvent::from_wasm_event`.

Common situations: Plugin author calls a send/raise API with a host-originated event type; macro bug mapping event direction incorrectly; plugin built against a different API version where directionality differed.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

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

            target_world,
            item,
            slot: self.slot,
            cooking_time: self.cooking_time,
            cancelled: self.cancelled,
        })
    }

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

    fn from_wasm_event(event: Event, _state: &mut PluginHostState) -> Self {
        match event {
            Event::CampfireStartEvent(_) => panic!("Cannot construct CampfireStartEvent from WASM"),
            _ => panic!("unexpected event type"),
        }
    }
}

impl ToFromWasmEvent for CauldronLevelChangeEvent {
    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::CauldronLevelChangeEvent(CauldronLevelChangeEventData {
            block_pos: to_wasm_block_position(self.block_pos),
            target_world,
            old_level: self.old_level,
            new_level: self.new_level,
            reason: format!("{:?}", self.reason),
            entity_id: self.entity.as_ref().map(|e| e.get_entity().entity_id),
            cancelled: self.cancelled,

View on GitHub (pinned to 8d4639e25a)