Skip to content

fix: handle HTTP 429 responses missing the Retry-After header#266

Merged
ayeshurun merged 1 commit into
microsoft:mainfrom
ayeshurun:dev/alonyeshurun/dataflow-create-retry-after
Jul 16, 2026
Merged

fix: handle HTTP 429 responses missing the Retry-After header#266
ayeshurun merged 1 commit into
microsoft:mainfrom
ayeshurun:dev/alonyeshurun/dataflow-create-retry-after

Conversation

@ayeshurun

Copy link
Copy Markdown
Collaborator

✨ Description of new changes

Summary: Long-running operations failing with x [UnexpectedError] retry-after.

Context: When Fabric throttles a request but returns an HTTP 429 without a Retry-After header, the rate-limit handler in fab_api_client.py read the header via direct subscript (response.headers["Retry-After"]). Because requests' CaseInsensitiveDict lowercases keys, this raised KeyError("retry-after"). That error was not caught by the requests.RequestException handler, so it bubbled up to main.py and surfaced as [UnexpectedError] retry-after. Creating a dataflow is a long-running, polling operation that is especially prone to hitting throttling, which is why it reproduced there.

The fix reuses the existing get_polling_interval() helper, which reads the retry-after header case-insensitively and falls back to the default polling interval (10s) when the header is missing or non-numeric. This makes the client resilient to throttled 429s and lets it retry as intended instead of erroring out.

Creating a dataflow (and other long-running, throttling-prone
operations) could fail with "[UnexpectedError] retry-after" when
Fabric returned a 429 without a Retry-After header. The 429 handler
read the header via direct subscript, raising a KeyError that escaped
the request exception handler and surfaced as an unexpected error.

Use the existing get_polling_interval helper, which reads the header
case-insensitively and falls back to the default polling interval when
it is missing or non-numeric.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a4b6c3e7-7425-4fa7-9f0a-ac7e87377ee2
Copilot AI review requested due to automatic review settings July 16, 2026 07:27
@ayeshurun
ayeshurun requested a review from a team as a code owner July 16, 2026 07:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a throttling edge case in fab_api_client.do_request() where HTTP 429 responses without a Retry-After header previously caused an uncaught KeyError("retry-after"), surfacing as an [UnexpectedError] retry-after during long-running/polling operations.

Changes:

  • Update the 429 handling path to use the shared get_polling_interval() helper (header case-insensitive + default fallback).
  • Add a regression test covering a 429 response missing Retry-After, asserting the default interval is used and the request retries.
  • Add a changelog entry documenting the fix.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/fabric_cli/client/fab_api_client.py Switch 429 handling from direct header subscript to get_polling_interval() to avoid KeyError and fallback to defaults.
tests/test_core/test_fab_api_client.py Add test ensuring 429 without Retry-After sleeps for default (10s) and retries successfully.
.changes/unreleased/fixed-20260716-092645.yaml Record the behavior fix in unreleased changelog.

Comment thread src/fabric_cli/client/fab_api_client.py
@ayeshurun
ayeshurun merged commit ff0a77d into microsoft:main Jul 16, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants