Stream: git-wasmtime

Topic: wasmtime / issue #13813 func_new_async can never satisfy ...


view this post on Zulip Wasmtime GitHub notifications bot (Jul 03 2026 at 10:55):

malformed-c opened issue #13813:

Summary

Linker::func_new_async (component model) can never satisfy an import whose WIT type is declared async 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 of func_new_async/func_wrap_async are 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_new and HostFunc::func_new_async construct DynamicHostFn::<_, false>:

https://github.com/bytecodealliance/wasmtime/blob/v46.0.1/crates/wasmtime/src/runtime/component/func/host.rs#L158-L208

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>::typecheck bails unless ASYNC == ty.async_:

https://github.com/bytecodealliance/wasmtime/blob/v46.0.1/crates/wasmtime/src/runtime/component/func/host.rs#L708-L714

Since ASYNC is false for both func_new and func_new_async (only Asyncness, a separate field unrelated to typechecking, differs between them), func_new_async can never typecheck against a component function whose WIT type has async_ == true.

By contrast, HostFunc::func_new_concurrent constructs DynamicHostFn::<_, true>:

https://github.com/bytecodealliance/wasmtime/blob/v46.0.1/crates/wasmtime/src/runtime/component/func/host.rs#L212-L241

...and does typecheck correctly against an async func import.

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#consume via linker.instance("test:asyncnoresource/api")?.func_new_async("consume", ...) fails at instantiate_async with:

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 async

Switching the exact same stub to func_new_concurrent (requires Config::concurrency_support, which defaults to true) 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 calls func_new, so it can't stub an async func import at all: https://github.com/bytecodealliance/wasmtime/blob/v46.0.1/crates/wasmtime/src/runtime/component/linker.rs#L383-L385). define_unknown_imports_as_traps may 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:

  1. When DynamicHostFn's typecheck fails specifically because ty.async_ == true && ASYNC == false, the error could name the mismatch more specifically and point at func_new_concurrent/func_wrap_concurrent as the fix, e.g. "type mismatch with async: this import is declared async func in WIT; func_new/func_new_async cannot satisfy it (they implement sync-typed WIT functions via blocking host code) — use func_new_concurrent instead".
  2. Linker::define_unknown_imports_as_traps could use func_new_concurrent (behind a concurrency_support check, or a documented caveat) so it can stub async func imports 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).

view this post on Zulip Wasmtime GitHub notifications bot (Jul 06 2026 at 02:57):

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!

view this post on Zulip Wasmtime GitHub notifications bot (Jul 06 2026 at 02:57):

alexcrichton added the wasm-proposal:component-model-async label to Issue #13813.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 06 2026 at 14:53):

alexcrichton closed issue #13813:

Summary

Linker::func_new_async (component model) can never satisfy an import whose WIT type is declared async 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 of func_new_async/func_wrap_async are 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_new and HostFunc::func_new_async construct DynamicHostFn::<_, false>:

https://github.com/bytecodealliance/wasmtime/blob/v46.0.1/crates/wasmtime/src/runtime/component/func/host.rs#L158-L208

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>::typecheck bails unless ASYNC == ty.async_:

https://github.com/bytecodealliance/wasmtime/blob/v46.0.1/crates/wasmtime/src/runtime/component/func/host.rs#L708-L714

Since ASYNC is false for both func_new and func_new_async (only Asyncness, a separate field unrelated to typechecking, differs between them), func_new_async can never typecheck against a component function whose WIT type has async_ == true.

By contrast, HostFunc::func_new_concurrent constructs DynamicHostFn::<_, true>:

https://github.com/bytecodealliance/wasmtime/blob/v46.0.1/crates/wasmtime/src/runtime/component/func/host.rs#L212-L241

...and does typecheck correctly against an async func import.

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#consume via linker.instance("test:asyncnoresource/api")?.func_new_async("consume", ...) fails at instantiate_async with:

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 async

Switching the exact same stub to func_new_concurrent (requires Config::concurrency_support, which defaults to true) 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 calls func_new, so it can't stub an async func import at all: https://github.com/bytecodealliance/wasmtime/blob/v46.0.1/crates/wasmtime/src/runtime/component/linker.rs#L383-L385). define_unknown_imports_as_traps may 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:

  1. When DynamicHostFn's typecheck fails specifically because ty.async_ == true && ASYNC == false, the error could name the mismatch more specifically and point at func_new_concurrent/func_wrap_concurrent as the fix, e.g. "type mismatch with async: this import is declared async func in WIT; func_new/func_new_async cannot satisfy it (they implement sync-typed WIT functions via blocking host code) — use func_new_concurrent instead".
  2. Linker::define_unknown_imports_as_traps could use func_new_concurrent (behind a concurrency_support check, or a documented caveat) so it can stub async func imports 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