Repository: getsentry/sentry-python

Issue:
Lambda via ApiGateway Console has no headers
When testing a Lambda via ApiGateway (HTTP Call) everything's fine.

But when I call the same endpoint using [AWS' ApiGateway Console](https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-test-method.html#how-to-test-method-console), I get this error.
Since headers are not passed in this specific context, `headers = None`.

```
{
   "errorMessage":"'NoneType' object has no attribute 'get'",
   "errorType":"AttributeError",
   "stackTrace":[
      "  File \"/var/task/sentry_sdk/integrations/aws_lambda.py\", line 138, in sentry_handler\n    transaction = Transaction.continue_from_headers(\n",
      "  File \"/var/task/sentry_sdk/tracing.py\", line 291, in continue_from_headers\n    headers.get(\"sentry-trace\"), **kwargs\n"
   ]
}
```




Discussion:

Resolving patch:
diff --git a/sentry_sdk/integrations/aws_lambda.py b/sentry_sdk/integrations/aws_lambda.py
--- a/sentry_sdk/integrations/aws_lambda.py
+++ b/sentry_sdk/integrations/aws_lambda.py
@@ -134,7 +134,10 @@ def sentry_handler(aws_event, aws_context, *args, **kwargs):
                     # Starting the thread to raise timeout warning exception
                     timeout_thread.start()
 
-            headers = request_data.get("headers", {})
+            headers = request_data.get("headers")
+            # AWS Service may set an explicit `{headers: None}`, we can't rely on `.get()`'s default.
+            if headers is None:
+                headers = {}
             transaction = Transaction.continue_from_headers(
                 headers, op="serverless.function", name=aws_context.function_name
             )
@@ -337,11 +340,15 @@ def event_processor(sentry_event, hint, start_time=start_time):
         if _should_send_default_pii():
             user_info = sentry_event.setdefault("user", {})
 
-            id = aws_event.get("identity", {}).get("userArn")
+            identity = aws_event.get("identity")
+            if identity is None:
+                identity = {}
+
+            id = identity.get("userArn")
             if id is not None:
                 user_info.setdefault("id", id)
 
-            ip = aws_event.get("identity", {}).get("sourceIp")
+            ip = identity.get("sourceIp")
             if ip is not None:
                 user_info.setdefault("ip_address", ip)
 
@@ -363,7 +370,11 @@ def event_processor(sentry_event, hint, start_time=start_time):
 def _get_url(aws_event, aws_context):
     # type: (Any, Any) -> str
     path = aws_event.get("path", None)
-    headers = aws_event.get("headers", {})
+
+    headers = aws_event.get("headers")
+    if headers is None:
+        headers = {}
+
     host = headers.get("Host", None)
     proto = headers.get("X-Forwarded-Proto", None)
     if proto and host and path:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -18,7 +18,7 @@ def get_file_text(file_name):
     with open(os.path.join(here, file_name)) as in_file:
         return in_file.read()
 
-    
+
 setup(
     name="sentry-sdk",
     version="0.19.4",
@@ -31,7 +31,7 @@ def get_file_text(file_name):
     },
     description="Python client for Sentry (https://sentry.io)",
     long_description=get_file_text("README.md"),
-    long_description_content_type='text/markdown',
+    long_description_content_type="text/markdown",
     packages=find_packages(exclude=("tests", "tests.*")),
     # PEP 561
     package_data={"sentry_sdk": ["py.typed"]},


Test patch: