Skip to content

fix: keep the request future in the stream pipeline for ResponseType.stream - #921

Merged
trevorwang merged 1 commit into
trevorwang:masterfrom
Yusufihsangorgel:fix/907-stream-no-await-in-async-star
Jul 21, 2026
Merged

fix: keep the request future in the stream pipeline for ResponseType.stream#921
trevorwang merged 1 commit into
trevorwang:masterfrom
Yusufihsangorgel:fix/907-stream-no-await-in-async-star

Conversation

@Yusufihsangorgel

Copy link
Copy Markdown
Contributor

Closes #907.

The problem

Generated methods for @DioResponseType(ResponseType.stream) awaited the
request future inside an async* body:

final _result = await _dio.fetch<ResponseBody>(_options);
final _value = _result.data!.stream;
yield* _value;

If the stream subscription is cancelled while execution is suspended at that
await, a later error from the pending future is no longer delivered through
the stream listener lifecycle and can surface as an unhandled zone error. In
practice that shows up as noisy false positives in global error collectors, even
when the consumer is handling stream errors correctly.

The fix

Emit the fetch without await and expand it through the stream pipeline, so the
future stays inside the stream:

final _result = _dio.fetch<ResponseBody>(_options);
final _value = _result.asStream().asyncExpand(
  (response) => response.data!.stream,
);
yield* _value;

Stream<String> gets the same shape with .map(utf8.decode) inside the expand.
This is the change proposed in the issue.

Tests

Updated the two ResponseType.stream codegen expectations, for
Stream<Uint8List> and for Stream<String>, to the new generated output.
Generator suite green (202 tests), dart analyze clean, formatted.

…stream

Closes trevorwang#907. Generated methods for @DioResponseType(ResponseType.stream) awaited
the request future inside an async* body, so if the subscription was cancelled
while suspended at the await, a later error from that future could escape the
stream listener lifecycle and surface as an unhandled zone error. Emit
_dio.fetch<ResponseBody>(...) without await and expand it through
asStream().asyncExpand(...) instead, keeping the future inside the stream.
@trevorwang
trevorwang merged commit b95c0a7 into trevorwang:master Jul 21, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Generated ResponseType.stream code awaits fetch inside async*, which can leak post-cancel errors to zone

2 participants