wilfreddenton opened issue #12226:
I created a repo that shows the basic setup that my much large/complex project has: https://github.com/wilfreddenton/wasm-tester
The
mainbranch shows how in v39 I am able to implement component imports with async methods and then call them synchronously in the guest code. Limiting complexity in the guest code i.e. avoiding async/await is desirable for this project.Is this just simply no longer possible in v40? The repo has a branch
wasmtime-40where the only change is updating the version number of the wasmtime dep. Everything compiles still but I get the following:Error: component imports instance `contract:built-in/context`, but a matching implementation was not found in the linker Caused by: 0: instance export `foo` has the wrong type 1: type mismatch with asyncIn the branch
wasmtime-40-fixI added theasynckeyword to all the functions in the wits, made the guest code async, and then enabledwasm_component_model_asyncas opposed to thewasm_component_modelI had before on the engine. This fixes the runtime but now all my guest code has to be async.So I just want to be sure that this is the correct/only migration strategy?
wilfreddenton edited issue #12226:
I created a repo that shows the basic setup that my much large/complex project has: https://github.com/wilfreddenton/wasm-tester
The
mainbranch shows how in v39 I am able to implement component imports with async methods and then call them synchronously in the guest code. Limiting complexity in the guest code i.e. avoiding async/await is desirable for this project.Is this just simply no longer possible in v40? The repo has a branch
wasmtime-40where the only change is updating the version number of the wasmtime dep. Everything compiles still but I get the following:Error: component imports instance `contract:built-in/context`, but a matching implementation was not found in the linker Caused by: 0: instance export `foo` has the wrong type 1: type mismatch with asyncIn the branch
wasmtime-40-fixI added theasynckeyword to all the functions in the wits, made the guest code async, and then enabledwasm_component_model_asyncas opposed to thewasm_component_modelI had before on the engine. This fixes the runtime but now all my guest code has to be async.So I just want to be sure that this is the correct/only migration strategy?
alexcrichton commented on issue #12226:
Thanks for the report, and yeah this is an unfortunate interaction with the new component-model-async work. Specifically what is happening here is that a component model change means that
asyncis now part of a function type in the component model. This means that Wasmtime, as a host, needs a way to define either an async function or a non-async function. Right now that's done in Wasmtime withfunc_wrap_concurrentforasyncandfunc_wraporfunc_wrap_asyncfor sync (yes, the irony isn't lost on us).The recent support for the
storeflag inbindgen!was also originally added for component-model-async functions. This was then sort of backported to prior support for host functions in such a way where by usingstore | asyncyou're usingfunc_wrap_concurrentunder the hood. That's what changed, that's why things broke for you, and that's why usingasyncin WIT "fixes" things.Routes forward for this I an think of are:
- One thing we historically talked about was the ability to dynamically specify the async-ness of a host function which would enable bindings generation to fix this automatically (e.g. support a non-
asyncWIT function that's async on the host).- Another solution, as you've found, is to use
asyncin the WIT. You should be able to instruct guest bindings generators to generate non-asyncbindings for async functions, but that'll require generator-specific configuration.
wilfreddenton commented on issue #12226:
Thanks for the response @alexcrichton.
One thing we historically talked about was the ability to dynamically specify the async-ness of a host function which would enable bindings generation to fix this automatically (e.g. support a non-async WIT function that's async on the host).
I believe this would be quite useful but I guess this is a long term solution.
Another solution, as you've found, is to use async in the WIT. You should be able to instruct guest bindings generators to generate non-async bindings for async functions, but that'll require generator-specific configuration.
I've been trying this strategy with
wit-bindgenbut haven't gotten it to work. Getting this runtime error:Error: error while executing at wasm backtrace: 0: 0x1f4c43 - <unknown>!<wasm function 0> 1: 0x13c5 - guest.wasm!guest::contract::built_in::context::foo::h06099e4fc41fc8e8 2: 0x735 - guest.wasm!<guest::Contract as guest::Guest>::use_foo::h509cde4d218381fb 3: 0x4a0 - guest.wasm!guest::_export_use_foo_cabi::h36d590b3aab01f1e 4: 0x77c - guest.wasm!use-foo note: using the `WASMTIME_BACKTRACE_DETAILS=1` environment variable may show more debugging information Caused by: wasm trap: cannot block a synchronous task before returningI'm testing in this branch of my
wasm-testerrepo. It uses theasynckeyword in the host (built-in) wit but does not use it in the guest export and then I'm using theasyncparameter of thewit_bindgen::generate!macro to disable async for thefooimport specifically. It also has the same error when I useasync: falseinstead of directly targeting the function.
wilfreddenton edited a comment on issue #12226:
Thanks for the response @alexcrichton.
One thing we historically talked about was the ability to dynamically specify the async-ness of a host function which would enable bindings generation to fix this automatically (e.g. support a non-async WIT function that's async on the host).
I believe this would be quite useful but I guess this is a long term solution.
Another solution, as you've found, is to use async in the WIT. You should be able to instruct guest bindings generators to generate non-async bindings for async functions, but that'll require generator-specific configuration.
I've been trying this strategy with
wit-bindgen(rust) but haven't gotten it to work. Getting this runtime error:Error: error while executing at wasm backtrace: 0: 0x1f4c43 - <unknown>!<wasm function 0> 1: 0x13c5 - guest.wasm!guest::contract::built_in::context::foo::h06099e4fc41fc8e8 2: 0x735 - guest.wasm!<guest::Contract as guest::Guest>::use_foo::h509cde4d218381fb 3: 0x4a0 - guest.wasm!guest::_export_use_foo_cabi::h36d590b3aab01f1e 4: 0x77c - guest.wasm!use-foo note: using the `WASMTIME_BACKTRACE_DETAILS=1` environment variable may show more debugging information Caused by: wasm trap: cannot block a synchronous task before returningI'm testing in this branch of my
wasm-testerrepo. It uses theasynckeyword in the host (built-in) wit but does not use it in the guest export and then I'm using theasyncparameter of thewit_bindgen::generate!macro to disable async for thefooimport specifically. It also has the same error when I useasync: falseinstead of directly targeting the function.
alexcrichton commented on issue #12226:
Ah ok yeah that's expected insofar as it's a sync function (
use-foo) calling anasyncfunction (the builtin function). To get this working you'll need to also modeluse-fooas itself anasyncfunction, for example:diff --git a/crates/guest/src/lib.rs b/crates/guest/src/lib.rs index 16f8d10..8aae10c 100644 --- a/crates/guest/src/lib.rs +++ b/crates/guest/src/lib.rs @@ -4,7 +4,8 @@ wit_bindgen::generate!({ generate_all, generate_unused_types: true, async: [ - "-import:contract:built-in/context#foo" + "-import:contract:built-in/context#foo", + "-use-foo", ] }); diff --git a/crates/guest/wit/contract.wit b/crates/guest/wit/contract.wit index cbef0b8..8c59be2 100644 --- a/crates/guest/wit/contract.wit +++ b/crates/guest/wit/contract.wit @@ -3,5 +3,5 @@ package root:component; world root { include contract:built-in/built-in; - export use-foo: func() -> string; + export use-foo: async func() -> string; }Using that it worked out for me locally
wilfreddenton commented on issue #12226:
Now what you said here https://github.com/WebAssembly/component-model/pull/578#discussion_r2577894213 makes sense to me. This is an example of coloring applying to the WITs but not to the guest implementation.
With this strategy I was able to migrate the project to v40. Thank you!
Afaic this issue can be closed but I'll leave that to you since it has been put under a project.
pchickey closed issue #12226:
I created a repo that shows the basic setup that my much large/complex project has: https://github.com/wilfreddenton/wasm-tester
The
mainbranch shows how in v39 I am able to implement component imports with async methods and then call them synchronously in the guest code. Limiting complexity in the guest code i.e. avoiding async/await is desirable for this project.Is this just simply no longer possible in v40? The repo has a branch
wasmtime-40where the only change is updating the version number of the wasmtime dep. Everything compiles still but I get the following:Error: component imports instance `contract:built-in/context`, but a matching implementation was not found in the linker Caused by: 0: instance export `foo` has the wrong type 1: type mismatch with asyncIn the branch
wasmtime-40-fixI added theasynckeyword to all the functions in the wits, made the guest code async, and then enabledwasm_component_model_asyncas opposed to thewasm_component_modelI had before on the engine. This fixes the runtime but now all my guest code has to be async.So I just want to be sure that this is the correct/only migration strategy?
Last updated: Jan 09 2026 at 13:15 UTC