Aditya1404Sal opened PR #13418 from Aditya1404Sal:fix-cross-component-stream-copy to bytecodealliance:main:
Summary
Fix cross-component async
stream/futurecopy logic so writer-side payload metadata and memory are resolved from the writer component instance, while reader-side payload metadata and memory are resolved from the reader component instance.Previously,
Instance::copyresolved bothwrite_tyandread_tyagainstself.component().types(). That works when both endpoints are inside one composed component graph, but breaks when the stream crosses dynamically linked component instances with distinctComponentTypestables.Problem
When a guest-created
stream<T>is returned by one component and passed into another dynamically linked component, the stream handle can be valid while the payload copy uses the wrong component type table or memory/options.The same issue can also surface as internal panics such as:
BUG: expected write payload type to be presentFix
Instance::copynow receives both endpoint instances:
write_instancefor writer payload ABI, writer memory, andLiftContextread_instancefor reader payload ABI, reader memory, andLowerContextThe guest write/read rendezvous call sites now pass the correct endpoint instances through to
copy.This also fixes partial stream writes by preserving the original
write_instancewhen re-storing a pendingWriteState::GuestReady; otherwise subsequent reads of the remaining write buffer could accidentally use the reader instance.Validation
Only Validated locally with wasmCloud’s
examples/patch-streama setup (which I will promptly create for wasmtime), where:
- a producer component returns
stream<u8>- a consumer component forwards that stream to a third component
- the sink component drains and logs each NDJSON patch line
Before this fix, the sink saw corrupted binary-looking data. After this fix, it receives all expected patch lines and the stream closes cleanly:
Also ran:
cargo check -p wasmtime --features component-model,component-model-async
Aditya1404Sal edited PR #13418:
Summary
Fix cross-component async
stream/futurecopy logic so writer-side payload metadata and memory are resolved from the writer component instance, while reader-side payload metadata and memory are resolved from the reader component instance.Previously,
Instance::copyresolved bothwrite_tyandread_tyagainstself.component().types(). That works when both endpoints are inside one composed component graph, but breaks when the stream crosses dynamically linked component instances with distinctComponentTypestables.Problem
When a guest-created
stream<T>is returned by one component and passed into another dynamically linked component, the stream handle can be valid while the payload copy uses the wrong component type table or memory/options.The same issue can also surface as internal panics such as:
BUG: expected write payload type to be presentFix
Instance::copynow receives both endpoint instances:
write_instancefor writer payload ABI, writer memory, andLiftContextread_instancefor reader payload ABI, reader memory, andLowerContextThe guest write/read rendezvous call sites now pass the correct endpoint instances through to
copy.This also fixes partial stream writes by preserving the original
write_instancewhen re-storing a pendingWriteState::GuestReady; otherwise subsequent reads of the remaining write buffer could accidentally use the reader instance.Validation
Only Validated locally with wasmCloud’s
examples/patch-streama setup (which I will promptly create for wasmtime), where:
- a producer component returns
stream<u8>- a consumer component forwards that stream to a third component
- the sink component drains and logs each NDJSON patch line
Before this fix, the sink saw corrupted binary-looking data. After this fix, it receives all expected patch lines and the stream closes cleanly:
Also ran:
cargo check -p wasmtime --features component-model,component-model-async
Aditya1404Sal has marked PR #13418 as ready for review.
Aditya1404Sal requested pchickey for a review on PR #13418.
Aditya1404Sal requested wasmtime-core-reviewers for a review on PR #13418.
github-actions[bot] added the label wasmtime:api on PR #13418.
pchickey unassigned pchickey from PR #13418 Fix: cross component stream copy.
pchickey requested alexcrichton for a review on PR #13418.
:memo: pchickey submitted PR review:
I dont have the context at the moment to be able to deeply review this. @alexcrichton is traveling this week for a conference, so his review may take a bit, but I've re-assigned to him.
:memo: dicej submitted PR review:
Thanks, @Aditya1404Sal. I'll admit I hadn't considered the possibility of passing the read end of a stream or future to a different top-level component instance than the write end, but it does make sense.
Would you be up for adding a test for this scenario, e.g. a new test in
crates/misc/component-async-tests/tests/scenario/streams.rs?
:speech_balloon: dicej created PR review comment:
Does it still make sense to take a
selfparameter here? It doesn't seem to be used anymore, and would presumably be a mistake to use instead ofwrite_instanceandread_instance.
:speech_balloon: dicej edited PR review comment.
Aditya1404Sal updated PR #13418.
Aditya1404Sal commented on PR #13418:
@dicej thanks for the review! I've added a regression test, lmk if there's anything else.
Aditya1404Sal edited a comment on PR #13418:
Thanks for the review @dicej -- I've added a regression test, lmk if there's anything else.
:thumbs_up: dicej submitted PR review:
Great work, thanks!
dicej added PR #13418 Fix: cross component stream copy to the merge queue.
:check: dicej merged PR #13418.
dicej removed PR #13418 Fix: cross component stream copy from the merge queue.
Last updated: Jun 01 2026 at 09:49 UTC