Skip to content

component new: Failed to resolve import env::console_log #2483

Closed

Description

@guest271314

I generated WIT from WAT using this script (generate_wit.js)

node generate_wit.js quic-wasm.wat > quic.wit

I then embed

../wasm-tools/wasm-tools component embed quic.wit quic.wasm -o quic.embedded.wasm

Creating a component fails

../wasm-tools/wasm-tools component new quic.embedded.wasm -o quic.component.wasm
error: failed to encode a component from module

Caused by:
    0: failed to decode world from module
    1: module was not valid
    2: failed to resolve import `env::console_log`
    3: import interface `env` is missing function `console_log` that is required by the module

Here's the generated WIT

package local:quic-wasm;

world quic-wasm-world {
  import env: interface {
    console-log: func(argv: string);
    get-time-ns: func() -> u64;
    random-fill: func(argv: list<u8>);
  }
  export qz-set-cert: func(argv: list<u8>) -> u32;
  export qz-set-key: func(argv: list<u8>) -> u32;
  export qz-init-server: func() -> u32;
  export qz-init-client: func() -> u32;
  export qz-deinit: func();
  export qz-recv-packet: func(argv: list<u8>) -> u32;
  export qz-send-packets: func(argv: list<u8>) -> u32;
  export qz-on-timeout: func();
  export qz-next-timeout-ns: func() -> u64;
  export qz-is-established: func() -> u32;
  export qz-is-closed: func() -> u32;
  export qz-poll-event: func(argv: list<u8>) -> u32;
  export qz-stream-send: func(argv0: u64, argv1: list<u8>) -> u32;
  export qz-stream-close: func(argv: u64);
  export qz-stream-read: func(argv0: u64, argv1: list<u8>) -> u32;
  export qz-datagram-send: func(argv: list<u8>) -> u32;
  export qz-datagram-recv: func(argv: list<u8>) -> u32;
  export qz-wt-accept-session: func(argv: u64) -> u32;
  export qz-wt-read-stream: func(argv0: u64, argv1: list<u8>) -> u32;
  export qz-wt-send-stream: func(argv0: u64, argv1: list<u8>) -> u32;
  export qz-wt-close-stream: func(argv: u64);
  export qz-wt-read-datagram: func(argv0: u64, argv1: list<u8>) -> u32;
  export qz-wt-send-datagram: func(argv0: u64, argv1: list<u8>) -> u32;
  export qz-wt-close-session: func(argv0: u64, argv1: list<u8>, argv2: u32) -> u32;
  export qz-alloc: func(argv: u32) -> u32;
  export qz-free: func(argv: list<u8>);
}

What's wrong with the WIT, or what's wrong with wasm-tools, or what's wrong with both?

Activity

  1. dicej commented on Apr 7, 2026

    @dicej
    Collaborator

    From what I can see, the WIT is fine and wasm-tools is doing the right thing, but the WAT being passed to watToWit does not match the naming scheme wasm-tools expects for the specified WIT interface. Specifically, wasm-tools expects an import named "console-log" from a module named "env" based on the declared name in the WIT file. Instead, it's finding an import named "console_log" from the module named "env" and doesn't know what to do with it.

  2. guest271314 commented on Apr 7, 2026

    @guest271314
    Author

    I don't see why wasm-tools is expecting a dash there. WIT has to deal with whatever is in the WAT and WASM.

    wabt-1.0.40/bin/wasm2wat quic.wasm -o quic-wasm.wat
    
    cat quic-wasm.wat | grep console
      (import "env" "console_log" (func (;0;) (type 5)))
    
    
  3. guest271314 commented on Apr 7, 2026

    @guest271314
    Author

    The source code has an underscore https://github.com/endel/quic-zig/blob/wasm-experiment/src/wasm_api.zig#L16

    extern "env" fn console_log(ptr: [*]const u8, len: usize) void;
    

    No idea why wasm-tools is expecting anything in particular from source code from the wild.

  4. dicej commented on Apr 7, 2026

    @dicej
    Collaborator

    Does Zig have a way to specify the import name? In C, it would be:

    __attribute__((__import_module__("env"), __import_name__("console-log")))
    extern void __wasm_import_env_console_log(uint8_t *, size_t);

    In Rust:

    #[link(wasm_import_module = "env")]
    unsafe extern "C" {
      #[link_name = "console-log"]
      fn wit_import1(_: *mut u8, _: usize, );
    }

    In Go:

    //go:wasmimport env console-log
    func wasm_import_console_log(arg0 uintptr, arg1 uint32)
  5. guest271314 commented on Apr 7, 2026

    @guest271314
    Author

    Does Zig have a way to specify the import name? In C, it would be:

    Hmm. So the suggestion is to change working source code for wasm-tools to be able to handle it, where the source code works as-is as a WebAssembly core Module https://github.com/guest271314/webtransport/blob/wasm/webtransport-example.js#L53C1-L68C33?

      const {instance} = await WebAssembly.instantiate(wasmBytes, {
        env: {
          // memory,
          get_time_ns: () => BigInt(Math.round(performance.now() * 1_000_000)),
          console_log: (ptr, len) => {
            const bytes = new Uint8Array(instance.exports.memory.buffer,ptr,len);
            console.log("[wasm]", new TextDecoder().decode(bytes));
          }
          ,
          random_fill: (ptr, len) => {
            crypto.getRandomValues(new Uint8Array(instance.exports.memory.buffer,ptr,len), );
          }
          ,
        },
      });
      const wasm = instance.exports;
    

    I think it should be the other way around. wasm-tools should be flexible enough, and/or the WIT/Component Model should be adaptible enough to handle whatever is thrown at it.

  6. dicej commented on Apr 7, 2026

    @dicej
    Collaborator

    WIT has to deal with whatever is in the WAT and WASM.

    WIT is intended to provide a human-readable representation of the Component Model type system, which does not cover every possible existing ABI and naming convention used in Wasm modules that exist in the wild. The expectation is that the module author (or binding generator) will have the Component Model "canonical" ABI and naming convention in mind when creating the application, which may require source code modifications.

    I do recall there was a plan to eventually support other (i.e. "non-canonical") ABIs and/or naming conventions in the Component Model, but I'm not aware of any existing support for that in the specification or in wasm-tools.

  7. guest271314 commented on Apr 7, 2026

    @guest271314
    Author

    The expectation is that the module author (or binding generator) will have the Component Model "canonical" ABI and naming convention in mind when creating the application, which may require source code modifications.

    Yeah, that doesn't make sense to me.

    I didn't have WebAssembly Components in mind when I created the WASM. I'm just trying to port the working code to different programming languages/application layers.

    This appears to me to be a bug in the core design.

    Who cares if the source code has an underscore or a dash? That's far too restrictive. If anything wasm-tools/the specification should just handle both; or internally map what it can't handle for whatever reason, to what it can handle.

    Realistically, I shouldn't have had to go to Google Gemini to create WIT from WAT. All of that conversion should be baked in to one of these WebAssembly Component Model programs.

    You said the WIT looks fine.

    From what I can see, the WIT is fine

    So, if the WIT is fine, there shouldn't be any issues creating a component. But there is, and that issue is seen downstream bytecodealliance/jco#1362 (comment).

    Can't have valid WIT, yet at the same time suggest to change the whole source code to accomodate a program that can't handle valid WIT.

  8. guest271314 commented on Apr 7, 2026

    @guest271314
    Author

    @dicej

    The expectation is that the module author (or binding generator) will have the Component Model "canonical" ABI and naming convention in mind when creating the application, which may require source code modifications.

    If that's the case you folks should consider updating all of those examples/tutorials in your documentations to say exactly that.

    I havn't read anywhere in the tutorials/examples of creating compoenents from existing WAT that the import/export names need to be changed to accomodate a specific design goal, and refer to that specification section that says you MUST use dashes in source code.

  9. guest271314 commented on Apr 7, 2026

    @guest271314
    Author

    Part of what I'm doing here is vetting the WebAssembly Component Model.

    I don't see what all the hubbub is about. I don't see any advantages in the design cf. core modules. But I'm testing it out for empirical evidence. Then I encounter this subtle, yet turns out to be a show-stopping 'lil inconsitency.

  10. tschneidereit commented on Apr 7, 2026

    @tschneidereit
    Member

    @guest271314 we appreciate feedback and questions, but I'd ask you to be mindful of the fact that you're discussing a project that many people have been working on for many years, as well as that we're all people with limited amounts of time. That means you have to do some amount of research yourself, instead of asking other people to answer any question you might have. It also means assuming that not everything you don't immediately understand is wrong or broken.

    You've voiced your opinion on all this here and in other issues such as in JCO—please be assured that we've heard it.

    I'll go ahead and close this issue, since it's answered as much as it can be.

  11. guest271314 commented on Apr 8, 2026

    @guest271314
    Author

    @tschneidereit I did my research. Just because something gets worked on a long time doesn't mean it works.

    You close the issue but your gear is still broken in this case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions