Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dio is not catching SocketException: Failed host lookup #1869

Closed
busslina opened this issue Jun 15, 2023 · 37 comments
Closed

Dio is not catching SocketException: Failed host lookup #1869

busslina opened this issue Jun 15, 2023 · 37 comments

Comments

@busslina
Copy link
Contributor

busslina commented Jun 15, 2023

Package

dio

Version

5.2.0+1

Output of flutter doctor -v

[✓] Flutter (Channel stable, 3.10.0, on Microsoft Windows [Versi¢n 10.0.19045.3086], locale es-ES)
    • Flutter version 3.10.0 on channel stable at C:\xxxxxxxxxxxx\flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 84a1e904f4 (5 weeks ago), 2023-05-09 07:41:44 -0700
    • Engine revision d44b5a94c9
    • Dart version 3.0.0
    • DevTools version 2.23.1

[✓] Windows Version (Installed version of Windows is version 10 or higher)

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
    • Android SDK at C:\Users\xxxxxxxx\AppData\Local\Android\Sdk
    • Platform android-33, build-tools 30.0.3
    • ANDROID_HOME = C:\Users\xxxxxxxxxxx\AppData\Local\Android\Sdk
    • ANDROID_SDK_ROOT = C:\Users\xxxxxxxxxx\AppData\Local\Android\Sdk
    • Java binary at: C:\Program Files\Android\Android Studio\jbr\bin\java
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
    • All Android licenses accepted.

[✓] Chrome - develop for the web
    • Chrome at C:\Program Files (x86)\Google\Chrome\Application\chrome.exe

[✓] Visual Studio - develop for Windows (Visual Studio Community 2022 17.4.4)
    • Visual Studio at C:\Program Files\Microsoft Visual Studio\2022\Community
    • Visual Studio Community 2022 version 17.4.33213.308
    • Windows 10 SDK version 10.0.20348.0

[✓] Android Studio (version 2022.1)
    • Android Studio at C:\Program Files\Android\Android Studio
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)

[✓] IntelliJ IDEA Community Edition (version 2021.1)
    • IntelliJ at C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.3.2
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart

[✓] VS Code (version 1.79.1)
    • VS Code at C:\Users\xxxxxxxxxx\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 3.66.0

[✓] Connected device (4 available)
    • 2201117SY (mobile) • MJG65DR4VGHMLRXC • android-arm64  • Android 12 (API 31)
    • Windows (desktop)  • windows          • windows-x64    • Microsoft Windows [Versi¢n 10.0.19045.3086]
    • Chrome (web)       • chrome           • web-javascript • Google Chrome 107.0.5304.88
    • Edge (web)         • edge             • web-javascript • Microsoft Edge 113.0.1774.42

[✓] Network resources
    • All expected network resources are available.

• No issues found!

Dart Version

3.0.0

Steps to Reproduce

I'm executing a 300 Mb file download on my physical mobile device and interrupting it at some point (maybe at 20%) by switching on the air-plane mode. It works okay, it try to resume download after 5 seconds delay. Then the problem occurs. When executing get method again, SocketException: Failed host lookup get thrown. The normal behaviour should be to be catched by try/catch clause, but it isn't. As I can see in the Stack Trace I think it is due to an asynchronous gap not being handled (catched). Key part is around ([07]:) section

import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'dart:typed_data';

import 'package:dio/dio.dart';

// Links
//
// - https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests
// - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range
// - https://api.flutter.dev/flutter/dart-typed_data/Uint8List-class.html
// - https://www.nginx.com/blog/smart-efficient-byte-range-caching-nginx/

extension DioExtension on Dio {
  // Functions
  //
  // - 01 - Range download

  //#region
  /// 01 - Range download.
  Future<Return<dynamic, RangeDownloadError>> rangeDownload({
    required String url,
    required File targetFile,
    bool ignoreTargetFilePreviousContent = false,
    int bufferSize = 1024 * 1024, // 1 Megabyte
    StreamController<double>? progressStreamController,
    StreamController<int>? retryingStreamController,
    RangeDownloadRetry retry = RangeDownloadRetry.noRetry,
  }) async {
    // [01]: Getting http head info
    final headInfo = await url.getHttpHeadInfo(this);

    // [02]: Error checking
    {
      // (01)
      if (headInfo == null) {
        return Return.error(
          'Failed to retrieve remote resource HEAD info',
          RangeDownloadError.headInfo,
        );
      }

      // (02)
      if (headInfo.contentLength == null) {
        return Return.error(
          'Remote resource HEAD info does not contain Content Length',
          RangeDownloadError.contentLength,
        );
      }

      // (03)
      if (headInfo.rangeFeatureEnabled == null) {
        return Return.error(
          'Remote resource HEAD info does not Range Feature Enabled',
          RangeDownloadError.rangeFeature,
        );
      }

      // (04)
      if (!headInfo.rangeFeatureEnabled!) {
        return Return.error(
          'Remote resource does not support Range Feature',
          RangeDownloadError.rangeFeatureNotSupported,
        );
      }

      // (05)
      if (!ignoreTargetFilePreviousContent && targetFile.existsSync()) {
        final length = targetFile.lengthSync();

        // [A]: Seems to be yet full downloaded
        if (length == headInfo.contentLength!) {
          return Return(success: true);
        }

        // [B]: Seems that target file is corrupted
        if (length > headInfo.contentLength!) {
          return Return.error(
            'Target file seems to be corrupted',
            RangeDownloadError.corruptedTargetFile,
          );
        }
      }
    }

    // [03]: Getting target file length
    final targetFileLength =
        !ignoreTargetFilePreviousContent && targetFile.existsSync()
            ? targetFile.lengthSync()
            : null;

    // [04]: Opening file to write
    final sink = targetFile.openWrite(
      mode: ignoreTargetFilePreviousContent
          ? FileMode.writeOnly
          : FileMode.writeOnlyAppend,
    );

    // [05]: Calculating initial range values
    int rangeStart = targetFileLength ?? 0;
    int rangeEnd = min(
      rangeStart + bufferSize - 1,
      headInfo.contentLength! - 1,
    );

    // [06]: Streaming base progress
    double progress = -1;
    if (progressStreamController != null) {
      progress =
          ((rangeStart / headInfo.contentLength!) * 100).withFractionDigits();

      progressStreamController.add(progress);
    }

    // [07]: Iterating until full content is downloaded
    {
      bool initialSuccess = false;
      int retryCount = 0;

      while (true) {
        // (01) Sending response
        Response? response;
        dynamic error;
        try {
          response = await get(
            url,
            onReceiveProgress: (count, total) {
              // Streaming progress update
              if (progressStreamController != null) {
                final newProgress =
                    (((rangeStart + count) / headInfo.contentLength!) * 100)
                        .withFractionDigits();
                if (newProgress != progress) {
                  progress = newProgress;
                  progressStreamController.add(progress);
                }
              }
            },
            options: Options(
              headers: {
                'range': 'bytes=$rangeStart-$rangeEnd',
              },
              responseType: ResponseType.bytes,
            ),
          );
        } catch (e) {
          error = e;
        }
        // } on DioError catch (e) {
        //   error = e;
        // }

        // (02) Failure
        if (error != null || !response!.successPartialContent) {
          // [A]: Retrying
          if (retry == RangeDownloadRetry.retry ||
              (retry == RangeDownloadRetry.retryAfterSuccess &&
                  initialSuccess)) {
            // Streaming retry attempt
            retryingStreamController?.add(retryCount++);

            // Delay
            await delay(const Duration(seconds: 5));

            continue;
          }

          // [B]: Aborting with error
          {
            // Unexpected error
            if (error != null) {
              return Return.error(
                'Unexpected error: ${error!}',
                RangeDownloadError.unexpectedError,
              );
            }

            // Unexpected status code
            return Return.error(
              'Response failed with status code: ${response!.statusCode}. Expected success partial content (206)',
              RangeDownloadError.unexpectedStatusCode,
            );
          }
        }

        // (03) Response success
        initialSuccess = true;

        // (04) Data
        final Uint8List data = response.data;

        // (05) Writing data
        sink.add(data);

        // (06) Checking finished
        if (rangeEnd == headInfo.contentLength! - 1) {
          break;
        }

        // (07) Recalculating range values
        rangeStart = rangeEnd + 1;
        rangeEnd = min(
          rangeStart + bufferSize - 1,
          headInfo.contentLength! - 1,
        );
      }
    }

    // [08]: Flushing
    await sink.flush();

    // [09]: Closing
    await sink.close();

    return Return(success: true);
  }
  //#endregion
}

Expected Result

See "Steps to Reproduce"

Actual Result

SocketException (SocketException: Failed host lookup: 'xxxxxxxxxxxx.com' (OS Error: No address associated with hostname, errno = 7))

imagen

imagen

@busslina busslina added h: need triage This issue needs to be categorized s: bug Something isn't working labels Jun 15, 2023
@busslina
Copy link
Contributor Author

busslina commented Jun 16, 2023

UPDATE I

So I studied the code, added some debug points and changed one code line. Then I can say the trouble is Here:

@override
  Future<ResponseBody> fetch(
    RequestOptions options,
    Stream<Uint8List>? requestStream,
    Future<void>? cancelFuture,
  ) async {
    if (_closed) {
      throw StateError(
        "Can't establish connection after the adapter was closed!",
      );
    }
    final operation = CancelableOperation.fromFuture(_fetch(
      options,
      requestStream,
      cancelFuture,
    ));
    if (cancelFuture != null) {
      cancelFuture.whenComplete(() => operation.cancel());
    }
    return operation.value;
  }

If the future wrapped onto CancelableOperation.fromFuture throw an error, this error seems to not being propagated down.
So I managed to propagate down (**) the error by calling Future's catchError method:

final operation = CancelableOperation.fromFuture(_fetch(
      options,
      requestStream,
      cancelFuture,
    ).catchError((error) {
      print('IOHttpClientAdapter.fetch() -- Future.catchError() -- $error');
    }));

Now, the error is propagated down (badly) and app is not crashing:

imagen

Now, the problem is that I'm not returning the appropiate object type on catchError method, that must be ResponseBody. But this is your job, HTTP specialized army.

NOTE that this bug (!?) may be found on other parts of the library. And as my logic can encompass, all kind of error must be catchable by end user. I had this problem with other Dart libraries and their owners had difficulties to understand this simple point. I hope you are not the same case.

** Not really propagating down, but at least catching it

@kuhnroyal
Copy link
Member

I think I broke this in a recent change for the request aborting. Will take a look later.

@kuhnroyal
Copy link
Member

As far as I can tell, this behaves the same way as it has before. I am not saying this is good or ideal but then it is not a bug and we need to discuss if and how we want to change this in a breaking release.

Do you have a different experience in a <5.2.0 version? If so, I need a reproducible sample.

@busslina
Copy link
Contributor Author

busslina commented Jun 16, 2023

As far as I can tell, this behaves the same way as it has before. I am not saying this is good or ideal but then it is not a bug and we need to discuss if and how we want to change this in a breaking release.

Do you mean with "behave" to not be able to catch any possible error, that make the app crash, by the final user? If so, it is clearly unacceptable. If you know a way to catch these errors, then no breaking release is needed. They are mostly OS errors that other HTTP libraries like Dart HttpClient (re)throw so the final client is able to catch it. As I understand Dio is not (re)throwing some errors like Host Lookup so the only way is app crashing. Let's take a think over there because it simply unacceptable.

Do you have a different experience in a <5.2.0 version? If so, I need a reproducible sample.

No, I have not tried this before.

I'm not saying that it has to be changed this or that. Only the simple fact that all these errors have to be a way to catch them. It is simple logic

@busslina
Copy link
Contributor Author

I opened this linked issue on CancelableOperation home Repo.

dart-lang/async#246

@kuhnroyal
Copy link
Member

Do you have a different experience in a <5.2.0 version? If so, I need a reproducible sample.

No, I have not tried this before.

If you have a reproducible case, please try on 5.1.x - the use of the CancelableOperation was introduced in 5.2.0.
It is important to know if this behaves the same in pre/post this change.

If this causes your "app" to crash, maybe you can try to register an uncaught exception handler via runZonedGuarded.

@alexcode9
Copy link

I can confirm this is happening, it's really easy to reproduce for me just try to connect to a non existing host.
This also disrupts any interceptor chain.

@kuhnroyal
Copy link
Member

The following test is successful:

      test(
        'SocketException on request',
        () async {
          final dio = Dio(BaseOptions()..baseUrl = 'https://does.not.exist')
            ..httpClientAdapter = IOHttpClientAdapter();

          await expectLater(
            dio.get(
              '/test',
              data: 'test',
            ),
            throwsA(allOf([
              isA<DioException>(),
              (DioException e) => e.type == DioExceptionType.unknown,
              (DioException e) => e.error is SocketException,
              (DioException e) => (e.error as SocketException)
                  .message
                  .startsWith("Failed host lookup: 'does.not.exist'"),
              (DioException e) =>
                  e.stackTrace.toString().contains('test/stacktrace_test.dart'),
            ])),
          );
        },
        testOn: 'vm',
      );

@busslina
Copy link
Contributor Author

busslina commented Jun 16, 2023

I will try with 5.1.x version.

Also I will make a simple test with CancelableOperation in order to demonstrate that it is not suitable for use because it is breaking the error chain.

UPDATE: Here is the test:

import 'package:async/async.dart';

void main(List<String> arguments) {
  // _test1();
  // _test2();
}

void _test1() {
  final op = CancelableOperation.fromFuture(_getFutureError());

  op.value.then(
    (value) {
      print('Future value: $value');
    },
  ).catchError(
    (error) {
      print('Future catched error: $error');
      return null;
    },
  );
}

void _test2() {
  final op = CancelableOperation.fromFuture(
    _getFutureError().catchError(
      (error) {
        print('Future catched error: $error');
        return null;
      },
    ),
  );

  op.value.then((value) {
    print('Future value: $value');
  });
}

Future<String?> _getFutureError() async {
  // 5 seconds delay
  await Future.delayed(const Duration(seconds: 5));

  // Throwing error
  throw ('Manual triggered test error');
}

_test1() result:
imagen

_test2() result:
imagen

No more questions your honor

Update:

Also not working using CancelableOperation.then method with onError argument. Giving same result: unhandled exception

@busslina

This comment was marked as abuse.

@kuhnroyal
Copy link
Member

There are no notifications when you update a comment, so I didn't even see that you posted anything new. Secondly I am on vacation. It would be great if you can provide a PR with a failing test case, then someone else on the contributors team may be able to provide a fix. I only have a phone.

@AlexV525 AlexV525 reopened this Jun 20, 2023
@AlexV525 AlexV525 added h: need extra help Extra help is needed p: dio Targeting `dio` package b: regression Worked before but not now and removed h: need triage This issue needs to be categorized labels Jun 20, 2023
@busslina
Copy link
Contributor Author

busslina commented Jun 20, 2023

@kuhnroyal apologizes. having a bad day. You ask me for a PR showing a failing case test. I just show you a simple test with 3 methods that shows that CancelableOperation breaks the error chain. So any future wrapped in a CancelableOperation just can't be catched if it throws an error. As simple as that. I put again this test. _test1 shows just that and _test2 shows how if the possible future error is catched before being wrapped into CancelableOperation then the error can be catched. I invite you to execute this simple code. First execute _test1, later execute _test2:

import 'package:async/async.dart';

void main(List<String> arguments) {
  // _test1();
  // _test2();
}

void _test1() {
  final op = CancelableOperation.fromFuture(_getFutureError());

  op.value.then(
    (value) {
      print('Future value: $value');
    },
  ).catchError(
    (error) {
      print('Future catched error: $error');
      return null;
    },
  );
}

void _test2() {
  final op = CancelableOperation.fromFuture(
    _getFutureError().catchError(
      (error) {
        print('Future catched error: $error');
        return null;
      },
    ),
  );

  op.value.then((value) {
    print('Future value: $value');
  });
}

Future<String?> _getFutureError() async {
  // 5 seconds delay
  await Future.delayed(const Duration(seconds: 5));

  // Throwing error
  throw ('Manual triggered test error');
}

@AlexV525
Copy link
Member

I just ran your example (modified prints) and no exceptions are uncaught (see the screenshot).

I'm wondering if this happened because you've enabled settings like "Break on exceptions" (I'm not using VS Code),
image
but that doesn't mean the exception is unhandled, it might only be a difference between how the debugger handles them. At least, eventually, they were all caught by .catchError.

image

@AlexV525 AlexV525 added i: cannot reproduce and removed h: need extra help Extra help is needed labels Jun 20, 2023
@AlexV525
Copy link
Member

When fetching the non-exist host (with "Break on exceptions" enabled):

  1. image
  2. image
  3. image

@busslina
Copy link
Contributor Author

busslina commented Jun 20, 2023

I just added a 3º method. _test1 and _test3 giving me unhandled exception:
imagen

My VSCode, only stops on unhandled exceptions:
imagen

Using last version of async package:
imagen

Can you execute _test3 and report result?

import 'package:async/async.dart';

void main(List<String> arguments) async {
  // _test1();
  // _test2();
  // await _test3();
}

void _test1() {
  final op = CancelableOperation.fromFuture(_getFutureError());

  op.value.then(
    (value) {
      print('Future value: $value');
    },
  ).catchError(
    (error) {
      print('Future catched error: $error');
      return null;
    },
  );
}

void _test2() {
  final op = CancelableOperation.fromFuture(
    _getFutureError().catchError(
      (error) {
        print('Future catched error: $error');
        return null;
      },
    ),
  );

  op.value.then((value) {
    print('Future value: $value');
  });
}

Future<void> _test3() async {
  final op = CancelableOperation.fromFuture(_getFutureError());

  try {
    final value = await op.value;
    print('Future value: $value');
  } catch (e) {
    print('Future catched error: $e');
  }
}

Future<String?> _getFutureError() async {
  // 5 seconds delay
  await Future.delayed(const Duration(seconds: 5));

  // Throwing error
  throw ('Manual triggered test error');
}

@AlexV525
Copy link
Member

Can you execute _test3 and report result?

X:/SDK/flutter-master/bin/cache/dart-sdk/bin/dart.exe --enable-asserts X:\Coding\Garages\Dart\dio\dio\test.dart
Future1 caught error: Manual triggered test error
Future2 caught error: Manual triggered test error
Future2 value: null
Future3 caught error: Manual triggered test error

Process finished with exit code 0

So far, the conclusion is, as I mentioned:

I'm wondering if this happened because you've enabled settings like "Break on exceptions" (I'm not using VS Code), image but that doesn't mean the exception is unhandled, it might only be a difference between how the debugger handles them. At least, eventually, they were all caught by .catchError.

@busslina
Copy link
Contributor Author

busslina commented Jun 20, 2023

@AlexV525 you are right: I deactivate VSCode "Uncught Exepctions" and now it works as desirable.
imagen
imagen

I don't know why? I always use VSCode and it were only stopping on unhandled exceptions. It's weird. Also when I was debugging with my Android mobile device it was stopping with Failed host lookup... It's very weird, compared to the behaviour while executing _test2.

I will retry the test on Mobile Device with this new VSCode configuration and report if it works as expected

@busslina
Copy link
Contributor Author

VSCode related issues:
dart-lang/sdk#47692
dart-lang/sdk#47985

@AlexV525
Copy link
Member

@busslina You may need to follow the error handling article of Flutter to see if they're uncaught in your apps. Prints and logs are sometimes less informative when telling where they came from.

Closing as the issue is not related to the plugin itself. Please provide more information if anyone is requesting to reopen it or submit a new issue if new wrong behavior was found.

@AlexV525 AlexV525 added i: out of support and removed s: bug Something isn't working b: regression Worked before but not now labels Jun 20, 2023
@kuhnroyal
Copy link
Member

It's alright, just try to be nice. We are all giving out best here. I also added tests for this in #1875

@AlexV525
Copy link
Member

To avoid this from the library side, we might need to wait until we bump the min Dart version to 2.17 in the next major version, which can catch those exceptions and rethrow them using Error.throwWithStackTrace. That would narrow the affection brought by asynchronized gaps.

@YiannisBourkelis

This comment was marked as off-topic.

@busslina
Copy link
Contributor Author

busslina commented Aug 27, 2023

@YiannisBourkelis from my experience I can tell you this is a VSCode issue. Whenever it happens you must click on the continue debugging execution button on VSCode and it will work as expected. On the compilated app it will not happen

@alexcode9
Copy link

alexcode9 commented Aug 27, 2023

Try to go back to flutter 3.10.6
I don't usually develop for android but 3.13.1 is broken on desktop platform and has that specific bug.

@YiannisBourkelis
Copy link

@busslina @alexcode9 thank you for your replies. I will work for now with unchecked unhandled exceptions on vscode and I hope it will get fixed in a while.

@josephcrowell
Copy link

Yep this is specific to Flutter 3.13.1 and not actually an issue in Dio.

@shinexoh
Copy link

So is this a bug in the Flutter plugin for Vscode and Android studio? It seems like it hasn't been fixed yet

@josephcrowell
Copy link

josephcrowell commented Nov 28, 2023

So is this a bug in the Flutter plugin for Vscode and Android studio? It seems like it hasn't been fixed yet

I think they traced it back to the dart plugin for VS Code. They seem to only be fixing specific cases but the error in Dio hasn't been covered yet.

dart-lang/sdk#53334
flutter/flutter#137629

@khomin

This comment was marked as off-topic.

@ddxl123
Copy link

ddxl123 commented Dec 19, 2023

尝试连接到无法访问的主机时出现相同的错误

DioException (DioException [connection error]: The connection errored: Connection refused This indicates an error which most likely cannot be solved by the library. Error: SocketException: Connection refused (OS Error: Connection refused, errno = 61), address = myhost.website, port = 54169)

me too

@kuhnroyal
Copy link
Member

I'm getting the same error when trying to connect to an unreachable host

DioException (DioException [connection error]: The connection errored: Connection refused This indicates an error which most likely cannot be solved by the library. Error: SocketException: Connection refused (OS Error: Connection refused, errno = 61), address = myhost.website, port = 54169)

Do you expect to receive something else instead?

@khomin
Copy link

khomin commented Dec 19, 2023

I'm getting the same error when trying to connect to an unreachable host
DioException (DioException [connection error]: The connection errored: Connection refused This indicates an error which most likely cannot be solved by the library. Error: SocketException: Connection refused (OS Error: Connection refused, errno = 61), address = myhost.website, port = 54169)

Do you expect to receive something else instead?

This is an uncaught exception
It cannot be caught using try catch when dio is used

@busslina
Copy link
Contributor Author

You can catch it with runZonedGuarded

https://api.flutter.dev/flutter/dart-async/runZonedGuarded.html

@kuhnroyal
Copy link
Member

This is an uncaught exception It cannot be caught using try catch when dio is used

Do you have any reproducible example? Because this test is green:

  test('GET wrong port', () async {
    final dio = Dio()..options.baseUrl = 'https://httpbun.com:45645/';

    await expectLater(
      dio.get(
        '/get',
      ),
      throwsA(
        isA<DioError>()
            .having(
              (e) => e.type,
              'type',
              equals(DioErrorType.connectionError),
            )
            .having(
              (e) => e.error,
              'error',
              isA<SocketException>().having(
                  (s) => s.message,
                  'message',
                  equals(
                    'Connection refused',
                  )),
            ),
      ),
    );
  });

@khomin
Copy link

khomin commented Dec 20, 2023

This is an uncaught exception It cannot be caught using try catch when dio is used

Do you have any reproducible example? Because this test is green:

Here is my example (linux)
my_app.zip

The main part in:
var info = await _httpsClient?.getJson('$_host/updateTo.json');
It pauses in 'assureDioError'

and only after that i can handle it in 'DioErrorHandler'

Screenshot from 2023-12-20 15-53-35

@AlexV525
Copy link
Member

Due to a known Dart issue with the debugger, we, unfortunately, have to lock this as we cannot take further action about it and it's not related to dio. Please refer to the above comments to track if the Dart team managed to solve this issue. More specifically:

@cfug cfug locked as too heated and limited conversation to collaborators Dec 20, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

9 participants