Skip to content

is_step_function_event crashes with AttributeError when event["Payload"] is a string #845

Description

@arun-leap

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.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions