Skip to content

Commit 7cfbad3

Browse files
authored
feat: Add additional exception information for bedrock (#290)
We've received customer confusion regarding some of the errors when attempting to run on bedrock. To help customers understand what's going wrong, add region and model information to exceptions coming out of the bedrock provider & point them to our docs when possible. Semi-related to #238 Co-authored-by: Mackenzie Zastrow <[email protected]>
1 parent 3ae8d77 commit 7cfbad3

File tree

2 files changed

+108
-1
lines changed

2 files changed

+108
-1
lines changed

src/strands/models/bedrock.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,32 @@ def stream(self, request: dict[str, Any]) -> Iterable[StreamEvent]:
380380
logger.warning("bedrock threw context window overflow error")
381381
raise ContextWindowOverflowException(e) from e
382382

383+
region = self.client.meta.region_name
384+
385+
# add_note added in Python 3.11
386+
if hasattr(e, "add_note"):
387+
# Aid in debugging by adding more information
388+
e.add_note(f"└ Bedrock region: {region}")
389+
e.add_note(f"└ Model id: {self.config.get('model_id')}")
390+
391+
if (
392+
e.response["Error"]["Code"] == "AccessDeniedException"
393+
and "You don't have access to the model" in error_message
394+
):
395+
e.add_note(
396+
"└ For more information see "
397+
"https://strandsagents.com/user-guide/concepts/model-providers/amazon-bedrock/#model-access-issue"
398+
)
399+
400+
if (
401+
e.response["Error"]["Code"] == "ValidationException"
402+
and "with on-demand throughput isn’t supported" in error_message
403+
):
404+
e.add_note(
405+
"└ For more information see "
406+
"https://strandsagents.com/latest/user-guide/concepts/model-providers/amazon-bedrock/#on-demand-throughput-isnt-supported"
407+
)
408+
383409
# Otherwise raise the error
384410
raise e
385411

tests/strands/models/test_bedrock.py

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import sys
23
import unittest.mock
34

45
import boto3
@@ -15,7 +16,10 @@
1516
@pytest.fixture
1617
def bedrock_client():
1718
with unittest.mock.patch.object(strands.models.bedrock.boto3, "Session") as mock_session_cls:
18-
yield mock_session_cls.return_value.client.return_value
19+
mock_client = mock_session_cls.return_value.client.return_value
20+
mock_client.meta = unittest.mock.MagicMock()
21+
mock_client.meta.region_name = "us-west-2"
22+
yield mock_client
1923

2024

2125
@pytest.fixture
@@ -1029,3 +1033,80 @@ def test_converse_output_guardrails_redacts_output(bedrock_client):
10291033

10301034
bedrock_client.converse.assert_called_once()
10311035
bedrock_client.converse_stream.assert_not_called()
1036+
1037+
1038+
@pytest.mark.skipif(sys.version_info < (3, 11), reason="This test requires Python 3.11 or higher (need add_note)")
1039+
def test_add_note_on_client_error(bedrock_client, model):
1040+
"""Test that add_note is called on ClientError with region and model ID information."""
1041+
# Mock the client error response
1042+
error_response = {"Error": {"Code": "ValidationException", "Message": "Some error message"}}
1043+
bedrock_client.converse_stream.side_effect = ClientError(error_response, "ConversationStream")
1044+
1045+
# Call the stream method which should catch and add notes to the exception
1046+
with pytest.raises(ClientError) as err:
1047+
list(model.stream({"modelId": "test-model"}))
1048+
1049+
assert err.value.__notes__ == ["└ Bedrock region: us-west-2", "└ Model id: m1"]
1050+
1051+
1052+
def test_no_add_note_when_not_available(bedrock_client, model):
1053+
"""Verify that on any python version (even < 3.11 where add_note is not available, we get the right exception)."""
1054+
# Mock the client error response
1055+
error_response = {"Error": {"Code": "ValidationException", "Message": "Some error message"}}
1056+
bedrock_client.converse_stream.side_effect = ClientError(error_response, "ConversationStream")
1057+
1058+
# Call the stream method which should catch and add notes to the exception
1059+
with pytest.raises(ClientError):
1060+
list(model.stream({"modelId": "test-model"}))
1061+
1062+
1063+
@pytest.mark.skipif(sys.version_info < (3, 11), reason="This test requires Python 3.11 or higher (need add_note)")
1064+
def test_add_note_on_access_denied_exception(bedrock_client, model):
1065+
"""Test that add_note adds documentation link for AccessDeniedException."""
1066+
# Mock the client error response for access denied
1067+
error_response = {
1068+
"Error": {
1069+
"Code": "AccessDeniedException",
1070+
"Message": "An error occurred (AccessDeniedException) when calling the ConverseStream operation: "
1071+
"You don't have access to the model with the specified model ID.",
1072+
}
1073+
}
1074+
bedrock_client.converse_stream.side_effect = ClientError(error_response, "ConversationStream")
1075+
1076+
# Call the stream method which should catch and add notes to the exception
1077+
with pytest.raises(ClientError) as err:
1078+
list(model.stream({"modelId": "test-model"}))
1079+
1080+
assert err.value.__notes__ == [
1081+
"└ Bedrock region: us-west-2",
1082+
"└ Model id: m1",
1083+
"└ For more information see "
1084+
"https://strandsagents.com/user-guide/concepts/model-providers/amazon-bedrock/#model-access-issue",
1085+
]
1086+
1087+
1088+
@pytest.mark.skipif(sys.version_info < (3, 11), reason="This test requires Python 3.11 or higher (need add_note)")
1089+
def test_add_note_on_validation_exception_throughput(bedrock_client, model):
1090+
"""Test that add_note adds documentation link for ValidationException about on-demand throughput."""
1091+
# Mock the client error response for validation exception
1092+
error_response = {
1093+
"Error": {
1094+
"Code": "ValidationException",
1095+
"Message": "An error occurred (ValidationException) when calling the ConverseStream operation: "
1096+
"Invocation of model ID anthropic.claude-3-7-sonnet-20250219-v1:0 with on-demand throughput "
1097+
"isn’t supported. Retry your request with the ID or ARN of an inference profile that contains "
1098+
"this model.",
1099+
}
1100+
}
1101+
bedrock_client.converse_stream.side_effect = ClientError(error_response, "ConversationStream")
1102+
1103+
# Call the stream method which should catch and add notes to the exception
1104+
with pytest.raises(ClientError) as err:
1105+
list(model.stream({"modelId": "test-model"}))
1106+
1107+
assert err.value.__notes__ == [
1108+
"└ Bedrock region: us-west-2",
1109+
"└ Model id: m1",
1110+
"└ For more information see "
1111+
"https://strandsagents.com/latest/user-guide/concepts/model-providers/amazon-bedrock/#on-demand-throughput-isnt-supported",
1112+
]

0 commit comments

Comments
 (0)