Skip to content

CUST-4514 added handling for non-json responses and tests#424

Open
samuelpx wants to merge 12 commits into
mainfrom
CUST-4514-python-sdk-handle-non-json-responses-html-fastly-empty-etc-stemming-from-500-s
Open

CUST-4514 added handling for non-json responses and tests#424
samuelpx wants to merge 12 commits into
mainfrom
CUST-4514-python-sdk-handle-non-json-responses-html-fastly-empty-etc-stemming-from-500-s

Conversation

@samuelpx
Copy link
Copy Markdown
Contributor

License

I confirm that this contribution is made under the terms of the MIT license and that I have the authority necessary to make this contribution on behalf of its copyright owner.

…es-html-fastly-empty-etc-stemming-from-500-s
…es-html-fastly-empty-etc-stemming-from-500-s
Comment thread nylas/models/errors.py Outdated
"""

request_id: str
request_id: Optional[str]
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.

I don't believe this is ever optional for our API effors

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks, I'll correct this!

Comment thread nylas/models/errors.py
self.headers: CaseInsensitiveDict = headers


class NylasNetworkError(AbstractNylasSdkError):
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.

Where are we actually utilizing this new error?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Nowhere yet, the idea is that it will replace the proposed non-json handling implementation in the future, we currently raise a NylasApiError to keep backwards compatibility as a priority, let me know if we should just use this instead.

@playerzero-ai
Copy link
Copy Markdown

playerzero-ai Bot commented Aug 28, 2025

Pull Request Summary

  • Error Handling Enhancements:

    • Made certain attributes optional in error classes to allow more flexible error handling.
    • Introduced a new NylasNetworkError class to better handle non-JSON responses, capturing additional error details like raw_body and flow_id.
  • HTTP Client Improvements:

    • Enhanced error messages for non-JSON responses with status codes 400 or higher, including a preview of the response body and Fastly flow ID.
    • Refactored exception handling for OAuth and API errors for improved code readability and maintainability.
    • Made minor cosmetic changes to method signatures without affecting functionality.
  • Testing Enhancements:

    • Added tests for various HTTP error scenarios, including non-JSON responses, empty responses, and different content types.
    • Focused on improving error handling for HTTP status codes like 500, 502, 503, and 504, with and without "flow_id" headers.
    • Ensured the system can handle a range of non-JSON response types and edge cases, enhancing the reliability and error reporting of the HTTP client.

Functional Tests

  • Verify that non-JSON responses with status codes 400 or higher include a preview of the response body and Fastly flow ID in the error message.
  • Test the handling of a 500 error with an HTML response, ensuring the flow ID is extracted from headers if present.
  • Check the error message clarity for a 502 error with a plain text response.
  • Ensure successful handling of a 200 response with non-JSON content, verifying correct processing of response headers.
  • Test error detection for a 500 error with an empty response body.
  • Verify that long non-JSON responses are truncated in error messages for readability.
  • Check error handling when specific headers like a flow ID are present, ensuring they are included in error messages.
  • Ensure proper error reporting for scenarios missing a flow ID header.
  • Validate error handling consistency across different content types (HTML, plain text, XML, CSS) in 500 error responses.

Files Changed

File Name Summary
nylas/models/errors.py Made request_id, status_code, and headers optional in error classes. Added NylasNetworkError for non-JSON error responses with extra attributes (raw_body, flow_id) to improve network error reporting.
nylas/handler/http_client.py Enhanced error handling for non-JSON responses with status ≥400 by including response preview and Fastly flow ID. Refactored OAuth and API error exception raising for readability. Minor formatting fix in _execute_download_request signature. No changes to query parameter building.
tests/handler/test_http_client.py Added tests covering non-JSON error responses (500, 502, 503, 504), success with non-JSON, empty and long responses, and various content types to improve HTTP client error handling and reporting robustness.

View more in PlayerZero
updated: Aug 28 @ 03:27 AM UTC

…es-html-fastly-empty-etc-stemming-from-500-s
…es-html-fastly-empty-etc-stemming-from-500-s
@playerzero-ai
Copy link
Copy Markdown

playerzero-ai Bot commented Sep 26, 2025

nylas + PlayerZero

Simulations

Project Branch Status Updated (UTC)
nylas CUST-4514-python-sdk-handle-non-json-responses-html-fastly-empty-etc-stemming-from-500-s -> main Error 0/8 passed Sep 26 @ 08:39 PM UTC

View more in PlayerZero
updated: Sep 26 @ 08:39 PM UTC

…es-html-fastly-empty-etc-stemming-from-500-s
Copy link
Copy Markdown
Contributor

@AaronDDM AaronDDM left a comment

Choose a reason for hiding this comment

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

Solid direction — handling non-JSON 4xx/5xx responses fixes a real pain point. A few things to address before merging:

  1. CHANGELOG entry is under v6.10.0 (already released). Move it to an Unreleased section so it shows up in the next release notes.
  2. Multi-line f-string in the error message produces ugly literal indentation (24 spaces of leading whitespace on each subsequent line). See inline comment.
  3. NylasNetworkError is declared but never raised anywhere. Either wire it up or remove it; dead code is confusing (this was flagged back in June and is still unresolved).
  4. AbstractNylasSdkError fields made Optional — already flagged in the earlier review. request_id/status_code/headers are not optional for genuine API errors; weakening these types just to satisfy the network-error path regresses type safety for the main flow. Prefer keeping them required on AbstractNylasSdkError and let NylasNetworkError (once wired up) override with Optional.
  5. Tests assert exact whole-message strings, which couples them to the indentation-bug formatting. Once #2 is fixed every test will break; assert on substrings (status code, flow_id, body excerpt) instead.
  6. Silent return ({}, response.headers) on non-JSON 2xx — minor, but worth a debug log so this doesn't silently mask a malformed-but-successful response.

Comment thread CHANGELOG.md

v6.10.0
----------------
* Added handling for non-JSON responses
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.

This entry is under v6.10.0, which has already been released. Please move it under an Unreleased section at the top so it lands in the next release notes.

type="network_error",
message=f"""
HTTP {response.status_code}: Non-JSON response received{flow_info}.
Body: {body_preview}""",
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.

The triple-quoted f-string inlines the source indentation into the error message, so the rendered text looks like:


                        HTTP 500: Non-JSON response received (flow_id: ...).
                        Body: ...

That'll look awful in logs and stack traces. Either collapse to a single line:

message=f"HTTP {response.status_code}: Non-JSON response received{flow_info}. Body: {body_preview}"

or use textwrap.dedent + .strip(). The existing tests assert on the indented string, so they'll need updating too — ideally to substring assertions.

status_code=response.status_code,
headers=response.headers,
) from exc
return ({}, response.headers)
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.

Silently returning ({}, headers) for a 2xx non-JSON body could mask a real problem (e.g. a malformed JSON body that happens to come back with 200). At minimum add a debug log; better, consider raising for unexpected non-JSON success too, since every JSON endpoint in this SDK should return parseable JSON.

Comment thread nylas/models/errors.py
self.headers: CaseInsensitiveDict = headers
self.request_id: Optional[str] = request_id
self.status_code: Optional[int] = status_code
self.headers: Optional[CaseInsensitiveDict] = headers
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.

Per the earlier review thread — these shouldn't become Optional on the base class. Genuine API errors always have a status_code and headers. Keep them required here and let NylasNetworkError declare its own Optionals if needed.

Comment thread nylas/models/errors.py
self.status_code: Optional[int] = status_code
self.raw_body: Optional[str] = raw_body
self.headers: Optional[CaseInsensitiveDict] = headers
self.flow_id: Optional[str] = flow_id
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.

This class is defined but never instantiated. Either raise it from _validate_response instead of (or alongside) NylasApiError, or drop it from this PR and add it when the v7.0 work lands. Right now it's just dead code and a maintenance trap.

response.headers = {"Content-Type": "text/html", "x-fastly-id": "fastly-123"}

with pytest.raises(NylasApiError) as e:
_validate_response(response)
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.

These assert str(e.value) == """...""" checks pin the exact whitespace of the error string and will all break once the multi-line f-string is fixed. Recommend asserting on substrings, e.g.:

assert "HTTP 500" in str(e.value)
assert "flow_id: fastly-123" in str(e.value)
assert "<h1>Internal Server Error</h1>" in str(e.value)

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.

2 participants