Repository navigation
Description
Package
dio
Version
5.11.1; reproduced on master 4684e29d with the repository package.
Operating-System
MacOS (Dart VM regression). The reproduction uses a local fake adapter and does not require an external server.
Adapter
The response-stream handler shared by adapters; reproduced through the public Dio API with a streaming test adapter.
Output of flutter doctor -v
Host environment (identifiers redacted)
[!] Flutter (Channel stable, 3.44.7, on macOS 26.6.2 25G83 darwin-arm64, locale zh-Hans-TW) [515ms]
• Flutter version 3.44.7 on channel stable at <home>/fvm/versions/3.44.7
! Warning: `flutter` on your path resolves to <home>/Documents/sdk/flutter/bin/flutter, which is not inside your current Flutter SDK checkout at <home>/fvm/versions/3.44.7. Consider adding <home>/fvm/versions/3.44.7/bin to the front of your path.
! Warning: `dart` on your path resolves to /opt/homebrew/Cellar/dart/3.12.2/libexec/bin/dart, which is not inside your current Flutter SDK checkout at <home>/fvm/versions/3.44.7. Consider adding <home>/fvm/versions/3.44.7/bin to the front of your path.
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 84fc5cbb22 (3 months ago), 2026-07-17 10:20:17 -0700
• Engine revision 69c8c61792
• Dart version 3.12.2
• DevTools version 2.57.0
• Pub download mirror https://pub.flutter-io.cn
• Flutter download mirror https://storage.flutter-io.cn
• Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios, cli-animations, enable-native-assets, enable-swift-package-manager, omit-legacy-version-file, enable-lldb-debugging, enable-uiscene-migration
• If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades.
[✓] Android toolchain - develop for Android devices (Android SDK version 36.1.0) [1,616ms]
• Android SDK at <home>/Library/Android/sdk
• Emulator version 36.6.11.0 (build_id 15507667) (CL:N/A)
• Platform android-36.1, build-tools 36.1.0
• ANDROID_HOME = <home>/Library/Android/sdk
• ANDROID_SDK_ROOT = <home>/Library/Android/sdk
• Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
This is the JDK bundled with the latest Android Studio installation on this machine.
To manually set the JDK path, use: `flutter config --jdk-dir="path/to/jdk"`.
• Java version OpenJDK Runtime Environment (build 21.0.10+-117844308-b1163.108)
• All Android licenses accepted.
[!] Xcode - develop for iOS and macOS (Xcode 27.0) [931ms]
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 27A266a
! iOS 27.0 Simulator not installed; this may be necessary for iOS and macOS development.
To download and install the platform, open Xcode, select Xcode > Settings > Components,
and click the GET button for the required platform.
For more information, please visit:
https://developer.apple.com/documentation/xcode/installing-additional-simulator-runtimes
• CocoaPods version 1.17.0
[✓] Chrome - develop for the web [4ms]
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[!] Proxy Configuration [3ms]
• HTTP_PROXY is set
! NO_PROXY is not set
[✓] Connected devices
• Device names and identifiers redacted.
[✓] Network resources [1,707ms]
• All expected network resources are available.
! Doctor found issues in 3 categories.Dart Version
3.12.2 stable, macos_arm64.
Steps to Reproduce
Consume one event using response.data!.stream.first, or cancel its subscription, without cancelling the request's optional CancelToken. The consumer is finished but the wrapper keeps its subscription to the adapter response.
import 'dart:async';
import 'dart:typed_data';
import 'package:dio/dio.dart';
class StreamingAdapter implements HttpClientAdapter {
StreamingAdapter(this.source);
final StreamController<Uint8List> source;
@override
Future<ResponseBody> fetch(RequestOptions options,
Stream<Uint8List>? requestStream, Future<void>? cancelFuture) async =>
ResponseBody(source.stream, 200);
@override
void close({bool force = false}) {}
}
Future<void> main() async {
var cancelCount = 0;
final source = StreamController<Uint8List>(onCancel: () => cancelCount++);
final dio = Dio()..httpClientAdapter = StreamingAdapter(source);
final response = await dio.get<ResponseBody>(
'https://example.test/stream',
options: Options(responseType: ResponseType.stream),
);
final first = response.data!.stream.first;
source.add(Uint8List.fromList([1]));
print(await first);
print('source.hasListener: ${source.hasListener}, cancelCount: $cancelCount');
// Actual: true, 0. Expected: false, 1.
unawaited(source.close());
dio.close();
}Expected Result
Consumer cancellation should cancel the source response subscription, release adapter resources, stop receive-progress/timeout work, and complete its cancellation future after asynchronous source cleanup finishes.
Actual Result
The source remains subscribed. handleResponseStream propagates pause/resume but has no consumer onCancel cleanup. Normal stream completion, explicit CancelToken cancellation, and timeout handling are separate existing paths.
Four new public-entry regressions fail against unchanged production code: .first, direct cancellation, pause followed by cancellation, and waiting for asynchronous upstream cleanup. The first three observe source.hasListener == true; the last finds that cleanup did not start. This can leave streaming responses active after a page stops consuming them. No claim of measured battery, TCP, or production-memory impact is made.
A focused fix and regression coverage are being prepared. The earlier CancelToken fixes and pause/resume work are different cancellation boundaries.
Activity
github-actions commentedon Oct 4, 2026
@kaluli123123 Infra and blank issues are only available for moderators. You're apparently using the wrong issue template.
fix(dio): release response streams when consumers cancel