Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Malformed Lambda proxy response: string indices must be integers

I am trying to write a serverless back-end for an application with AWS Lambda, and am running into the error in the title. The error occurs when testing with API Gateway proxy integration, but the function works fine when tested in the Lambda console.

Here is the error:

{  
   "errorMessage":"string indices must be integers",
   "errorType":"TypeError",
   "stackTrace":[  
      [  
         "/var/task/auth_login.py",
         17,
         "lambda_handler",
         "response = get_user(payload)"
      ],
      [  
         "/var/task/shifty_utils/__init__.py",
         22,
         "get_user",
         "table = dynamo.Table(user['company'] + '_users')"
      ]
   ]
}

Here is context for where it occurs:

def lambda_handler(event, context):
    payload = event['body']
    response = get_user(payload)

def get_user(user):
    try:
        table = dynamo.Table(user['company'] + '_users')
        response = table.get_item(
            Key={
                'userId': user['userId'],
                'position': user['position']
            }
        )
    except ClientError as e:
        print(e.response['Error']['Message'])
        return {'message': e.response['Error']['Message']}
    else:
        return response

Basically proxy integration seems to be reading in the event object as a JSON formatted string, as opposed to a dict, but here's what happens if I adjust my code for that:

{  
   "errorMessage":"the JSON object must be str, bytes or bytearray, not 'dict'",
   "errorType":"TypeError",
   "stackTrace":[  
      [  
         "/var/task/auth_login.py",
         15,
         "lambda_handler",
         "payload = json.loads(event)"
      ],
      [  
         "/var/lang/lib/python3.6/json/__init__.py",
         348,
         "loads",
         "'not {!r}'.format(s.__class__.__name__))"
      ]
   ]
}

I can't win. Any help is appreciated.

like image 522
Phito Avatar asked Nov 29 '22 22:11

Phito


2 Answers

You've identified the issue. However you're trying to convert a dict to dict.

This is what you have:

json.loads(event) # event is a dict

The body part as you have rightly identified is what is getting in as str.

This is what you should have:

json.loads(event['body'])

One more step is to make it client-agnostic.

if isinstance(event['body'], (unicode, str)):
    body = json.loads(event['body'])
like image 171
Oluwafemi Sule Avatar answered Dec 05 '22 14:12

Oluwafemi Sule


This is because event['body'] is not a dict but a str. (I ran into this problem when decoding an SQS triggered event)

In case if anyone ran into a problem when a value of json.loads(event['body']) is again not dict but str, here is a solution that decodes str to dict recursively.

import json

def to_dict(obj : object) -> dict:
    """ Serialize Object to Dictionary Recursively

    Arguments:
        obj {object} -- string, list, or dictionary to be serialize

    Returns:
        dict -- Serialized Dictionary
    """

    if isinstance(obj, dict):
        data = {}
        for k, v in obj.items():
            data[k] = to_dict(v)
        return data

    elif hasattr(obj, "_ast"):
        return to_dict(obj._ast())

    elif hasattr(obj, "__iter__") and not isinstance(obj, str):
        return [to_dict(v) for v in obj]

    elif hasattr(obj, "__dict__"):
        data = {key : to_dict(value) for key, value in obj.__dict__.items() if 
                  not callable(value) and not key.startswith('_')}

    elif isinstance(obj, str):
        try:
            data = {}
            obj = json.loads(obj)
            for k, v in obj.items():
                data[k] = to_dict(v)
                return data
        except:
            return obj
    else:
        return obj

Example Usage:

test = {'Records': ['{"s3": "{\\"bucket\\": \\"bucketname\\"}"}', '{"s3": "{\\"bucket\\": \\"bucketname\\"}"}']}

print(to_dict(test)['Records'][0]['s3']['bucket'])

This should print "bucketname".

like image 36
Kai Peng Avatar answered Dec 05 '22 13:12

Kai Peng