diff --git a/src/aws_durable_execution_sdk_python/execution.py b/src/aws_durable_execution_sdk_python/execution.py index e3e7be5..5b31d53 100644 --- a/src/aws_durable_execution_sdk_python/execution.py +++ b/src/aws_durable_execution_sdk_python/execution.py @@ -217,8 +217,17 @@ def wrapper(event: Any, context: LambdaContext) -> MutableMapping[str, Any]: invocation_input = event service_client = invocation_input.service_client else: - logger.debug("durableExecutionArn: %s", event.get("DurableExecutionArn")) - invocation_input = DurableExecutionInvocationInput.from_dict(event) + try: + logger.debug( + "durableExecutionArn: %s", event.get("DurableExecutionArn") + ) + invocation_input = DurableExecutionInvocationInput.from_dict(event) + except (KeyError, TypeError, AttributeError) as e: + msg = ( + "The payload is not the correct Durable Function input. " + "Please set DurableConfig on the AWS Lambda to invoke it as a Durable Function." + ) + raise ExecutionError(msg) from e # Local runner always uses its own client, otherwise use custom or default if invocation_input.is_local_runner: diff --git a/tests/execution_test.py b/tests/execution_test.py index 68a06d1..57c83c7 100644 --- a/tests/execution_test.py +++ b/tests/execution_test.py @@ -2012,3 +2012,59 @@ def test_handler(event: Any, context: DurableContext) -> dict: # THEN the execution succeeds using the custom client assert result["Status"] == InvocationStatus.SUCCEEDED.value assert result["Result"] == '{"result": "success"}' + + +def test_durable_execution_with_non_durable_payload_raises_error(): + """Test that invoking a durable function with a regular event raises a helpful error.""" + + # GIVEN a durable function + @durable_execution + def test_handler(event: Any, context: DurableContext) -> dict: + return {"result": "success"} + + # GIVEN a regular Lambda event (not a durable execution payload) + regular_event = {"key": "value", "data": "test"} + + lambda_context = Mock() + lambda_context.aws_request_id = "test-request" + lambda_context.client_context = None + lambda_context.identity = None + lambda_context._epoch_deadline_time_in_ms = 1000000 # noqa: SLF001 + lambda_context.invoked_function_arn = None + lambda_context.tenant_id = None + + # WHEN the handler is invoked with a non-durable payload + # THEN it raises a ValueError with a helpful message + with pytest.raises( + ExecutionError, + match="The payload is not the correct Durable Function input", + ): + test_handler(regular_event, lambda_context) + + +def test_durable_execution_with_non_dict_event_raises_error(): + """Test that invoking a durable function with a non-dict event raises a helpful error.""" + + # GIVEN a durable function + @durable_execution + def test_handler(event: Any, context: DurableContext) -> dict: + return {"result": "success"} + + # GIVEN a non-dict event + non_dict_event = "not a dict" + + lambda_context = Mock() + lambda_context.aws_request_id = "test-request" + lambda_context.client_context = None + lambda_context.identity = None + lambda_context._epoch_deadline_time_in_ms = 1000000 # noqa: SLF001 + lambda_context.invoked_function_arn = None + lambda_context.tenant_id = None + + # WHEN the handler is invoked with a non-dict event + # THEN it raises a ValueError with a helpful message + with pytest.raises( + ExecutionError, + match="The payload is not the correct Durable Function input", + ): + test_handler(non_dict_event, lambda_context)