Skip to content

fix(bedrock): raise_for_status in WrappedBotoClient so gateway errors surface#95

Merged
vldcmp-uipath merged 1 commit into
mainfrom
fix/bedrock-wrapped-boto-raise-for-status
Jun 23, 2026
Merged

fix(bedrock): raise_for_status in WrappedBotoClient so gateway errors surface#95
vldcmp-uipath merged 1 commit into
mainfrom
fix/bedrock-wrapped-boto-raise-for-status

Conversation

@vldcmp-uipath

Copy link
Copy Markdown
Contributor

Problem

WrappedBotoClient (the httpx-backed Bedrock shim that replaces boto3 when talking to the LLM Gateway) read responses with .json() / iter_bytes() without checking the HTTP status. On a non-2xx gateway response — e.g. a 403 License not available — the error body was parsed as if it were a normal Converse result and handed to langchain_aws, which then raised a misleading:

ValueError: No 'output' key found in the response from the Bedrock Converse API.
This usually happens due to misconfiguration of endpoint or region ...

The real status code (403) and the gateway's detail ("…you need additional 'AGU'") were lost — so a licensing error surfaced as a confusing "check your endpoint/region" message.

Fix

Call response.raise_for_status() before reading the body in converse, invoke_model, and the streaming generator (_stream_generator, used by converse_stream / invoke_model_with_response_stream). The UiPath httpx client's patched raise_for_status then raises the typed UiPathAPIError subclass (e.g. UiPathPermissionDeniedError, carrying .status_code and .body).

For streaming responses the error body is read first (if response.is_error: response.read()), since the gateway returns a non-streamed JSON error body and UiPathAPIError.from_response parses response.json() to populate detail. Verified on httpx 0.28.1 that is_error / status_code are available from the response headers inside the stream() context before the body is read, and that the success path still streams via iter_bytes().

Verification

Confirmed end-to-end against a real gateway 403: the Bedrock Converse path now produces UiPathPermissionDeniedError(status_code=403, body={... "detail": "License not available ... 'AGU'" ...}) instead of the opaque ValueError.

Tests

New tests/langchain/clients/bedrock/test_wrapped_boto_client.py:

  • converse / invoke_model raise on a 403 (and converse returns the body on 200)
  • converse_stream / invoke_model_with_response_stream raise on a 403 when consumed

🤖 Generated with Claude Code

… surface

WrappedBotoClient read responses with .json()/iter_bytes without checking the
HTTP status, so a non-2xx gateway response (e.g. 403 License-not-available) was
parsed as a normal result and handed to langchain_aws, which then raised a
misleading "No 'output' key ... misconfiguration of endpoint or region"
ValueError - losing the real status code and detail.

Call raise_for_status() in converse, invoke_model, and the streaming generator
so gateway HTTP errors surface as the patched UiPathAPIError subclass (e.g.
UiPathPermissionDeniedError), matching the OpenAI and Vertex paths. For
streaming, read the error body first so the typed exception keeps its detail.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vldcmp-uipath vldcmp-uipath merged commit 53fd47c into main Jun 23, 2026
10 checks passed
@vldcmp-uipath vldcmp-uipath deleted the fix/bedrock-wrapped-boto-raise-for-status branch June 23, 2026 10:51
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