Skip to content

fix(http): defensively handle missing optional fields and snake_case keys in HttpRetryOptions.from_json - #353

Closed
Hardik K (hardikkaurani) wants to merge 6 commits into
microsoft:mainfrom
hardikkaurani:fix/http-retry-options-defensive-parsing
Closed

Hardik K (hardikkaurani) wants to merge 6 commits into
microsoft:mainfrom
hardikkaurani:fix/http-retry-options-defensive-parsing

Conversation

@hardikkaurani

Copy link
Copy Markdown
Contributor

Summary of Changes

Closes #351

In azure.durable_functions.http.models.HttpRetryOptions.from_json(), deserialization previously accessed optional retry fields (maxRetryIntervalInMilliseconds, retryTimeoutInMilliseconds, and backoffCoefficient) using direct dictionary subscripting value["..."].

When a wire payload omits these optional fields (for example, when serialized with default options or across language SDK boundaries), from_json() raised KeyError (e.g. KeyError: 'maxRetryIntervalInMilliseconds'), causing the built-in HTTP orchestrator polling loop (builtin_http_poll_orchestrator) to fail during replay.

Furthermore, unlike DurableHttpResponse.from_json() which defensively handles both status_code and statusCode, HttpRetryOptions.from_json() only recognized camelCase keys, rejecting snake_case dictionaries.

This change:

  • Defensively extracts fields with .get(), defaulting backoff_coefficient to 1.0, max_retry_interval to timedelta(days=6) (matching the HttpRetryOptions constructor default when omitted), and preserving explicit None for unbounded intervals.
  • Supports both camelCase and snake_case key naming (first_retry_interval_in_milliseconds, max_number_of_attempts, backoff_coefficient, max_retry_interval_in_milliseconds, retry_timeout_in_milliseconds, and status_codes_to_retry).
  • Adds unit and orchestrator execution tests covering partial wire payloads, explicit None max intervals, and snake_case configurations.

Changes Across Commits

  1. Commit 1: fix(http): handle missing optional fields in HttpRetryOptions.from_json

    • Safely extract maxRetryIntervalInMilliseconds, retryTimeoutInMilliseconds, and backoffCoefficient in HttpRetryOptions.from_json().
  2. Commit 2: fix(http): support snake_case keys in HttpRetryOptions.from_json

    • Add defensive fallback lookup for snake_case dictionary keys across all policy properties.
  3. Commit 3: test(http): verify HttpRetryOptions.from_json with missing optional fields

    • Add unit test verifying that minimal payloads and payloads with explicit None max intervals reconstruct correctly.
  4. Commit 4: test(http): verify HttpRetryOptions.from_json with snake_case keys

    • Add unit test verifying reconstruction from snake_case wire payloads.
  5. Commit 5: docs(http): document defensive payload parsing in HttpRetryOptions.from_json

    • Update docstring in models.py and document the fix in azure-functions-durable/CHANGELOG.md.
  6. Commit 6: test(http): verify orchestrator execution with partial retry options payload

    • Add an execution test verifying that builtin_http_poll_orchestrator successfully runs when provided with a partial retryOptions dictionary.

Verification

  • pytest tests/azure-functions-durable/test_http_retry.py (81/81 passed)
  • ruff check . (All checks passed)

Signed-off-by: Hardik Kaurani <hardikkaurani1@gmail.com>
Signed-off-by: Hardik Kaurani <hardikkaurani1@gmail.com>
…ields

Signed-off-by: Hardik Kaurani <hardikkaurani1@gmail.com>
Signed-off-by: Hardik Kaurani <hardikkaurani1@gmail.com>
…om_json

Signed-off-by: Hardik Kaurani <hardikkaurani1@gmail.com>
…payload

Signed-off-by: Hardik Kaurani <hardikkaurani1@gmail.com>
Copilot AI balanced review requested due to automatic review settings November 10, 2026 22:50

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.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

@hardikkaurani

Copy link
Copy Markdown
Contributor Author

Hi maintainers, Bernd Verst (@berndverst) and andystaples

I've opened this PR to address #351 by making HttpRetryOptions.from_json() more defensive when reconstructing retry policies. It now handles missing optional fields using the appropriate defaults and supports both camelCase and snake_case keys, improving compatibility with partial wire payloads across SDK boundaries.

I've also added regression tests covering missing fields, explicit None values, snake_case configurations, and execution of the HTTP polling orchestrator with partial retry options.

Validation is passing: 81 tests passed, and ruff check . reports no issues.

Whenever you have a moment, I'd appreciate your review and feedback. Thank you!

@berndverst

Bernd Verst (berndverst) commented Nov 11, 2026 •

Copy link
Copy Markdown
Member

Hardik K (@hardikkaurani) we will not accept PRs for issues that have been opened by the PR author just moments earlier.

An issue at minimum requires community discussion or triage from maintainers. No unsolicited PRs please.

We already went over this with your previous contribution: #310 (comment)

The issue requires triage from andystaples or myself (Bernd Verst (@berndverst)) before we will accept a PR.

@berndverst Bernd Verst (berndverst) added question Further information is requested issue not triaged The associated issue has not been triaged yet. Maintainers will not prioritize review of this PR. and removed question Further information is requested labels Nov 11, 2026
@hardikkaurani

Copy link
Copy Markdown
Contributor Author

Hi Bernd Verst (@berndverst),

Thanks for clarifying. I understand your contribution process and acknowledge that I should have waited for maintainer triage and community discussion before opening this PR.

I'll keep this in mind for future contributions and avoid submitting PRs for issues that haven't been discussed or triaged first.

Apologies for overlooking this, and thanks for taking the time to clarify the expectations.

@andystaples

Copy link
Copy Markdown
Contributor

Thanks for the contribution. Closing per the explanation in #351 (comment).

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

Labels

issue not triaged The associated issue has not been triaged yet. Maintainers will not prioritize review of this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HttpRetryOptions.from_json raises KeyError on wire payloads missing optional retry fields or using snake_case keys

4 participants