Dial requests in `stream` behaviour are silently dropped
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 5.6k
- Forks
- 1.3k
- Avg merge
- 8h 47m
- Merged PRs (30d)
- 19
Description
Summary
I'm struggling to understand why the stream behavior calls try_send without handling the result here.
In our use case with hundreds of streams opened per second, it becomes a serious problem — some of the requested streams never trigger a dial, so nothing happens until a timeout on the caller's side.
Expected behavior
If a stream couldn't be opened, at least an error should be returned to the caller. Ideally, the behaviour should handle it itself and, e.g. queue the request for later, but I can see why it's problematic.
Actual behavior
Control::open_stream never returns, although some resources were allocated.
Relevant log output
2025-09-03T10:56:22.581481Z DEBUG sqd_network_transport::behaviour::stream_client: Opening stream to 12D3KooWFjzbi2MNkVpEDtdybAFuvixmTUzzijVNXxSo4cxAgpoR
2025-09-03T10:56:22.581514Z DEBUG libp2p_stream::control: Requesting new stream peer=12D3KooWFjzbi2MNkVpEDtdybAFuvixmTUzzijVNXxSo4cxAgpoR
2025-09-03T10:56:22.581546Z DEBUG libp2p_stream::shared: Not connected to peer, initiating dial peer=12D3KooWFjzbi2MNkVpEDtdybAFuvixmTUzzijVNXxSo4cxAgpoR
...Nothing mentioning "12D3KooWFjzbi2MNkVpEDtdybAFuvixmTUzzijVNXxSo4cxAgpoR" on TRACE level
2025-09-03T10:56:32.584019Z DEBUG sqd_network_transport::behaviour::stream_client: Connection to 12D3KooWFjzbi2MNkVpEDtdybAFuvixmTUzzijVNXxSo4cxAgpoR timed out
Possible Solution
A few options I see:
- Just use an unbounded channel. It might be the best option if the backpressure can't be correctly propagated.
- Await until the dial request is sent, propagating backpressure to the client to pause new requests until the behaviour is polled unblocking the channel.
- If none of the above is possible, at least return an error to the client, saying that there are too many concurrent dial attempts.
Version
0.55
Would you like to work on fixing this bug?
Yes
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at protocols/stream/src/shared.rs around the try_send call linked in the issue, then trace how Control::open_stream handles dial requests and channel backpressure. Reproduce the high-rate stream-opening case described in the logs and determine how a failed request should be surfaced or retained; done means callers no longer wait indefinitely when a dial request cannot be sent.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- networking
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100