Skip to content

_retryCount is shared between multiple requests making it dangerous to infinite requests #170

Open

Description

@itsUndefined

Describe the bug
Because _retryCount is not local var to _attemptRequest, it's possible to create infinite loops since a new request restarts the _retryCount to 0 for all pending requests.

To Reproduce

  1. Add a shouldAttemptRetryOnResponse that starts a new request with the same intercepted client that succeeds ( e.g. a refresh )
  2. Make an api request that fails all the time and calls shouldAttemptRetryOnResponse
  3. Observe infinite looping

Expected behavior
I expected that after maxRetryAttempts attempts of the original request, the request would be cancelled

Please complete the following information):

  • Flutter version: 3.35.4
  • http_interceptor: 2.0.0

Activity

  1. itsUndefined commented on Sep 26, 2025

    @itsUndefined
    Author

    I fixed the issue locally by changing the method _attemptRequest to the following:

    Future<BaseResponse> _attemptRequest(BaseRequest request,
          {bool isStream = false, int retryCount = 0}) async {
        BaseResponse response;
        try {
          // Intercept request
          final interceptedRequest = await _interceptRequest(request);
    
          var stream = requestTimeout == null
              ? await _inner.send(interceptedRequest)
              : await _inner
                  .send(interceptedRequest)
                  .timeout(requestTimeout!, onTimeout: onRequestTimeout);
    
          response = isStream ? stream : await Response.fromStream(stream);
    
          if (retryPolicy != null &&
              retryPolicy!.maxRetryAttempts > retryCount &&
              await retryPolicy!.shouldAttemptRetryOnResponse(response)) {
            await Future.delayed(retryPolicy!
                .delayRetryAttemptOnResponse(retryAttempt: retryCount + 1));
            return _attemptRequest(request, retryCount: retryCount + 1);
          }
        } on Exception catch (error) {
          if (retryPolicy != null &&
              retryPolicy!.maxRetryAttempts > retryCount &&
              await retryPolicy!.shouldAttemptRetryOnException(error, request)) {
            await Future.delayed(retryPolicy!
                .delayRetryAttemptOnException(retryAttempt: retryCount + 1));
            return _attemptRequest(request, retryCount: retryCount + 1);
          } else {
            rethrow;
          }
        }
    
        return response;
      }

    I also removed the global _retryCount variable.

    I tried to open a PR to fix this on the master branch but I noticed the project is taken over by AI Slop and the code was very different between what's published on pub ( 2.0.0 ) and master.

  2. CodingAleCR commented on Mar 18, 2026

    @CodingAleCR
    Owner

    Yeah, there was an attempt to fix things using AI when it wasn't properly handled. That and the fact that the API decisions made in the past by myself were not the best. It led the library towards something much more cumbersome to maintain. I ended up rewriting most of it, keeping few things and will likely end 2.x version and its (very much lacking) support.

  3. CodingAleCR commented on Mar 18, 2026

    @CodingAleCR
    Owner

    Take a look at #173 if you are still interested, since I know it's been quite a while since you took interest in this 🙏🏼

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

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions