title: Python AWS Lambda function 502 null body {"message": "Internal server error"}
body: <p>I am investigating the feasibility of using a python lambda to serve a throttled endpoint connecting to a dynamo database. There is a basic token authentication and the counts for the throttling are kept in a dynamodb with a TTL of a day. I call it throttling but its actualy a daily count of requests. All the complicated parts work and if the user is unauthenticated I get the expected response <code>{&quot;message&quot;: &quot;No token, or your token is invalid!&quot;}</code> and if the daily count of requests is exhausted i also get the expected message
  <code>{&quot;message&quot;: &quot;Daily Invocations Exhausted!&quot;}</code> however when the authentication and throttle allows a response from the <code>lambda_handler</code> i get a 502 <code>{&quot;message&quot;: &quot;Internal server error&quot;}</code>.
  When I look at the API Gateway test i see this log:</p>
  <pre><code>Mon Nov 29 14:56:28 UTC 2021 : Endpoint response body before transformations: null
  Mon Nov 29 14:56:28 UTC 2021 : Execution failed due to configuration error: Malformed Lambda proxy response
  Mon Nov 29 14:56:28 UTC 2021 : Method completed with status: 502
  </code></pre>
  <p>And when I print the body and see the logs in CloudFormation i see this:</p>
  <pre><code>2021-11-29T15:56:28.103+01:00   {&quot;message&quot;: &quot;stuff!&quot;}
  </code></pre>
  <p>I am new with python lambdas so I am completely at a loss here, this behaviour makes no sense to me, I am hoping you can see something in the code which I am missing.</p>
  <pre><code>import json
  import time
  
  # import requests
  import boto3
  from botocore.exceptions import ClientError
  
  dynamodb = boto3.client('dynamodb')
  DAY_LIMIT = 5
  
  
  def get_token(token):
      try:
          response = dynamodb.get_item(TableName='tokens', Key={'token': {'S': token}})
      except ClientError as e:
          print(e.response['Error']['Message'])
      else:
          return None if 'Item' not in response else response['Item']
  
  def get_token_throttle(token):
      try:
          response = dynamodb.get_item(TableName='token_throttle',
                                Key={'token': {'S': token}})
      except ClientError as e:
          print(e.response['Error']['Message'])
      else:
          return None if 'Item' not in response else response['Item']
  
  def authenticated(function):
      def wrapper(event, context):
          if (event['queryStringParameters'] is None or &quot;token&quot; not in event['queryStringParameters'] or
                  get_token(event['queryStringParameters']['token']) is None):
              return {
                  &quot;statusCode&quot;: 401,
                  &quot;body&quot;: json.dumps({
                      &quot;message&quot;: &quot;No token, or your token is invalid!&quot;
                  }),
              }
          else:
              return function(event, context)
  
      return wrapper
  
  
  def lambda_limit_per_day(function):
      def wrapper(event, context):
          throttle = get_token_throttle(event['queryStringParameters']['token'])
  
          if throttle == None:
              dynamodb.put_item(TableName='token_throttle', Item={
                  &quot;token&quot;: {&quot;S&quot;: event['queryStringParameters']['token']},
                  &quot;invocations&quot;: {&quot;N&quot;: str(1)},
                  &quot;deletion&quot;: {&quot;N&quot;: str(int(time.time()) + 86400)}  # one day
              })
              function(event, context)
          elif int(throttle['invocations']['N']) &lt; DAY_LIMIT:
              dynamodb.put_item(TableName='token_throttle', Item={
                  &quot;token&quot;: {&quot;S&quot;: event['queryStringParameters']['token']},
                  &quot;invocations&quot;: {&quot;N&quot;: str(int(throttle['invocations']['N']) + 1)},
                  &quot;deletion&quot;: {&quot;N&quot;: str(throttle['deletion']['N'])}  # one day
              })
              function(event, context)
          else:
              return {
                  &quot;statusCode&quot;: 200,
                  &quot;body&quot;: json.dumps({
                      &quot;message&quot;: &quot;Daily Invocations Exhausted!&quot;
                  }),
              }
      return wrapper
  
  
  @authenticated
  @lambda_limit_per_day
  def lambda_handler(event, context):
      &quot;&quot;&quot;Sample pure Lambda function
  
      Parameters
      ----------
      event: dict, required
          API Gateway Lambda Proxy Input Format
  
          Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
  
      context: object, required
          Lambda Context runtime methods and attributes
  
          Context doc: https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html
  
      Returns
      ------
      API Gateway Lambda Proxy Output Format: dict
  
          Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html
      &quot;&quot;&quot;
      print(&quot;Running Final function&quot;)
      body = json.dumps({
              &quot;message&quot;: &quot;stuff!&quot;
          })
      print(body)
      return {
          &quot;statusCode&quot;: 200,
          &quot;body&quot;: body,
      }
  </code></pre>