Skip to content

Bug: Event handler with unsupported content-type headers raises an exception instead of returning a 4xx error #7978

@chriselion

Description

@chriselion

Expected Behaviour

Passing unsupported content-type headers (for example, "headers": {"content-type": "text/xml"}) to an event handler (tested with ALBResolver, but probably affects others) should result in some sort of client error, for example 422.

Current Behaviour

Currently, an uncaught exception is raised, resulting in a 500 status code:

request returned status 500
  error: Traceback (most recent call last):
  File "/Users/celion/.cache/uv/environments-v2/validation-repro-e88f9191e633f920/lib/python3.12/site-packages/aws_lambda_powertools/event_handler/api_gateway.py", line 2734, in _call_route
    route(router_middlewares=self._router_middlewares, app=self, route_arguments=route_arguments),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/celion/.cache/uv/environments-v2/validation-repro-e88f9191e633f920/lib/python3.12/site-packages/aws_lambda_powertools/event_handler/api_gateway.py", line 509, in __call__
    return self._middleware_stack(app)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/celion/.cache/uv/environments-v2/validation-repro-e88f9191e633f920/lib/python3.12/site-packages/aws_lambda_powertools/event_handler/api_gateway.py", line 1639, in __call__
    return self.current_middleware(app, self.next_middleware)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/celion/.cache/uv/environments-v2/validation-repro-e88f9191e633f920/lib/python3.12/site-packages/aws_lambda_powertools/event_handler/middlewares/base.py", line 121, in __call__
    return self.handler(app, next_middleware)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/celion/.cache/uv/environments-v2/validation-repro-e88f9191e633f920/lib/python3.12/site-packages/aws_lambda_powertools/event_handler/middlewares/openapi_validation.py", line 102, in handler
    received_body=self._get_body(app),
                  ^^^^^^^^^^^^^^^^^^^
  File "/Users/celion/.cache/uv/environments-v2/validation-repro-e88f9191e633f920/lib/python3.12/site-packages/aws_lambda_powertools/event_handler/middlewares/openapi_validation.py", line 132, in _get_body
    raise NotImplementedError("Only JSON body or Form() are supported")
NotImplementedError: Only JSON body or Form() are supported

Code snippet

# /// script
# dependencies = [
#   "aws-lambda-powertools==3.24.0",
#   "pydantic"
# ]
# ///

import pydantic
import aws_lambda_powertools
from aws_lambda_powertools.event_handler import ALBResolver

class MyRequest(pydantic.BaseModel):
    foo: str = ""

class MyResponse(pydantic.BaseModel):
    bar: str

app = ALBResolver(enable_validation=True)

@app.put("/test/")
def test_endpoint(
    body: MyRequest,
) -> MyResponse:
    return MyResponse(bar=body.foo)


def main():
    print(f"Running on aws-lambda-powertools=={aws_lambda_powertools.__version__} pydantic=={pydantic.__version__}")
    event = {
        "httpMethod": "PUT",
        "path": "/test/",
        "requestId": "some_request_id",
        "requestContext": {"elb": {"targetGroupArn": ":target:"}},
        # Set non-JSON non-form headers
        "headers": {"content-type": "text/xml"}
    }

    try:
        response = app.resolve(event, context=None)
        print(f"request returned status {response['statusCode']}")
        if response["statusCode"] != 200:
            print(f"  error: {response['body']}")
    except Exception as e:
        print(f"Raise an exception resolving event: {e}")

if __name__ == "__main__":
    main()

Possible Solution

The relevant code is here:

def _get_body(self, app: EventHandlerInstance) -> dict[str, Any]:
"""
Get the request body from the event, and parse it according to content type.
"""
content_type = app.current_event.headers.get("content-type", "").strip()
# Handle JSON content
if not content_type or content_type.startswith(APPLICATION_JSON_CONTENT_TYPE):
return self._parse_json_data(app)
# Handle URL-encoded form data
elif content_type.startswith(APPLICATION_FORM_CONTENT_TYPE):
return self._parse_form_data(app)
else:
raise NotImplementedError("Only JSON body or Form() are supported")

An easy fix would be to raise a different exception type - maybe RequestValidationError?

Steps to Reproduce

No special installation steps are required. I can reproduce the error with the latest release (3.24.0)

Powertools for AWS Lambda (Python) version

3.24.0 (current latest)

AWS Lambda function runtime

3.12

Packaging format used

PyPi

Debugging logs

n/a, can reproduce locally

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Status

    Ideas

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions