Skip to content

[Bug] The built-in retry never retries the token POST: HTTPAdapter(max_retries=1) keeps urllib3's default allowed_methods #957

Open

Description

@HardMax71

msal/application.py lines 716-718 mount HTTPAdapter(max_retries=1) as "a minimal retry, better than nothing". For the token endpoint it is nothing: urllib3's Retry(1) keeps the default allowed_methods, which excludes POST, so a connection reset during the token request escapes after one attempt as requests.exceptions.ConnectionError.

Repro over a local TLS server that resets the first /token connection (self-signed cert, verify=False, nothing leaves 127.0.0.1): https://gist.github.com/HardMax71/fd1025dc346b2aefe1291e11cc343d8c

msal 1.38.0 | requests 2.33.0 | urllib3 2.7.0
default http_client (HTTPAdapter(max_retries=1)): ConnectionError escaped, connections after discovery=1: ('Connection aborted.', OSError(22, 'Invalid argument'))
custom http_client, Retry(allowed_methods=None): token=yes | connections after discovery=2

Same on 1.37.0. I know #432 settled on retries being an http-layer concern and a custom http_client being the answer, and that is what we run. This is narrower: the adapter MSAL itself mounts does not do what its comment says. HTTPAdapter(max_retries=Retry(total=1, connect=1, allowed_methods=None, backoff_factor=0.3)) keeps the same one-retry budget and makes it real for the POST. Can send the PR.

Activity

  1. 4gust commented on Sep 4, 2026

    @4gust
    Contributor

    Max Azatian (@HardMax71) Thank you for reporting the bug and for raising the PR. I’ll analyze the issue and review the changes, then get back to you with my feedback and findings.

  2. HardMax71 commented on Sep 23, 2026

    @HardMax71
    Author

    Hi Nilesh Choudhary (@4gust), just following up to see if there are any updates on this. Thanks!

  3. HardMax71 commented on Oct 3, 2026

    @HardMax71
    Author

    Updated the repro gist: its fake server closed the socket before reading the whole POST, so the retried request could be reset too, and #958 failed about one run in four for that reason. With the request read in full, #958 passes 30 of 30 and dev still fails every run.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions