Skip to content

Error: resource types are not the same when composing components #149

Open

Description

@mschuwalow

I'm trying to wrap a component that implments wasi:http/incoming-handler into a different api. The way I'm trying to accomplish this is by having two different components that will be composed with it.

  1. Exports the wasi:http/types interface + some extensions. This will be composed with (2) and (3) and has otherwise no imports (except other wasi interfaces)
  2. The wrapped component. This imports wasi:http/types and exports wasi:http/incoming-handler.
  3. A component providing the new api. This imports wasi:http/types, wasi:http/incoming-handler, the extensions from (1) and exports the new api.

Problem is that when I try composing the wasm, it errors with:

❯ wac plug adapter.wasm --plug types.wasm -o adapter-plugged.wasm
error: encoding produced a component that failed validation

Caused by:
    type mismatch for import `wasi:http/incoming-handler@0.2.3`
    type mismatch in instance export `incoming-request`
    resource types are not the same (ResourceId { globally_unique_id: 2, contextually_unique_id: 8 } vs. ResourceId { globally_unique_id: 2, contextually_unique_id: 57 }) (at offset 0x4e0399)

This error shows up both for wac plug and wac compose.


Wits look as follows:
Component 1:

package poc:types;

interface extensions {
    use wasi:http/types@0.2.3.{method, scheme, status-code, incoming-request, response-outparam};

    type fields = list<tuple<string, list<u8>>>;

    type body = list<u8>;

    record body-and-trailers {
        body: body,
        trailers: option<fields>
    }

    record request {
        method: method,
        path-with-query: string,
        scheme: scheme,
        authority: string,
        headers: fields,
        body-and-trailers: option<body-and-trailers>
    }

    record response {
        status: status-code,
        body: option<body-and-trailers>
    }

    resource response-outparam-proxy {
        constructor();

        new-outparam: func() -> response-outparam;
        get-response: func() -> response;
    }

    new-wasi-http-request: func(request: request) -> incoming-request;
}

world api {
    export wasi:http/types@0.2.3;
    export extensions
}

Component 2:

package poc:handler;

world api {
  import wasi:http/types@0.2.3;
  export wasi:http/incoming-handler@0.2.3;
}

Component 3:

package poc:adapter;

interface adapted-api {
    use poc:types/extensions.{request, response};

    handle: func(request: request) -> response;
}

world api {
    import wasi:http/incoming-handler@0.2.3;
    import wasi:http/types@0.2.3;
    import poc:types/extensions;

    export adapted-api;
}

I suspect this is a similiar error to bytecodealliance/wasm-tools#1565. This comment provided a reproduction that fails with the same error.

Activity

  1. vigoo commented on Jan 28, 2025

    @vigoo

    I now have a much smaller reproducer for this, still investigating the root cause. Just wanted to add some details from this ongoing investigation, in case it triggers some ideas

    The following simple case produces the composition error:

    "socket" component:

    package x:y;
    
    interface api {
      use wasi:io/poll@0.2.0.{pollable};
    
      run: func();
      get: func() -> pollable;
    }
    
    world compose-bug {
      import wasi:clocks/monotonic-clock@0.2.0;
      import wasi:io/poll@0.2.0;
    
      export api;
    }

    "plug" component:

    package x:z;
    
    world wrapper {
      import wasi:io/poll@0.2.0;
      export wasi:io/poll@0.2.0;
    }

    Trying to "plug" this wrapper to the other component produces a component with the following validation error:

    error: type mismatch for import `wasi:clocks/monotonic-clock@0.2.0`
    type mismatch in instance export `pollable`
    resource types are not the same (ResourceId { globally_unique_id: 0, contextually_unique_id: 1 } vs. ResourceId { globally_unique_id: 0, contextually_unique_id: 12 }) (at offset 0xabe6)
    

    The following is also true:

    • The problem is caused by monotonic-clock, which is imported into the inner component, is referring to Pollable in wasi:io/poll.
    • Importing something else that the wrapper does not contain, but has no reference to wasi:io/poll, works (for example I can import wasi:logging/logging into the inner component with no problem)
    • If the wrapper also wraps (imports and exports) monotonic-clock, the composition succeeds
  2. elewis787 commented on Apr 17, 2025

    @elewis787

    @jeff1010322 and I are also running into this error.

    We have created a repository that highlights the reproducible issue at https://github.com/hayride-dev/compose-bug.

    In the example, we create 3 components

    • foo: exports the foo interface, which defines a foo resource.
    • foo-bar: exports the foo-bar interface, which defines a foo-bar resource that uses foo.
    • foo-bar-baz: imports both foo and foo-bar, and creates a command component that exports the CLI run functions. Uses foo and foobar to build a "foo-bar-baz" string.

    We build foo, foo-bar, and foo-bar-baz as components, then use WAC to compose them together.

    wac plug foo-bar.wasm --plug foo.wasm -o foo-bar-composed.wasm
    wac plug foo-bar-baz.wasm --plug foo-bar-composed.wasm -o foo-bar-baz-composed.wasm

    In the above example, foo-bar and foo are successfully plugged.

    However, when attempting to plug foo-bar-composed.wasm with foo-bar-baz.wasm, the following error is triggered

    error: encoding produced a component that failed validation
    
    Caused by:
        type mismatch for import `compose:lib/foo-bar@0.0.1`
        type mismatch in instance export `foo-resource`
        resource types are not the same (ResourceId { globally_unique_id: 2, contextually_unique_id: 51 } vs. ResourceId { globally_unique_id: 2, contextually_unique_id: 1 }) (at offset 0x15d26f)
    make: *** [wac-foo-bar-baz] Error 1
    

    This can also be triggered by attempting to plug foo.wasm directly into foo-bar-baz.wasm

    wac plug foo-bar-baz.wasm --plug foo.wasm -o composed.wasm
    error: encoding produced a component that failed validation
    
    Caused by:
        type mismatch for import `compose:lib/foo-bar@0.0.1`
        type mismatch in instance export `foo-resource`
        resource types are not the same (ResourceId { globally_unique_id: 2, contextually_unique_id: 1 } vs. ResourceId { globally_unique_id: 2, contextually_unique_id: 26 }) (at offset 0x107127)
    

    Based on code comments in https://github.com/bytecodealliance/wasm-tools/blob/351f1537490f7d5e4a61f8ab16302984589d25d2/crates/wasmparser/src/validator/component_types.rs#L1284 and the error message, we suspect that this is related to the contextually_unique_id each component is generating for the resource that is attempting to be passed between components.

    Any suggestions on a workaround would be awesome, or guidance on the root cause.

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