Summary
The arn:aws:states:::states:startExecution.sync / .sync:2 service integration (a parent state machine starting a child state machine) fails under the Step Functions parser backend with States.Runtime / cause 'Input'.
Root cause: the parser passes the ASL PascalCase parameter keys (Input, StateMachineArn) straight to boto3's start_execution, whose members are lowercase (stateMachineArn / name / input / traceHeader). botocore's serializer then raises KeyError: 'Input'.
This appears to be a regression introduced when the parser was ported from LocalStack (#9142): the base StateTaskService._normalise_parameters / _normalise_response — which in LocalStack convert the request/response between SFN PascalCase and the boto member casing — were reduced to pass in moto, while the helper methods they used to call (_to_boto_request / _from_boto_response) were kept but are now never invoked.
It goes unnoticed because the SFN→SNS / →DynamoDB / →SQS integration tests use services whose boto members are already PascalCase (TopicArn, Message, TableName), so verbatim passthrough happens to work. There is no SFN→SFN (startExecution.sync) integration test, and start_execution is the case where SFN's own API members are lowercase.
How to reproduce
import json, time
import boto3
from moto.server import ThreadedMotoServer
from moto.core.config import default_user_config
# Enable the ASL interpreter (parser backend)
default_user_config["stepfunctions"]["execute_state_machine"] = True
srv = ThreadedMotoServer(port=5000)
srv.start()
sfn = boto3.client("stepfunctions", endpoint_url="http://localhost:5000",
region_name="us-east-1", aws_access_key_id="x", aws_secret_access_key="x")
role = "arn:aws:iam::123456789012:role/sfn"
child = sfn.create_state_machine(
name="child", roleArn=role,
definition=json.dumps({"StartAt": "P", "States": {"P": {"Type": "Pass", "End": True}}}),
)["stateMachineArn"]
parent = sfn.create_state_machine(
name="parent", roleArn=role,
definition=json.dumps({
"StartAt": "CallChild",
"States": {
"CallChild": {
"Type": "Task",
"Resource": "arn:aws:states:::states:startExecution.sync:2",
"Parameters": {"Input": {"foo": "bar"}, "StateMachineArn": child},
"End": True,
}
},
}),
)["stateMachineArn"]
exe = sfn.start_execution(stateMachineArn=parent, name="r1", input="{}")["executionArn"]
for _ in range(40):
d = sfn.describe_execution(executionArn=exe)
if d["status"] != "RUNNING":
break
time.sleep(0.25)
print("STATUS:", d["status"]) # FAILED
print("ERROR:", d.get("error")) # States.Runtime
print("CAUSE:", d.get("cause")) # An error occurred while executing the state 'CallChild' ... 'Input'
srv.stop()
Expected
The parent execution reaches SUCCEEDED (the child runs and the sync:2 task returns its describe-execution output), as it does on real AWS Step Functions.
Actual
STATUS: FAILED
ERROR: States.Runtime
CAUSE: An error occurred while executing the state 'CallChild' (entered at the event id #4). 'Input'
The underlying exception (visible if you log ExecutionState._from_error) is:
File ".../botocore/serialize.py", line 473, in _serialize_type_structure
member_shape = members[member_key]
~~~~~~~^^^^^^^^^^^^
KeyError: 'Input'
from state_task_service_sfn.py::_eval_service_task → getattr(sfn_client, "start_execution")(**normalised_parameters) with normalised_parameters = {"Input": "...", "StateMachineArn": "..."}.
Pointers
moto/stepfunctions/parser/asl/component/state/exec/state_task/service/state_task_service.py — base _normalise_parameters (and _normalise_response) are pass; the _to_boto_request / _from_boto_response helpers are present but never called.
- Compare LocalStack's equivalent base
_normalise_parameters, which looks up the boto input_shape and calls _to_boto_request(parameters, input_shape) to convert the casing before the boto call.
state_task_service_sfn.py::_normalise_parameters only JSON-stringifies Input; it relies on the (now-missing) base normalisation to fix key casing.
Environment
- moto 5.1.22
- boto3 1.42.93 / botocore 1.42.93
- Python 3.12.13
Summary
The
arn:aws:states:::states:startExecution.sync/.sync:2service integration (a parent state machine starting a child state machine) fails under the Step Functions parser backend withStates.Runtime/ cause'Input'.Root cause: the parser passes the ASL PascalCase parameter keys (
Input,StateMachineArn) straight toboto3'sstart_execution, whose members are lowercase (stateMachineArn/name/input/traceHeader). botocore's serializer then raisesKeyError: 'Input'.This appears to be a regression introduced when the parser was ported from LocalStack (#9142): the base
StateTaskService._normalise_parameters/_normalise_response— which in LocalStack convert the request/response between SFN PascalCase and the boto member casing — were reduced topassin moto, while the helper methods they used to call (_to_boto_request/_from_boto_response) were kept but are now never invoked.It goes unnoticed because the SFN→SNS / →DynamoDB / →SQS integration tests use services whose boto members are already PascalCase (
TopicArn,Message,TableName), so verbatim passthrough happens to work. There is no SFN→SFN (startExecution.sync) integration test, andstart_executionis the case where SFN's own API members are lowercase.How to reproduce
Expected
The parent execution reaches
SUCCEEDED(the child runs and thesync:2task returns its describe-execution output), as it does on real AWS Step Functions.Actual
The underlying exception (visible if you log
ExecutionState._from_error) is:from
state_task_service_sfn.py::_eval_service_task→getattr(sfn_client, "start_execution")(**normalised_parameters)withnormalised_parameters = {"Input": "...", "StateMachineArn": "..."}.Pointers
moto/stepfunctions/parser/asl/component/state/exec/state_task/service/state_task_service.py— base_normalise_parameters(and_normalise_response) arepass; the_to_boto_request/_from_boto_responsehelpers are present but never called._normalise_parameters, which looks up the botoinput_shapeand calls_to_boto_request(parameters, input_shape)to convert the casing before the boto call.state_task_service_sfn.py::_normalise_parametersonly JSON-stringifiesInput; it relies on the (now-missing) base normalisation to fix key casing.Environment