Skip to content

Developer should throw custom exception in interceptor #1950

Open

Description

@WutangNailao

Request Statement

When i write a interceptor class extends Interceptor, in some case, i wish throw some exception to tell the developer some thing went wrong. so i throw a custom exception in override function 'onResponse', but this exception was catched by DioException, and this exception can not tell me more infomation about this error.

image
image

So, i wish this will be supported

Solution Brainstorm

No response

Activity

  1. ueman commented on Sep 1, 2023

    @ueman
    Contributor

    This makes a lot of sense.

    I think we either should properly wrap the exception, or we shouldn't wrap it at all.

  2. kuhnroyal commented on Sep 1, 2023

    @kuhnroyal
    Member

    I think we do.

    Just from looking at the screens, the reported exception probably originated at the jsonDecode.

  3. AlexV525 commented on Sep 15, 2023

    @AlexV525
    Member

    These (#1949) are quite similar which requires a nicer first-look regarding the exception.

  4. kuhnroyal commented on Sep 15, 2023

    @kuhnroyal
    Member

    Adding request information to the exception is one thing. Figuring out a sensible way to convert arbitrary exceptions/objects into strings is another. Any ideas for this? We call toString() on the inner error but we don't always pass a message to the DioException - that is why it says [unknown]: null.

  5. brian030128 commented on Sep 30, 2023

    @brian030128
    Contributor

    DioException has a error field, this is probably what you're looking for?

    /// The original error/exception object;
    /// It's usually not null when `type` is [DioExceptionType.unknown].
    final Object? error;

  6. AlexV525 commented on Oct 14, 2023

    @AlexV525
    Member

    Based on the above comments, the root cause of the exception is the JSON fails to be decoded before it reaches your exception, so a FormatException was thrown. Otherwise, it would be DioException(APIException).

    Closing as it's working as intended.

  7. added
    i: wontfixThis will not be worked on
    and removed
    s: featureThis issue indicates a feature request
    on Oct 14, 2023
  8. WutangNailao commented on Oct 21, 2023

    @WutangNailao
    Author

    it's my wrong, i show a wrong example.
    this is a good example i think for my issue.
    image
    image

    when i get a response with code 401, i throw a apiexception, in the terminal, i see which i throwed apiexception, but it wrapped with dioException, so i can't not catch this error exactly next time.

  9. added
    s: featureThis issue indicates a feature request
    p: dioTargeting `dio` package
    and removed
    i: wontfixThis will not be worked on
    on Oct 24, 2023
  10. kuhnroyal commented on Nov 3, 2023

    @kuhnroyal
    Member

    Not sure how we can achieve that other than the developer registering custom types somewhere.

  11. trongtindev commented on Jan 18, 2025

    @trongtindev

    Is there any temporary solution? :(

  12. ZhZhZhen commented on Feb 16, 2025

    @ZhZhZhen

    It would be great if the custom error thrown in the interceptor could be caught in the onError of Future.then(onData, onError), but currently, I don't know why it can't be caught. I'm not very familiar with Dart yet and don't know how to handle it.

  13. kuhnroyal commented on Feb 26, 2025

    @kuhnroyal
    Member

    Maybe we can add something like DioException.custom(MyCustomError()) and unwrap this later?

  14. radomir9720 commented on May 19, 2025

    @radomir9720

    Maybe we can add something like DioException.custom(MyCustomError()) and unwrap this later?

    Sounds like a solution, since there are no other proposals. Waiting for this feature.

  15. radomir9720 commented on May 19, 2025

    @radomir9720

    Is there any temporary solution? :(

    There is. For example, a straightforward one:

    import 'package:dio/src/dio/dio_for_native.dart';
    
    final class CustomExceptionDio extends DioForNative {
      CustomExceptionDio([super.baseOptions]);
    
      @override
      Future<Response<T>> fetch<T>(RequestOptions requestOptions) async {
        try {
          return await super.fetch<T>(requestOptions);
        } catch (e) {
          if (e is DioException) {
            final customException = e.error;
            if (customException != null) throw customException;
          }
    
          rethrow;
        }
      }
    }
    

    Then, instead of Dio() constructor use CustomExceptionDio().

    P. S. Don't forget that a instance of DioForNative won't work on web. For web you'll need to do the same trick with DioForBrowser, then use the conditional import to decide which instance to create depending on the platform you're program runs on(exactly like Dio() constructor does under the hood)

    Interceptor example:

    final class ExceptionMapperInterceptor extends Interceptor {
      const ExceptionMapperInterceptor();
      @override
      void onError(DioException err, ErrorInterceptorHandler handler) {
        final statusCode = err.response?.statusCode;
        if (statusCode != null && statusCode >= HttpStatus.internalServerError) {
          return handler.reject(
            DioException(
              error: MyCustomException(), // <- Here you pass your exception
              requestOptions: err.requestOptions,
            ),
          );
        }
        handler.next(err);
      }
    }
    
  16. theprantadutta commented on May 12, 2026

    @theprantadutta

    Hi @kuhnroyal @AlexV525 — would it be useful if I took this on? My plan, based on @kuhnroyal's sketch upthread:

    1. Add a way to throw a custom exception from inside an Interceptor and have the caller receive the original error rather than an opaque DioException. Initial API shape: a DioException.custom(error, {stackTrace, response, requestOptions}) factory whose wrapped error is accessible via DioException.error (already exists on the class).
    2. Update the interceptor error path so that when a user throws a non-DioException from onRequest / onResponse / onError, it's wrapped into DioException.custom(...) instead of being swallowed into a generic DioException with no preserved original.
    3. Add tests for all three interceptor callback throw paths, verifying the caller can recover the original exception type.

    Happy to defer if someone's already on this, or adjust the API shape (e.g., a new property on DioException rather than a .custom(...) factory, or a different name) if you'd prefer.

  17. AlexV525 commented on May 14, 2026

    @AlexV525
    Member

    Happy to defer if someone's already on this, or adjust the API shape (e.g., a new property on DioException rather than a .custom(...) factory, or a different name) if you'd prefer.

    @realmeylisdev (with AI) seems to be working on it, but the PR got closed due to the repo being deleted.

  18. realmeylisdev commented on May 14, 2026

    @realmeylisdev

    Picked this back up — opened #2514 with the design previously sketched by @kuhnroyal here (#1950 (comment)) and prototyped in the closed #2484.

    Scope of #2514:

    • New DioException.custom(...) factory + propagateInnerError flag (default false).
    • New rejectCustomError(...) helper on RequestInterceptorHandler, ResponseInterceptorHandler, ErrorInterceptorHandler.
    • Single unwrap point in DioMixin.fetch() using Error.throwWithStackTrace.
    • Strict opt-in: every existing on DioException catch (e) keeps working unchanged (verified by a regression sentinel test).
    • 9 new tests covering all three handlers, direct-throw, copyWith, QueuedInterceptor, and the regression sentinel.

    Happy to iterate on naming or anything else during review.

  19. theprantadutta commented on May 14, 2026

    @theprantadutta

    Thanks @AlexV525 for the heads-up, and great to see you back on this @realmeylisdev — all yours. I'll bow out cleanly. Good luck with #2514!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    e: PR welcomedp: dioTargeting `dio` packages: featureThis issue indicates a feature request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions