question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Bug: exception_handler decorator won't return Response with botocore ClientError

See original GitHub issue

Expected Behaviour

On botocore ClientError the Lambda function shall return:

{
  "statusCode": 400,
  "headers": {
    "Content-Type": "application/json"
  },
  "body": "{\"statusCode\": 400, \"message\": \"Bad Request\"}",
  "isBase64Encoded": false
}

Current Behaviour

Lambda function raises exception and ends with error, instead of returning HTTP response

Code snippet

import json
import boto3
from botocore.exceptions import ClientError

from aws_lambda_powertools.utilities.data_classes import (
    APIGatewayProxyEventV2,
    event_source,
)
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools import Logger
from aws_lambda_powertools.event_handler import APIGatewayHttpResolver, content_types
from aws_lambda_powertools.utilities.typing import LambdaContext
from aws_lambda_powertools.event_handler.exceptions import (
    BadRequestError,
    InternalServerError,
    NotFoundError,
)
from aws_lambda_powertools.event_handler.api_gateway import Response

logger = Logger()
app = APIGatewayHttpResolver()
dynamo = boto3.resource("dynamodb")


@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_HTTP)
@event_source(data_class=APIGatewayProxyEventV2)
def lambda_handler(event: APIGatewayProxyEventV2, context: LambdaContext):
    return app.resolve(event, context)

@app.get("/my/path")
def get_hello_universe():
    table = dynamo.Table("non-existent")
    table.get_item(
        Key={
            "pk": "abc",
            "sk": "123",
        },
    )
    return {"message": "hello universe"}
    

@app.exception_handler(ClientError)
def handle_botocore_error(ex: ClientError):
    metadata = {"path": app.current_event.path}
    logger.error(f"Exception: {ex}", extra=metadata)
    # return Response(
    #     status_code=400,
    #     content_type=content_types.APPLICATION_JSON,
    #     body=json.dumps({"statusCode": 400, "message": "Bad request"}),
    # )

    raise BadRequestError("something bad happened")

Possible Solution

No response

Steps to Reproduce

Use the provided code snippet to see that the Lambda will throw an exception instead of returning a 400 “Bad Request” response.

AWS Lambda Powertools for Python version

latest (Layer version 18)

AWS Lambda function runtime

3.9

Packaging format used

Lambda Layers

Debugging logs

START RequestId: 846da9eb-f64a-41e7-90cf-293386069384 Version: $LATEST
{"level":"ERROR","location":"handle_botocore_error:45","message":"Exception: An error occurred (AccessDeniedException) when calling the GetItem operation: User: arn:aws:sts::373270804851:assumed-role/test-role-hg1im76s/test is not authorized to perform: dynamodb:GetItem on resource: arn:aws:dynamodb:eu-central-1:373270804851:table/non-existent","timestamp":"2022-04-25 17:21:59,753+0000","service":"service_undefined","cold_start":true,"function_name":"test","function_memory_size":"128","function_arn":"arn:aws:lambda:eu-central-1:373270804851:function:test","function_request_id":"846da9eb-f64a-41e7-90cf-293386069384","correlation_id":"id","path":"/my/path","xray_trace_id":"1-6266d8b6-7c8a3e216f62498e0331a61a"}
[ERROR] BadRequestError: something bad happened
Traceback (most recent call last):
  File "/opt/python/aws_lambda_powertools/logging/logger.py", line 354, in decorate
    return lambda_handler(event, context)
  File "/opt/python/aws_lambda_powertools/middleware_factory/factory.py", line 134, in wrapper
    response = middleware()
  File "/opt/python/aws_lambda_powertools/utilities/data_classes/event_source.py", line 39, in event_source
    return handler(data_class(event), context)
  File "/var/task/lambda_function.py", line 28, in lambda_handler
    return app.resolve(event, context)
  File "/opt/python/aws_lambda_powertools/event_handler/api_gateway.py", line 498, in resolve
    return self._resolve().build(self.current_event, self._cors)
  File "/opt/python/aws_lambda_powertools/event_handler/api_gateway.py", line 557, in _resolve
    return self._call_route(route, match_results.groupdict())  # pass fn args
  File "/opt/python/aws_lambda_powertools/event_handler/api_gateway.py", line 613, in _call_route
    response_builder = self._call_exception_handler(exc, route)
  File "/opt/python/aws_lambda_powertools/event_handler/api_gateway.py", line 654, in _call_exception_handler
    return ResponseBuilder(handler(exp), route)
  File "/var/task/lambda_function.py", line 52, in handle_botocore_error
    raise BadRequestError("something bad happened")END RequestId: 846da9eb-f64a-41e7-90cf-293386069384
REPORT RequestId: 846da9eb-f64a-41e7-90cf-293386069384	Duration: 344.21 ms	Billed Duration: 345 ms	Memory Size: 128 MB	Max Memory Used: 67 MB	Init Duration: 630.48 ms

Issue Analytics

  • State:closed
  • Created a year ago
  • Reactions:1
  • Comments:13 (12 by maintainers)

github_iconTop GitHub Comments

2reactions
heitorlessacommented, Apr 26, 2022

Yes to the first question - we should handle ServiceError exceptions differently as customers will instinctively and eventually raise these to signal 4xx

On Tue, 26 Apr 2022 at 19:11, Stephan @.***> wrote:

Actually it seems that any exception raised within an exception handler route will raise and cause the Lambda function to end with an error. I guess you could say that it’s intentional however it doesn’t seem intuitive at first.

@heitorlessa https://github.com/heitorlessa should ServiceError type exceptions (BadRequestError, InternalServerError, NotFoundError, UnauthorizedError) be handled differently when raised in an exception handler than other exceptions? Alternatively, we leave it as is and extend the documentation to say that exceptions raised in exception handlers will cause a Lambda function to error.

As @michaelbrewer https://github.com/michaelbrewer aparrently implemented that part, I’m interested in his take on this.

Please see the following commit for a proposal from my side: 6aa7c00 https://github.com/awslabs/aws-lambda-powertools-python/commit/6aa7c009fa9c832c74d3517c639018c2ba93ad38

I can create a PR later but have to drop off for now

— Reply to this email directly, view it on GitHub https://github.com/awslabs/aws-lambda-powertools-python/issues/1153#issuecomment-1110047769, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAZPQBD5SB6R46VP6RAFADTVHAPUNANCNFSM5UJH6PKQ . You are receiving this because you were mentioned.Message ID: @.***>

1reaction
michaelbrewercommented, Apr 26, 2022

Just that your @app.exception_handler should not swallow the passed ex, but thats just a tip in the docs 😛

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to handle errors with boto3? - Stack Overflow
Use the response contained within the exception. Here is an example: import boto3 from botocore.exceptions import ClientError try: iam = boto3.client('iam') ...
Read more >
Error handling — Boto3 Docs 1.26.35 documentation - AWS
The most common botocore exception you'll encounter is ClientError . This is a general exception when an error response is provided by an...
Read more >
Handling Errors in Boto3 & Botocore - Trek10
ClientError: An error occurred (IllegalLocationConstraintException) when calling the CreateBucket operation: The unspecified location constraint is incompatible ...
Read more >
How to use the botocore.exceptions function in ... - Snyk
To help you get started, we've selected a few botocore.exceptions examples, ... ClientError as error: raise BackupClientError(error.response) except ...
Read more >
Guidelines for Ansible Amazon AWS module development
Fixing bugs; Adding new features; Migrating to boto3 ... For more information on botocore exception handling see the botocore error documentation.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found