malformed-c opened issue #13813:
Summary
Linker::func_new_async(component model) can never satisfy an import whose WIT type is declaredasync func— it always fails with"type mismatch with async"at instantiation time, regardless of the actual host function's behavior. This isn't a functional bug (the semantics offunc_new_async/func_wrap_asyncare correct and intentional — they implement a sync-WIT-typed function via async/blocking Rust, per the "Blocking / Async Behavior" doc section), but the error message gives no indication of why the mismatch happened or which API to use instead, which made this fairly hard to track down.Root cause
Both
HostFunc::func_newandHostFunc::func_new_asyncconstructDynamicHostFn::<_, false>:pub(crate) fn func_new<T, F>(func: F) -> Result<Arc<HostFunc>> { Self::new(Asyncness::No, DynamicHostFn::<_, false>::new(...)) } #[cfg(feature = "async")] pub(crate) fn func_new_async<T, F>(func: F) -> Result<Arc<HostFunc>> { Self::new(Asyncness::Yes, DynamicHostFn::<_, false>::new(...)) // <- also `false` }
DynamicHostFn<F, const ASYNC: bool>::typecheckbails unlessASYNC == ty.async_:Since
ASYNCisfalsefor bothfunc_newandfunc_new_async(onlyAsyncness, a separate field unrelated to typechecking, differs between them),func_new_asynccan never typecheck against a component function whose WIT type hasasync_ == true.By contrast,
HostFunc::func_new_concurrentconstructsDynamicHostFn::<_, true>:...and does typecheck correctly against an
async funcimport.Repro
package test:asyncnoresource; interface api { consume: async func(x: u32) -> string; } world asyncnoresource { import api; export probe: async func() -> string; }Any attempt to satisfy
api#consumevialinker.instance("test:asyncnoresource/api")?.func_new_async("consume", ...)fails atinstantiate_asyncwith:Error: component imports instance `test:asyncnoresource/api`, but a matching implementation was not found in the linker Caused by: 0: instance export `consume` has the wrong type 1: type mismatch with asyncSwitching the exact same stub to
func_new_concurrent(requiresConfig::concurrency_support, which defaults totrue) succeeds and typechecks correctly.Found this while building a generic "stub every unsatisfied import with a trapping function" helper (a hand-rolled async-aware replacement for
Linker::define_unknown_imports_as_traps, which has the same issue — it always callsfunc_new, so it can't stub anasync funcimport at all: https://github.com/bytecodealliance/wasmtime/blob/v46.0.1/crates/wasmtime/src/runtime/component/linker.rs#L383-L385).define_unknown_imports_as_trapsmay be worth fixing too, for the same reason.Suggested improvement
Since the current behavior is intentional (not a bug to "fix" in the sense of changing semantics), the actionable improvement is diagnostics:
- When
DynamicHostFn's typecheck fails specifically becausety.async_ == true && ASYNC == false, the error could name the mismatch more specifically and point atfunc_new_concurrent/func_wrap_concurrentas the fix, e.g."type mismatch with async: this import is declaredasync funcin WIT; func_new/func_new_async cannot satisfy it (they implement sync-typed WIT functions via blocking host code) — use func_new_concurrent instead".Linker::define_unknown_imports_as_trapscould usefunc_new_concurrent(behind aconcurrency_supportcheck, or a documented caveat) so it can stubasync funcimports too, rather than only ever being usable for components with no unsatisfied async imports.Happy to send a PR for either or both if useful — wanted to check the framing/plan first given
Linker/LinkerInstance's API surface is fairly deliberate.wasmtime 46.0.1, reproduced via a from-scratch minimal WIT world (not tied to any particular upstream codegen tool).
alexcrichton commented on issue #13813:
Definitely agreed that the error message could be improved here, and if you're up for sending a PR I'd be happy to review. The approach here sounds reasonable, thanks for filing an issue for this!
alexcrichton added the wasm-proposal:component-model-async label to Issue #13813.
alexcrichton closed issue #13813:
Summary
Linker::func_new_async(component model) can never satisfy an import whose WIT type is declaredasync func— it always fails with"type mismatch with async"at instantiation time, regardless of the actual host function's behavior. This isn't a functional bug (the semantics offunc_new_async/func_wrap_asyncare correct and intentional — they implement a sync-WIT-typed function via async/blocking Rust, per the "Blocking / Async Behavior" doc section), but the error message gives no indication of why the mismatch happened or which API to use instead, which made this fairly hard to track down.Root cause
Both
HostFunc::func_newandHostFunc::func_new_asyncconstructDynamicHostFn::<_, false>:pub(crate) fn func_new<T, F>(func: F) -> Result<Arc<HostFunc>> { Self::new(Asyncness::No, DynamicHostFn::<_, false>::new(...)) } #[cfg(feature = "async")] pub(crate) fn func_new_async<T, F>(func: F) -> Result<Arc<HostFunc>> { Self::new(Asyncness::Yes, DynamicHostFn::<_, false>::new(...)) // <- also `false` }
DynamicHostFn<F, const ASYNC: bool>::typecheckbails unlessASYNC == ty.async_:Since
ASYNCisfalsefor bothfunc_newandfunc_new_async(onlyAsyncness, a separate field unrelated to typechecking, differs between them),func_new_asynccan never typecheck against a component function whose WIT type hasasync_ == true.By contrast,
HostFunc::func_new_concurrentconstructsDynamicHostFn::<_, true>:...and does typecheck correctly against an
async funcimport.Repro
package test:asyncnoresource; interface api { consume: async func(x: u32) -> string; } world asyncnoresource { import api; export probe: async func() -> string; }Any attempt to satisfy
api#consumevialinker.instance("test:asyncnoresource/api")?.func_new_async("consume", ...)fails atinstantiate_asyncwith:Error: component imports instance `test:asyncnoresource/api`, but a matching implementation was not found in the linker Caused by: 0: instance export `consume` has the wrong type 1: type mismatch with asyncSwitching the exact same stub to
func_new_concurrent(requiresConfig::concurrency_support, which defaults totrue) succeeds and typechecks correctly.Found this while building a generic "stub every unsatisfied import with a trapping function" helper (a hand-rolled async-aware replacement for
Linker::define_unknown_imports_as_traps, which has the same issue — it always callsfunc_new, so it can't stub anasync funcimport at all: https://github.com/bytecodealliance/wasmtime/blob/v46.0.1/crates/wasmtime/src/runtime/component/linker.rs#L383-L385).define_unknown_imports_as_trapsmay be worth fixing too, for the same reason.Suggested improvement
Since the current behavior is intentional (not a bug to "fix" in the sense of changing semantics), the actionable improvement is diagnostics:
- When
DynamicHostFn's typecheck fails specifically becausety.async_ == true && ASYNC == false, the error could name the mismatch more specifically and point atfunc_new_concurrent/func_wrap_concurrentas the fix, e.g."type mismatch with async: this import is declaredasync funcin WIT; func_new/func_new_async cannot satisfy it (they implement sync-typed WIT functions via blocking host code) — use func_new_concurrent instead".Linker::define_unknown_imports_as_trapscould usefunc_new_concurrent(behind aconcurrency_supportcheck, or a documented caveat) so it can stubasync funcimports too, rather than only ever being usable for components with no unsatisfied async imports.Happy to send a PR for either or both if useful — wanted to check the framing/plan first given
Linker/LinkerInstance's API surface is fairly deliberate.wasmtime 46.0.1, reproduced via a from-scratch minimal WIT world (not tied to any particular upstream codegen tool).
Last updated: Jul 29 2026 at 05:03 UTC