Pumpkin-MC/Pumpkin · error

Cannot construct BlockReceiveGameEvent from WASM

Error message

Cannot construct BlockReceiveGameEvent from WASM

What it means

A deliberate panic in from_wasm_event for BlockReceiveGameEvent. If the WASM Event variant delivered to the converter is BlockReceiveGameEvent itself, the code panics because this event type cannot be reconstructed from the WASM side — it flows only from host to plugin.

Solutions

  1. Do not forward BlockReceiveGameEvent back into from_wasm_event; cancel/consume it host-side instead.
  2. If recursion is the cause, guard the dispatch so events triggered inside a plugin callback are not re-delivered to the same plugin.
  3. Check the pumpkin-api-macros generated code to ensure the correct conversion direction is used for this event.
  4. Convert the panic into a logged error + event drop for production robustness.

Example fix

// before
match event {
    Event::BlockReceiveGameEvent(_) => {
        panic!("Cannot construct BlockReceiveGameEvent from WASM")
    }
    _ => panic!("unexpected event type"),
}
// after
match event {
    Event::BlockReceiveGameEvent(_) => {
        log::warn!("BlockReceiveGameEvent cannot be constructed from WASM; dropping");
        return Err(ConversionError::UnsupportedDirection);
    }
    other => Err(ConversionError::UnexpectedVariant(other.name())),
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Only call from_wasm_event for plugin-to-host event types
assert!(!is_host_to_plugin_only::<BlockReceiveGameEvent>(), "BlockReceiveGameEvent cannot be constructed from WASM");

Type guard

fn can_construct_from_wasm<E: ToFromWasmEvent>(event: &Event) -> bool {
    matches!(event, Event::BlockReceiveGameEvent(_)) == false || E::HAS_FROM_WASM
}

Try / catch

let result = std::panic::catch_unwind(AssertUnwindSafe(|| convert_from_wasm(event, state)));
if result.is_err() {
    log::warn!("one-way event cannot be constructed from WASM; ignored");
}

Prevention

When it happens

Trigger: The generated plugin dispatch calls from_wasm_event with an Event::BlockReceiveGameEvent payload, meaning an event that should be one-way host->plugin was routed back through the WASM-to-native conversion.

Common situations: A macro-generated handler wrongly re-emits the event; plugin code triggers the same event recursively; refactoring swapped to_wasm_event/from_wasm_event usage.

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/36cb017f1a97372f. Report an issue: GitHub.

Appendix: source

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

            source_entity_id: self
                .source_entity
                .as_ref()
                .map(|e| e.get_entity().entity_id),
            cancelled: self.cancelled,
        })
    }

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

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

impl ToFromWasmEvent for BlockShearEntityEvent {
    fn to_wasm_event(&self, state: &mut PluginHostState) -> Event {
        let target_world = state
            .add_world(self.world.clone())
            .expect("failed to add world resource");
        let item = state
            .add_item_stack(Arc::new(Mutex::new(self.item.clone())))
            .expect("failed to add item stack resource");
        Event::BlockShearEntityEvent(BlockShearEntityEventData {
            block_pos: to_wasm_block_position(self.block_pos),
            target_world,
            target_entity_id: self.target.get_entity().entity_id,

View on GitHub (pinned to 8d4639e25a)