From e06460e41c8bda37d8677f28ebcdfda5861f9a06 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Wed, 19 Nov 2025 15:43:48 +0000 Subject: [PATCH 1/2] refactor: check if the input is a durable input --- .../execution.py | 14 ++++- tests/execution_test.py | 56 +++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/aws_durable_execution_sdk_python/execution.py b/src/aws_durable_execution_sdk_python/execution.py index e3e7be5..21cf4ce 100644 --- a/src/aws_durable_execution_sdk_python/execution.py +++ b/src/aws_durable_execution_sdk_python/execution.py @@ -217,8 +217,18 @@ 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 function is not being invoked as a durable function. " + "Please check the function configuration to ensure durability is turned on, " + "or use the testing SDK for local testing." + ) + raise ValueError(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..7e0e290 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( + ValueError, + match="The function is not being invoked as a durable function", + ): + 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( + ValueError, + match="The function is not being invoked as a durable function", + ): + test_handler(non_dict_event, lambda_context) From 8bb42d9641dcd1fe1d3e3ccda6547ec3957c8fbc Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Wed, 19 Nov 2025 16:39:40 +0000 Subject: [PATCH 2/2] refactor: address feedback --- src/aws_durable_execution_sdk_python/execution.py | 7 +++---- tests/execution_test.py | 8 ++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/aws_durable_execution_sdk_python/execution.py b/src/aws_durable_execution_sdk_python/execution.py index 21cf4ce..5b31d53 100644 --- a/src/aws_durable_execution_sdk_python/execution.py +++ b/src/aws_durable_execution_sdk_python/execution.py @@ -224,11 +224,10 @@ def wrapper(event: Any, context: LambdaContext) -> MutableMapping[str, Any]: invocation_input = DurableExecutionInvocationInput.from_dict(event) except (KeyError, TypeError, AttributeError) as e: msg = ( - "The function is not being invoked as a durable function. " - "Please check the function configuration to ensure durability is turned on, " - "or use the testing SDK for local testing." + "The payload is not the correct Durable Function input. " + "Please set DurableConfig on the AWS Lambda to invoke it as a Durable Function." ) - raise ValueError(msg) from e + 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 7e0e290..57c83c7 100644 --- a/tests/execution_test.py +++ b/tests/execution_test.py @@ -2036,8 +2036,8 @@ def test_handler(event: Any, context: DurableContext) -> dict: # WHEN the handler is invoked with a non-durable payload # THEN it raises a ValueError with a helpful message with pytest.raises( - ValueError, - match="The function is not being invoked as a durable function", + ExecutionError, + match="The payload is not the correct Durable Function input", ): test_handler(regular_event, lambda_context) @@ -2064,7 +2064,7 @@ def test_handler(event: Any, context: DurableContext) -> dict: # WHEN the handler is invoked with a non-dict event # THEN it raises a ValueError with a helpful message with pytest.raises( - ValueError, - match="The function is not being invoked as a durable function", + ExecutionError, + match="The payload is not the correct Durable Function input", ): test_handler(non_dict_event, lambda_context)