Skip to content

fix(tools): decode RestApiTool HTTP error bodies with declared charset - #7207

Open
chelsealong wants to merge 1 commit into
google:mainfrom
chelsealong:fix-7206-rest-api-tool-non-utf8-error-body
Open

chelsealong wants to merge 1 commit into
google:mainfrom
chelsealong:fix-7206-rest-api-tool-non-utf8-error-body

Conversation

@chelsealong

Copy link
Copy Markdown
Contributor

Link to Issue or Description of Change

1. Link to an existing issue (if applicable):

Fixes #7206

Problem: RestApiTool.call() builds the error message for the model in
its except httpx.HTTPStatusError handler with:

error_details = response.content.decode("utf-8")

This forces UTF-8 regardless of the charset the server declares. A
non-UTF-8 error body (e.g. a Latin-1/Windows-1252 page from a legacy
ERP or IIS server) raises UnicodeDecodeError. Because the exception
is raised inside the except httpx.HTTPStatusError handler, the
sibling except ValueError can't catch it, so it propagates out of the
tool and ends the whole agent run — the model never gets the chance to
see and recover from the HTTP error.

Solution: Use response.text instead, matching the existing
non-JSON success path a few lines below (except ValueError: ... response.text). httpx decodes response.text using the response's
declared charset and replaces undecodable bytes instead of raising.

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

Added test_call_http_failure_non_utf8_body, which builds a real
httpx.Response (404, Content-Type: text/plain; charset=iso-8859-1,
body "Commande introuvable : échec" encoded as Latin-1) and asserts
RestApiTool.call() returns the normal error dict instead of raising.
Also updated the existing test_call_http_failure mock to set
.text alongside .content, since the code path now reads that
attribute.

Regression proof — reverting only the source fix
(git checkout HEAD~1 -- src/google/adk/tools/openapi_tool/openapi_spec_parser/rest_api_tool.py)
and running the new test:

$ python -m pytest tests/unittests/tools/openapi_tool/openapi_spec_parser/test_rest_api_tool.py -k http_failure -q
...
E       UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 23: invalid continuation byte
src/google/adk/tools/openapi_tool/openapi_spec_parser/rest_api_tool.py:643: UnicodeDecodeError
1 failed, 1 passed, 80 deselected in 1.28s

With the fix restored:

$ python -m pytest tests/unittests/tools/openapi_tool/openapi_spec_parser/test_rest_api_tool.py -k http_failure -q
2 passed, 80 deselected in 2.72s

$ python -m pytest tests/unittests/tools/openapi_tool -q
342 passed, 38 warnings in 4.59s

Also ran the repo's formatters/linters on the changed files (both clean):

$ python -m isort --check-only --diff <files>
$ python -m pyink --check --diff <files>
All done! 2 files would be left unchanged.

AI assistance disclosure

This change was prepared with the assistance of Claude Code (Anthropic),
under human review before submission.

response.content.decode("utf-8") raises UnicodeDecodeError for a
non-UTF-8 error body (e.g. a Latin-1 page from a legacy server), inside
the except httpx.HTTPStatusError handler where the sibling except
ValueError can't catch it, crashing the whole agent run. Use
response.text instead, matching the existing non-JSON success path a
few lines below, which decodes with the response's declared charset
and replaces undecodable bytes rather than raising.

Fixes google#7206
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.

RestApiTool crashes the agent run on a non-UTF-8 error response body (UnicodeDecodeError in the HTTPStatusError handler)

2 participants