Comments (7)
Hi @heitorlessa and @aitchnyu, after investigating further I discovered that the issue goes beyond fixing the RequestValidationError
or not. Our exception_handler
function captures a list of exceptions passed to it, however, it is important to note that most exceptions in Python inherit from Exception
(some from BaseException
). So if we set exception_handler
to catch Exception
, it will also catch exceptions like ValueError
, KeyError
, TypeError
, RequestValidationError
, and others.
Ideally, it's advisable to catch more specific exceptions, especially if you want to generate custom messages for specific error types like RequestValidationError
. I'm not sure if there's a straightforward solution at the moment, I'll need to investigate further. One potential action arising from this issue is to update our documentation to reflect this behavior, where catching Exception
acts as a catch-all mechanism for all exceptions.
code
from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing import LambdaContext
from aws_lambda_powertools.event_handler.api_gateway import Response
tracer = Tracer()
logger = Logger()
app = APIGatewayRestResolver()
@app.get("/hello")
def get_todos():
raise ValueError
@app.exception_handler(Exception)
def handle_invalid_limit_qs(ex: Exception): # receives exception raised
return Response(
status_code=400,
body="Catching Exception, but raising ValueError",
)
@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)
def lambda_handler(event: dict, context: LambdaContext) -> dict:
return app.resolve(event, context)
execution
sam local invoke --event events/event.json --skip-pull-image
Invoking app.lambda_handler (python3.11)
Requested to skip pulling images ...
Mounting /home/leandro/DEVEL-PYTHON/tmp/exception-different-router/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated, inside runtime container
START RequestId: e408630c-0660-4d24-a3c5-d6e590f6d959 Version: $LATEST
START RequestId: e408630c-0660-4d24-a3c5-d6e590f6d959 Version: $LATEST
END RequestId: e408630c-0660-4d24-a3c5-d6e590f6d959
REPORT RequestId: e408630c-0660-4d24-a3c5-d6e590f6d959 Init Duration: 0.11 ms Duration: 407.67 ms Billed Duration: 408 ms Memory Size: 128 MB Max Memory Used: 128 MB
{"statusCode": 400, "body": "Catching Exception, but raising ValueError ", "isBase64Encoded": false, "multiValueHeaders": {}}
I'm adding labels such as “need help” and “revisit” to keep this issue on our radar.
Thank you
from powertools-lambda-python.
Thanks for opening your first issue here! We'll come back to you as soon as we can.
In the meantime, check out the #python channel on our Powertools for AWS Lambda Discord: Invite link
from powertools-lambda-python.
hey @aitchnyu - thank you for submitting an extensive bug report!! It should work with RequestValidationError
exception.
I'll investigate the behaviour today when catching a catch-all Exception
like you did, and come back to you.
As per docs, catching RequestValidatioError
should work as you want; tested locally too.
from typing import Optional
import requests
from pydantic import BaseModel, Field
from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.event_handler import APIGatewayRestResolver, Response, content_types
from aws_lambda_powertools.event_handler.openapi.exceptions import RequestValidationError
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing import LambdaContext
tracer = Tracer()
logger = Logger()
app = APIGatewayRestResolver(enable_validation=True)
class Todo(BaseModel):
userId: int
id_: Optional[int] = Field(alias="id", default=None)
title: str
completed: bool
@app.exception_handler(RequestValidationError)
def handle_validation_error(ex: RequestValidationError):
logger.error("Request failed validation", path=app.current_event.path, errors=ex.errors())
return Response(
status_code=422,
content_type=content_types.APPLICATION_JSON,
body="Invalid data",
)
@app.post("/todos")
def create_todo(todo: Todo) -> int:
response = requests.post("https://jsonplaceholder.typicode.com/todos", json=todo.dict(by_alias=True))
response.raise_for_status()
return response.json()["id"]
@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_HTTP)
@tracer.capture_lambda_handler
def lambda_handler(event: dict, context: LambdaContext) -> dict:
return app.resolve(event, context)
![image](https://private-user-images.githubusercontent.com/3340292/307712182-ec8c50e9-2414-49fb-ad9c-7ef6ce09f470.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE5NTc5NjksIm5iZiI6MTcyMTk1NzY2OSwicGF0aCI6Ii8zMzQwMjkyLzMwNzcxMjE4Mi1lYzhjNTBlOS0yNDE0LTQ5ZmItYWQ5Yy03ZWY2Y2UwOWY0NzAucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDcyNiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA3MjZUMDEzNDI5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NjRkMjI1MjUyY2Q2NDgxOWJiNmUwNzEzY2NmYzg5MzNkYzg3YzVhMjIzNTA0YTYyYTEwYzY1ODUyZjAzZTNhYiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.jiYJRZHNCiO6e2S_1DeZnBSOCfUeqtYpxfRY9xP_eLY)
from powertools-lambda-python.
Can't reproduce with either general Exception
and the suggested RequestValidationException
-- need more details.
Example below on how to get those exact details what the documentation suggests with RequestValidationError
.
from typing import Annotated, Optional
import requests
from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.event_handler import (
APIGatewayRestResolver,
Response,
content_types,
)
from aws_lambda_powertools.event_handler.openapi.exceptions import (
RequestValidationError,
)
from aws_lambda_powertools.event_handler.openapi.params import Path, Query
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing import LambdaContext
from aws_lambda_powertools.utilities.parser import Field, BaseModel
tracer = Tracer()
logger = Logger()
app = APIGatewayRestResolver(enable_validation=True)
app.enable_swagger(path="/swagger")
class Todo(BaseModel):
userId: int
id_: Optional[int] = Field(alias="id", default=None)
title: str
completed: bool
@app.exception_handler(RequestValidationError)
def catch_validation(ex: RequestValidationError):
logger.info("Catch all exception handler", error=ex)
err = ex.errors()[0]
location, message, type = err["loc"], err["msg"], err["type"]
return Response(
status_code=400,
content_type=content_types.TEXT_PLAIN,
body=f"Uh oh! Received an exception",
)
@app.get("/todos")
@tracer.capture_method
def get_todos(
completed: Annotated[str | None, Query(min_length=4)] = None
) -> list[Todo]:
url = "https://jsonplaceholder.typicode.com/todos"
if completed is not None:
url = f"{url}/?completed={completed}"
todo = requests.get(url)
todo.raise_for_status()
return todo.json()
@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)
@tracer.capture_lambda_handler
def lambda_handler(event: dict, context: LambdaContext) -> dict:
return app.resolve(event, context)
from powertools-lambda-python.
My workaround is having handlers for both RequestValidationError
and Exception
. If I were to disable the RequestValidationError
handler, the Exception
would handle it (against my expectations).
app = APIGatewayRestResolver(enable_validation=True)
...
@app.exception_handler(Exception)
def handle_exception(ex: Exception): # pragma: no cover
...
return Response(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
content_type=content_types.APPLICATION_JSON,
body=json.dumps({"message": "internal server error"}),
)
@app.exception_handler(RequestValidationError)
def handle_request_validation_error(ex: RequestValidationError):
# Copy of ApiGatewayResolver _call_exception_handler
errors = [{"loc": e["loc"], "type": e["type"]} for e in ex.errors()]
return Response(
status_code=HTTPStatus.UNPROCESSABLE_ENTITY,
content_type=content_types.APPLICATION_JSON,
body={"statusCode": HTTPStatus.UNPROCESSABLE_ENTITY, "detail": errors},
)
from powertools-lambda-python.
Hey @heitorlessa and @aitchnyu!
After a long investigation, we have concluded that this is a fundamental aspect of how Python handles exceptions. In Python, most exceptions inherit from the base class Exception
, which means that catching Exception
will capture a wide range of exception types, including ValueError
, KeyError
, TypeError
, and RequestValidationError
. This behavior is an integral part of the Python language design. Modifying how Powertools for AWS Lambda handles and catches exceptions is not a viable solution at this time, and even if we attempted to change it, we have no idea of the potential side effects.
For cases like this, the recommended approach is to catch more specific exceptions, to better handle and respond to different error types.
I'm closing this issue and please reopen if you find a solution or have an idea how to address this.
Thanks
from powertools-lambda-python.
⚠️ COMMENT VISIBILITY WARNING⚠️
This issue is now closed. Please be mindful that future comments are hard for our team to see.
If you need more assistance, please either tag a team member or open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.
from powertools-lambda-python.
Related Issues (20)
- Maintenance: add the Metrics feature to nox tests HOT 1
- Maintenance: add the Tracer feature to nox tests HOT 1
- Maintenance: add the Event Handler feature to nox tests HOT 1
- Allow logging of None type values on logging context via a config value HOT 2
- Maintenance: Fix error when creating a developer environment in Gitpod HOT 1
- Feature request: provide Parser models for Lambda Authorizer HOT 3
- Maintenance: add the Parameters feature to nox tests HOT 1
- Maintenance: add the Typing feature to nox tests HOT 2
- Maintenance: add the Validation feature to nox tests HOT 2
- Maintenance: add the Parser feature to nox tests HOT 2
- Maintenance: add the Feature Flags feature to nox tests HOT 2
- Maintenance: add the Streaming feature to nox tests HOT 2
- Maintenance: add the Middleware Factory feature to nox tests HOT 2
- Maintenance: add the Idempotency feature to nox tests HOT 2
- Maintenance: add the Event Source Data Class feature to nox tests HOT 2
- Maintenance: add the Batch Processing feature to nox tests HOT 2
- Maintenance: add the Data Masking feature to nox tests HOT 2
- Docs: Fix Become a public reference link HOT 1
- Bug: Event handler + cors + headers HOT 5
- [Support Powertools for AWS Lambda (Python)]: Brsk HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from powertools-lambda-python.