Skip to content

fix: bedrock throttling exception on maintainers processing [CM-740]#3913

Merged
mbani01 merged 2 commits intomainfrom
fix/bedrock_throttling_exception
Mar 11, 2026
Merged

fix: bedrock throttling exception on maintainers processing [CM-740]#3913
mbani01 merged 2 commits intomainfrom
fix/bedrock_throttling_exception

Conversation

@mbani01
Copy link
Contributor

@mbani01 mbani01 commented Mar 11, 2026

This pull request improves the robustness of the invoke_bedrock function by adding retry logic to handle throttling errors from the Amazon Bedrock API. It introduces exponential backoff with jitter for retries and cleans up error handling to avoid redundant exception logging.

Error handling and reliability improvements:

  • Added retry logic with exponential backoff and jitter for handling ThrottlingException errors when calling the Bedrock API, allowing up to 5 retries with increasing delays. [1] [2] [3]
  • Removed redundant generic exception handling at the end of the function, relying on more targeted error handling and logging.

Dependency and import updates:

  • Imported asyncio, random, and ClientError to support the new retry and delay logic.

Note

Medium Risk
Adds retry/backoff and new sleep delays around Bedrock model invocation, which can change latency and failure behavior for maintainer processing if errors are misclassified or retries exhaust.

Overview
Improves invoke_bedrock robustness by retrying bedrock_client.invoke_model on AWS ThrottlingException up to 5 times using exponential backoff with jitter, logging a warning and delaying between attempts.

Refactors response parsing/validation to run after the retry loop and adjusts error logging to focus on JSON parse failures (logging the raw model text) rather than a generic “Bedrock API error” message.

Written by Cursor Bugbot for commit 49f2b90. This will update automatically on new commits. Configure here.

mbani01 added 2 commits March 11, 2026 15:29
Signed-off-by: Mouad BANI <mouad-mb@outlook.com>
Signed-off-by: Mouad BANI <mouad-mb@outlook.com>
@mbani01 mbani01 self-assigned this Mar 11, 2026
Copilot AI review requested due to automatic review settings March 11, 2026 15:31
@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR improves robustness of the Bedrock invocation path used by maintainer processing by adding explicit retry/backoff behavior for Bedrock throttling, and simplifying error handling around response parsing/validation.

Changes:

  • Add throttling retry loop with exponential backoff + jitter around bedrock_client.invoke_model.
  • Introduce module-level retry/backoff constants and new imports to support retry sleep and jitter.
  • Restructure response parsing/validation error handling and logging.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

logger.error(f"Amazon Bedrock API error: {e}")
logger.error("Failed to parse the response as JSON. Raw response:")
logger.error(response_body["content"][0]["text"])
raise e
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

raise e resets the traceback and makes debugging harder. Use a bare raise here so the original exception context is preserved.

Suggested change
raise e
raise

Copilot uses AI. Check for mistakes.
Comment on lines +120 to 131
# Validate output with the provided model if it exists
try:
body_bytes = await response["body"].read()
response_body = json.loads(body_bytes.decode("utf-8"))
raw_text = response_body["content"][0]["text"].replace('"""', "").strip()

# Expect pure JSON - no markdown handling
output = json.loads(raw_text)

# Calculate cost
input_tokens = response_body["usage"]["input_tokens"]
output_tokens = response_body["usage"]["output_tokens"]
input_cost = (input_tokens / 1000) * 0.003
output_cost = (output_tokens / 1000) * 0.015
total_cost = input_cost + output_cost

# Validate output with the provided model if it exists
try:
validated_output = pydantic_model.model_validate(output, strict=True)
except ValidationError as ve:
logger.error(f"Output validation failed: {ve}")
raise ve

return BedrockResponse[T](output=validated_output, cost=total_cost)
except Exception as e:
logger.error("Failed to parse the response as JSON. Raw response:")
logger.error(response_body["content"][0]["text"])
raise e
validated_output = pydantic_model.model_validate(output, strict=True)
except ValidationError as ve:
logger.error(f"Output validation failed: {ve}")
raise ve

return BedrockResponse[T](output=validated_output, cost=total_cost)
except Exception as e:
logger.error(f"Amazon Bedrock API error: {e}")
logger.error("Failed to parse the response as JSON. Raw response:")
logger.error(response_body["content"][0]["text"])
raise e
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

The outer except Exception will also catch ValidationError raised from the validation block and log it as a JSON parsing failure (and potentially log raw model text). Consider narrowing this handler to JSON/KeyError-related failures (or adding a dedicated except ValidationError: raise) so validation errors aren’t misclassified.

Copilot uses AI. Check for mistakes.
Comment on lines +85 to +90
for attempt in range(1, MAX_THROTTLE_RETRIES + 1):
try:
response = await bedrock_client.invoke_model(
body=body, modelId=modelId, accept=accept, contentType=contentType
)
break
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

This adds a custom retry loop on throttling, but the client Config already enables botocore retries (retries={"max_attempts": 3}), which can compound the total number of attempts and overall wait time. Consider consolidating retry behavior (either rely on botocore retries, or reduce/disable them when using this explicit backoff loop) to keep worst-case latency bounded and predictable.

Copilot uses AI. Check for mistakes.
Comment on lines 128 to 131
except Exception as e:
logger.error(f"Amazon Bedrock API error: {e}")
logger.error("Failed to parse the response as JSON. Raw response:")
logger.error(response_body["content"][0]["text"])
raise e
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

The except block logs response_body["content"][0]["text"], but response_body may be undefined if JSON decoding fails (or if response["body"].read()/json.loads(...) raises). This can mask the original error with an UnboundLocalError. Consider initializing response_body/raw text to a safe default and logging body_bytes (decoded) when available, or using logger.exception without indexing into response_body in the failure path.

Copilot uses AI. Check for mistakes.
Comment on lines +123 to +125
except ValidationError as ve:
logger.error(f"Output validation failed: {ve}")
raise ve
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

raise ve resets the traceback/context. If the goal is just to rethrow after logging, use a bare raise to preserve the original stack trace.

Copilot uses AI. Check for mistakes.
@mbani01 mbani01 merged commit fa00e9d into main Mar 11, 2026
16 checks passed
@mbani01 mbani01 deleted the fix/bedrock_throttling_exception branch March 11, 2026 15:55
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.

3 participants