Stream: git-wasmtime

Topic: wasmtime / issue #12226 How to migrate from v39 to v40 (s...


view this post on Zulip Wasmtime GitHub notifications bot (Dec 28 2025 at 22:28):

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 main branch 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-40 where 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 async

In the branch wasmtime-40-fix I added the async keyword to all the functions in the wits, made the guest code async, and then enabled wasm_component_model_async as opposed to the wasm_component_model I 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?

view this post on Zulip Wasmtime GitHub notifications bot (Dec 28 2025 at 22:29):

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 main branch 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-40 where 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 async

In the branch wasmtime-40-fix I added the async keyword to all the functions in the wits, made the guest code async, and then enabled wasm_component_model_async as opposed to the wasm_component_model I 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?

view this post on Zulip Wasmtime GitHub notifications bot (Jan 05 2026 at 15:28):

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 async is 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 with func_wrap_concurrent for async and func_wrap or func_wrap_async for sync (yes, the irony isn't lost on us).

The recent support for the store flag in bindgen! 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 using store | async you're using func_wrap_concurrent under the hood. That's what changed, that's why things broke for you, and that's why using async in WIT "fixes" things.

Routes forward for this I an think of are:

view this post on Zulip Wasmtime GitHub notifications bot (Jan 05 2026 at 18:15):

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-bindgen 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 returning

I'm testing in this branch of my wasm-tester repo. It uses the async keyword in the host (built-in) wit but does not use it in the guest export and then I'm using the async parameter of the wit_bindgen::generate! macro to disable async for the foo import specifically. It also has the same error when I use async: false instead of directly targeting the function.

view this post on Zulip Wasmtime GitHub notifications bot (Jan 05 2026 at 18:15):

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 returning

I'm testing in this branch of my wasm-tester repo. It uses the async keyword in the host (built-in) wit but does not use it in the guest export and then I'm using the async parameter of the wit_bindgen::generate! macro to disable async for the foo import specifically. It also has the same error when I use async: false instead of directly targeting the function.

view this post on Zulip Wasmtime GitHub notifications bot (Jan 07 2026 at 18:54):

alexcrichton commented on issue #12226:

Ah ok yeah that's expected insofar as it's a sync function (use-foo) calling an async function (the builtin function). To get this working you'll need to also model use-foo as itself an async function, 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

view this post on Zulip Wasmtime GitHub notifications bot (Jan 07 2026 at 23:11):

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.

view this post on Zulip Wasmtime GitHub notifications bot (Jan 07 2026 at 23:13):

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 main branch 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-40 where 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 async

In the branch wasmtime-40-fix I added the async keyword to all the functions in the wits, made the guest code async, and then enabled wasm_component_model_async as opposed to the wasm_component_model I 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