Skip to content

fix(http-client-python): raise azure-core error types for customized errors covering standard status codes#10998

Draft
l0lawrence wants to merge 1 commit into
microsoft:mainfrom
l0lawrence:l0lawrence/python-custom-error-status-mapping
Draft

fix(http-client-python): raise azure-core error types for customized errors covering standard status codes#10998
l0lawrence wants to merge 1 commit into
microsoft:mainfrom
l0lawrence:l0lawrence/python-custom-error-status-mapping

Conversation

@l0lawrence

Copy link
Copy Markdown
Member

Problem

When a TypeSpec operation declares a customized error model that covers one of the standard azure-core status codes (401, 404, 409, 304), the Python emitter did not always raise the dedicated azure-core error type:

  • Ranged error (e.g. 4XX) covering a standard code → fell through to a generic HttpResponseError.
  • Default error model (covers all non-success codes) → raised the typed error (via map_error) but without the deserialized error body.

Fix

For status codes 401 → ClientAuthenticationError, 404 → ResourceNotFoundError, 409 → ResourceExistsError, 304 → ResourceNotModifiedError, the generated client now deserializes the customized error body first and then raises the dedicated azure-core error type with that body attached.

  • Ranged custom error: emit typed raises for standard codes within the range, after deserialization.
  • Default custom error: exclude the standard codes from error_map (so map_error doesn't pre-empt), deserialize the default body, then raise the typed error with the body. Codes already handled inline by a non-default error are skipped to avoid dead code.
  • Single/multi specific-code custom errors and the no-custom-error path are unchanged.

Example generated output (ranged + default)

if response.status_code not in [204]:
    map_error(status_code=response.status_code, response=response, error_map=error_map)
    error = None
    if 494 <= response.status_code <= 499:
        error = _failsafe_deserialize(_models.ErrorInRange, response)
    else:
        error = _failsafe_deserialize(_models.DefaultError, response)
    if response.status_code == 401:
        raise ClientAuthenticationError(response=response, model=error)
    if response.status_code == 404:
        raise ResourceNotFoundError(response=response, model=error)
    if response.status_code == 409:
        raise ResourceExistsError(response=response, model=error)
    if response.status_code == 304:
        raise ResourceNotModifiedError(response=response, model=error)
    raise HttpResponseError(response=response, model=error)

Validation

  • Regenerated all Azure + unbranded spector specs (181 specs, 0 failures).
  • response-status-code-range mock-api tests pass (sync + async, 4/4), exercising both an in-range code and the single 404 → ResourceNotFoundError with the custom body.
  • Added a fix changelog entry for @typespec/http-client-python.

@microsoft-github-policy-service microsoft-github-policy-service Bot added the emitter:client:python Issue for the Python client emitter: @typespec/http-client-python label Jun 16, 2026
@pkg-pr-new

pkg-pr-new Bot commented Jun 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/http-client-python@10998

commit: 5a0ec04

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

  • @typespec/http-client-python
Show changes

@typespec/http-client-python - fix ✏️

Always populate the operation error_map with the standard azure-core error types (401 → ClientAuthenticationError, 404 → ResourceNotFoundError, 409 → ResourceExistsError, 304 → ResourceNotModifiedError), even when a customized error model covers those status codes. Previously, a standard status code covered by a customized ranged or default error model fell back to a generic HttpResponseError; it now raises its dedicated error type via map_error. The customized error body continues to be deserialized and attached to the HttpResponseError raised for other (non-standard) status codes.

@azure-sdk-automation

azure-sdk-automation Bot commented Jun 16, 2026

Copy link
Copy Markdown

You can try these changes here

🛝 Playground 🌐 Website 🛝 VSCode Extension

@iscai-msft iscai-msft left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this is too complicated, we can just make sure we still generate the error map like here. map_error should handle throwing the correct error bc it takes in the error map that we pass it, so we don't need to specifically raise ResourceNotFoundError etc later in the code. Then keep the part that make sure the deserialization model correctly maps to the status code, like in the generated code here.

…errors covering standard status codes

Always populate the operation error_map with the standard azure-core error types (401 -> ClientAuthenticationError, 404 -> ResourceNotFoundError, 409 -> ResourceExistsError, 304 -> ResourceNotModifiedError), even when a customized error model covers those status codes via a ranged or default error response. map_error then raises the dedicated error type instead of falling back to a generic HttpResponseError. The customized error body continues to be deserialized and attached to the HttpResponseError raised for other (non-standard) status codes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@l0lawrence l0lawrence force-pushed the l0lawrence/python-custom-error-status-mapping branch from 57cf0b7 to 5a0ec04 Compare June 16, 2026 22:07
@l0lawrence

Copy link
Copy Markdown
Member Author

I think this is too complicated, we can just make sure we still generate the error map like here. map_error should handle throwing the correct error bc it takes in the error map that we pass it, so we don't need to specifically raise ResourceNotFoundError etc later in the code. Then keep the part that make sure the deserialization model correctly maps to the status code, like in the generated code here.

If error_map has the error then doesn't map_error raise before we deserialize the body

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

Labels

emitter:client:python Issue for the Python client emitter: @typespec/http-client-python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants