Repository navigation
feat(http): add option to retry only unprocessed mutations - #897
Merged
Vincent Biret (baywet) merged 2 commits intoNov 13, 2026
Merged
Vincent Biret (baywet) merged 2 commits into
Vincent Biret (baywet) merged 2 commits into
Conversation
Add RetryHandlerOption.retry_unprocessed_mutations_only. It defaults to False, which keeps the current behavior. When it is True, POST and PATCH requests are retried only after a 429 or 503 response, which indicate the server did not process the request. A 504 is returned to the caller, because the server may already have applied the request and a retry could apply it twice. Other methods are unaffected.
Jackson Smith (jackson-asmith)
requested a review
from a team
as a code owner
November 13, 2026 17:04
There was a problem hiding this comment.
🟡 Changes recommended
The tests lack RedirectHandler–RetryHandler integration coverage to verify that retry restrictions behave correctly across both method-changing and method-preserving redirects.
1 open issue
What changed in this PR
Adds opt-in retry safety to the HTTPX middleware to reduce duplicate POST/PATCH side effects after gateway timeouts, while preserving existing behavior by default.
Changes:
- Adds
retry_unprocessed_mutations_only, defaulting toFalse, with documentation of its safety assumptions. - When enabled, restricts POST/PATCH retries to 429 and 503 responses without changing other methods or existing retry safeguards.
- Adds regression tests for defaults, method/status combinations, later retry attempts, and per-request configuration.
| File | Description |
|---|---|
packages/http/httpx/tests/middleware_tests/test_retry_handler.py |
Adds retry-policy regression tests and a fixture that skips retry delays. |
packages/http/httpx/kiota_http/middleware/retry_handler.py |
Applies the method-specific restriction on each retry decision. |
packages/http/httpx/kiota_http/middleware/options/retry_handler_option.py |
Defines and documents the new opt-in setting. |
Review effort: Balanced
Run RedirectHandler and RetryHandler together with the option on. A POST that a 303 turns into a GET is retried after a 504, and a POST kept by a 307 is not.
|
This was referenced Nov 13, 2026
Vincent Biret (baywet)
approved these changes
Nov 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.




Fixes #896
This ports microsoft/kiota-dotnet#864 to Python. The Go port is microsoft/kiota-http-go#312.
Problem
RetryHandler retries 429, 503 and 504 responses whatever the HTTP method. For POST and PATCH, a retry after a 504 can apply the request twice. A 504 means a gateway stopped waiting, not that the server did nothing, so the first attempt may already have succeeded. With Microsoft Graph's sendMail, this sends the same email twice.
Callers can't avoid this today without turning off retries entirely. RetryHandlerOption.should_retry is a boolean, not a callback, so there's no way to skip retries for some methods short of subclassing the handler.
Change
This adds RetryHandlerOption.retry_unprocessed_mutations_only, matching the .NET option.
The default pipeline runs RedirectHandler before RetryHandler, so the retry handler only sees the request for the current redirect hop and resends exactly that. Checking request.method is therefore always the method being resent. The .NET and Go versions had to account for redirects; this one doesn't.
Tests
test_retry_handler.py has 18 new cases covering:
With the new check removed from should_retry, the 6 tests for the new behavior fail and the other 12 pass. A fixture skips the wait between retries, so the new tests take about 0.1 seconds. For the httpx package, yapf, mypy, pylint and the full test suite (227 tests) pass locally on Python 3.15.