Cruxial0 opened issue #10573:
I am in the process of writing a plugin system in Rust using wasmtime. I use WIT to define a contract. In the contract I have an interface defined as:
interface events { on-permissions-granted: func(); on-plugin-loaded: func(); }The idea is to call these event functions from my host, then let plugins do whatever they need to do. Strangely enough, it works with a single function, but when I add a second function I run into the error:
wasm trap: cannot enter component instance. My current code is as follows:pub async fn initialize(&mut self) -> Result<(), Box<dyn std::error::Error>> { log::info!("Initializing plugin manager"); self.load_plugins()?; let mut loaded_instances = Vec::new(); for plugin in self.plugins.clone() { let instance = self.instantiate_plugin(plugin.clone()).await?; loaded_instances.push(instance); } for instance in &loaded_instances { self.push_active_plugin(instance.clone()); self.on_plugin_loaded(&instance).await?; // Check permissions let resolved = PERMISSION_MANAGER.with(|pm| { let mut manager = pm.borrow_mut(); match manager.add_plugin(instance.plugin.clone()) { Ok(state) => state == PermissionState::Granted, Err(_) => false, } }); if resolved { self.on_permissions_granted(&instance).await?; } } self.plugins = loaded_instances.iter().map(|i| i.plugin.clone()).collect(); Ok(()) }trait PluginEvents { async fn on_plugin_loaded(&mut self, instance: &PluginInstance) -> Result<(), Box<dyn std::error::Error>>; async fn on_permissions_granted(&mut self, instance: &PluginInstance) -> Result<(), Box<dyn std::error::Error>>; } impl PluginEvents for PluginManager { async fn on_plugin_loaded(&mut self, instance: &PluginInstance) -> Result<(), Box<dyn std::error::Error>> { let load_func = get_typed_function::<(), ()>(instance, "events:on-plugin-loaded", &mut self.store)?; match load_func.call_async(&mut self.store, ()).await { Ok(_) => (), Err(e) => log::warn!("Failed to call on-plugin-loaded: {}", e), } Ok(()) } async fn on_permissions_granted(&mut self, instance: &PluginInstance) -> Result<(), Box<dyn std::error::Error>> { let perm_func = get_typed_function::<(), ()>(instance, "events:on-permissions-granted", &mut self.store)?; match perm_func.call_async(&mut self.store, ()).await { Ok(_) => (), Err(e) => log::warn!("Failed to call on-permissions-granted: {}", e), // error occurs here } Ok(()) } }(note:
get_typed_functionis my own wrapper function)I know there's been similar issues in the past, notably #8670, which I have read, but the use case seems different from mine. Is there any way to fix this issue, or is it a limitation within wasmtime?
bjorn3 commented on issue #10573:
I believe you need to call
.post_return_async()on theTypedFuncafter the.call_async()has returned and before you call into the component again.
Cruxial0 closed issue #10573:
I am in the process of writing a plugin system in Rust using wasmtime. I use WIT to define a contract. In the contract I have an interface defined as:
interface events { on-permissions-granted: func(); on-plugin-loaded: func(); }The idea is to call these event functions from my host, then let plugins do whatever they need to do. Strangely enough, it works with a single function, but when I add a second function I run into the error:
wasm trap: cannot enter component instance. My current code is as follows:pub async fn initialize(&mut self) -> Result<(), Box<dyn std::error::Error>> { log::info!("Initializing plugin manager"); self.load_plugins()?; let mut loaded_instances = Vec::new(); for plugin in self.plugins.clone() { let instance = self.instantiate_plugin(plugin.clone()).await?; loaded_instances.push(instance); } for instance in &loaded_instances { self.push_active_plugin(instance.clone()); self.on_plugin_loaded(&instance).await?; // Check permissions let resolved = PERMISSION_MANAGER.with(|pm| { let mut manager = pm.borrow_mut(); match manager.add_plugin(instance.plugin.clone()) { Ok(state) => state == PermissionState::Granted, Err(_) => false, } }); if resolved { self.on_permissions_granted(&instance).await?; } } self.plugins = loaded_instances.iter().map(|i| i.plugin.clone()).collect(); Ok(()) }trait PluginEvents { async fn on_plugin_loaded(&mut self, instance: &PluginInstance) -> Result<(), Box<dyn std::error::Error>>; async fn on_permissions_granted(&mut self, instance: &PluginInstance) -> Result<(), Box<dyn std::error::Error>>; } impl PluginEvents for PluginManager { async fn on_plugin_loaded(&mut self, instance: &PluginInstance) -> Result<(), Box<dyn std::error::Error>> { let load_func = get_typed_function::<(), ()>(instance, "events:on-plugin-loaded", &mut self.store)?; match load_func.call_async(&mut self.store, ()).await { Ok(_) => (), Err(e) => log::warn!("Failed to call on-plugin-loaded: {}", e), } Ok(()) } async fn on_permissions_granted(&mut self, instance: &PluginInstance) -> Result<(), Box<dyn std::error::Error>> { let perm_func = get_typed_function::<(), ()>(instance, "events:on-permissions-granted", &mut self.store)?; match perm_func.call_async(&mut self.store, ()).await { Ok(_) => (), Err(e) => log::warn!("Failed to call on-permissions-granted: {}", e), // error occurs here } Ok(()) } }(note:
get_typed_functionis my own wrapper function)I know there's been similar issues in the past, notably #8670, which I have read, but the use case seems different from mine. Is there any way to fix this issue, or is it a limitation within wasmtime?
Cruxial0 commented on issue #10573:
I believe you need to call
.post_return_async()on theTypedFuncafter the.call_async()has returned and before you call into the component again.Okay yeah, that's it. It even clearly states so in the documentation. Not sure how I missed that... Thanks.
Last updated: Dec 06 2025 at 06:05 UTC