-
Notifications
You must be signed in to change notification settings - Fork 441
Closed
Labels
bugSomething isn't workingSomething isn't working
Description
Expected Behaviour
When using quoted type annotations with Annotated in AWS Lambda Powertools API Gateway resolver, the parameter should be correctly identified as a body parameter and properly parse the incoming JSON request body.
When using quoted type annotations (forward references) like 'Annotated[UserCreate, Body(...)]', the parameter is incorrectly treated as a query parameter instead of a body parameter. This results in a 422 Unprocessable Content error with a "missing query parameter" message, even when the JSON body is correctly provided.
Current Behaviour
- Type resolution fails silently
- Parameter placement falls back to "best guess" behavior
- Complex types may be misclassified as simple types
- Explicit parameter annotations are ignored
Code snippet
import json
from typing import Annotated
from aws_lambda_powertools import Tracer
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
from aws_lambda_powertools.event_handler.openapi.params import Body
from pydantic import BaseModel
app = APIGatewayRestResolver(enable_validation=True)
class UserCreate(BaseModel):
username: str
email: str
age: int
id: str
@app.post("/users")
def create_user(
user_create_request: 'Annotated[UserCreate, Body(title="New User", description="The user data to create")]',
) -> dict:
return {"message": f"Created user {user_create_request.username}"}
def lambda_handler(event, context):
return app.resolve(event, context)
if __name__ == "__main__":
test_event = {
"body": json.dumps({
"username": "john_doe",
"email": "[email protected]",
"age": 30,
"id": "user123"
}),
"httpMethod": "POST",
"path": "/users",
"headers": {
"Content-Type": "application/json"
},
"requestContext": {
"requestId": "test-id"
}
}
result = lambda_handler(test_event, {})
if (
result["statusCode"] == 422
and "missing" in result["body"]
and "user_create_request" in result["body"]
):
print("Bug reproduced! Got expected 422 error with missing user_create_request:")
print(result["body"])
else:
print("Unexpected result:")
print(f"Status: {result['statusCode']}")
print(f"Body: {result['body']}")
"""
The issue occurs due to how AWS Lambda Powertools handles type resolution:
1. In get_typed_signature(), there's a bug in how it gets the globals for the call:
globalns = getattr(call, "__global__", {}) # Bug: Returns empty dict if __global__ not found
and that is always true becuase it's not __global_ its __globals__
This fails to get the actual module globals where UserCreate is defined.
2. When evaluating the forward reference string in get_typed_annotation():
annotation = ForwardRef(annotation)
annotation = evaluate_forwardref(annotation, globalns, globalns)
Because globalns is empty, it can't resolve "UserCreate" or other types in the string.
3. This causes the unresolved ForwardRef to be passed to field_annotation_is_complex(),
where get_origin() returns None since it can't get the origin of an unresolved reference.
4. With origin=None, field_annotation_is_complex() returns False, making
field_annotation_is_scalar() return True.
5. Because the parameter is incorrectly identified as a scalar field,
is_body_param() returns False and the parameter isn't added to
dependant.body_params.
6. This results in the parameter being treated as a query parameter
instead of a body parameter, leading to the missing argument error.
The fix could be either:
a) Use direct type annotation instead of a string forward reference
b) Fix get_typed_signature() to properly get the module globals:
globalns = getattr(call, "__globals__", {}) # Use current globals as fallback
"""
Possible Solution
Fix get_typed_signature() to properly get the module globals:
globalns = getattr(call, "__globals__", {})
Steps to Reproduce
Steps to Reproduce
- Create an API Gateway resolver with validation enabled
- Define a Pydantic model for request validation
- Create an endpoint using a quoted type annotation with
Annotated
andBody
- Send a POST request with a valid JSON body
- Observe the 422 error indicating a missing query parameter
Powertools for AWS Lambda (Python) version
latest
AWS Lambda function runtime
3.8
Packaging format used
Lambda Layers
Debugging logs
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working
Type
Projects
Status
Shipped