Expected Behavior
When a Lambda is invoked with an event that contains a Payload key whose value is a string (e.g. a Step Functions Map state that wraps each item as {"Payload": "<s3 object key>"}), the wrapper should classify the trigger as unknown/not-step-function and continue silently.
Actual Behavior
is_step_function_event assumes event["Payload"] is a dict. With a string value it raises AttributeError: 'str' object has no attribute 'get' inside _before, and because self.trigger_tags is then never assigned, _after raises a second AttributeError: '_LambdaDecorator' object has no attribute 'trigger_tags'. Both are caught and logged by the wrapper, so the function itself is unaffected — but every invocation emits two ERROR-level tracebacks. At our volume that is several hundred spurious error logs per day, which drowns real errors and skews log-based monitors.
The culprit is the unwrap in is_step_function_event (datadog_lambda/trigger.py):
event = event.get("Payload", event)
# JSONPath style
if "Execution" in event and "StateMachine" in event and "State" in event:
return True
# JSONata style
dd_context = event.get("_datadog") # <- AttributeError when event is now a str
"Execution" in event happens to work on a str (substring check), then event.get("_datadog") crashes. The isinstance(event, dict) guard added to parse_event_source for #532 only protects the top-level event, not the unwrapped Payload value.
Steps to Reproduce the Problem
from datadog_lambda.trigger import is_step_function_event
is_step_function_event({"Payload": "some/s3/object-key.json"})
# AttributeError: 'str' object has no attribute 'get'
Any state machine using the documented Legacy Lambda pattern with a non-dict payload reproduces it end to end, e.g. a Map state with:
Parameters:
Payload.$: "$$.Map.Item.Value" # items are plain strings
Specifications
- Datadog Lambda Layer version: reproduced on both
Datadog-Python312:119 (datadog-lambda 8.119.0) and Datadog-Python312:126 (datadog-lambda 8.126.0, latest at time of filing)
- PyPI package: also reproduced against
datadog-lambda==8.126.0 installed directly (see snippet above), so the bug is in the library, not the layer packaging
- Python version: 3.12 (Lambda runtime
python3.12)
- Instrumentation: handler wrapped via the standard layer redirect (
datadog_lambda.handler.handler + DD_LAMBDA_HANDLER), deployed with serverless-plugin-datadog 5.122.0 with enableDDTracing: true
- Trigger: Step Functions state machine, Task state invoking the function directly (
Resource: <function ARN>) from inside a Map state whose Parameters wrap each item as {"Payload": "<string>"}
- The stacktrace line numbers below are from the 8.119.0 layer build; the same code path exists unchanged in 8.126.0 (
is_step_function_event, event = event.get("Payload", event) followed by event.get("_datadog"))
Stacktrace
[ERROR] Error 'str' object has no attribute 'get'. Traceback: Traceback (most recent call last):
File "./python/lib/python3.12/site-packages/datadog_lambda/wrapper.py", line 244, in _before
File "./python/lib/python3.12/site-packages/datadog_lambda/trigger.py", line 366, in extract_trigger_tags
File "./python/lib/python3.12/site-packages/datadog_lambda/trigger.py", line 161, in parse_event_source
File "./python/lib/python3.12/site-packages/datadog_lambda/trigger.py", line 424, in is_step_function_event
AttributeError: 'str' object has no attribute 'get'
followed on the same invocation by:
[ERROR] Error '_LambdaDecorator' object has no attribute 'trigger_tags'. Traceback: Traceback (most recent call last):
File "./python/lib/python3.12/site-packages/datadog_lambda/wrapper.py", line 302, in _after
AttributeError: '_LambdaDecorator' object has no attribute 'trigger_tags'
Suggested fix
Guard the unwrapped value in is_step_function_event:
event = event.get("Payload", event)
if not isinstance(event, dict):
return False
(A defensive getattr(self, "trigger_tags", None) in _after would also stop the second, derivative error from masking the first.)
Expected Behavior
When a Lambda is invoked with an event that contains a
Payloadkey whose value is a string (e.g. a Step Functions Map state that wraps each item as{"Payload": "<s3 object key>"}), the wrapper should classify the trigger as unknown/not-step-function and continue silently.Actual Behavior
is_step_function_eventassumesevent["Payload"]is a dict. With a string value it raisesAttributeError: 'str' object has no attribute 'get'inside_before, and becauseself.trigger_tagsis then never assigned,_afterraises a secondAttributeError: '_LambdaDecorator' object has no attribute 'trigger_tags'. Both are caught and logged by the wrapper, so the function itself is unaffected — but every invocation emits two ERROR-level tracebacks. At our volume that is several hundred spurious error logs per day, which drowns real errors and skews log-based monitors.The culprit is the unwrap in
is_step_function_event(datadog_lambda/trigger.py):"Execution" in eventhappens to work on a str (substring check), thenevent.get("_datadog")crashes. Theisinstance(event, dict)guard added toparse_event_sourcefor #532 only protects the top-level event, not the unwrappedPayloadvalue.Steps to Reproduce the Problem
Any state machine using the documented Legacy Lambda pattern with a non-dict payload reproduces it end to end, e.g. a Map state with:
Specifications
Datadog-Python312:119(datadog-lambda 8.119.0) andDatadog-Python312:126(datadog-lambda 8.126.0, latest at time of filing)datadog-lambda==8.126.0installed directly (see snippet above), so the bug is in the library, not the layer packagingpython3.12)datadog_lambda.handler.handler+DD_LAMBDA_HANDLER), deployed withserverless-plugin-datadog5.122.0 withenableDDTracing: trueResource: <function ARN>) from inside a Map state whoseParameterswrap each item as{"Payload": "<string>"}is_step_function_event,event = event.get("Payload", event)followed byevent.get("_datadog"))Stacktrace
followed on the same invocation by:
Suggested fix
Guard the unwrapped value in
is_step_function_event:(A defensive
getattr(self, "trigger_tags", None)in_afterwould also stop the second, derivative error from masking the first.)