Skip to content

bug: localstack using an xml string parser for json during cdklocal deploy #12643

Closed
@jbrown-athian

Description

@jbrown-athian

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

Using LocalStack Pro 4.2.0-4.4.0, when performing a cdklocal deploy --all, the localstack log indicates it is attempting to process an xml file when it contains json.

Console from localstack container below:

2025-05-16 17:18:06.376 | 2025-05-16T22:18:06.375  INFO --- [et.reactor-5] localstack.request.aws     : AWS cloudformation.DescribeStacks => 200
2025-05-16 17:18:06.378 | 2025-05-16T22:18:06.377  INFO --- [et.reactor-7] localstack.request.aws     : AWS sts.AssumeRole => 200
2025-05-16 17:18:06.381 | 2025-05-16T22:18:06.380  INFO --- [et.reactor-4] localstack.request.aws     : AWS cloudformation.DescribeStacks => 200
2025-05-16 17:18:06.382 | 2025-05-16T22:18:06.382  INFO --- [et.reactor-3] localstack.request.aws     : AWS sts.AssumeRole => 200
2025-05-16 17:18:06.383 | 2025-05-16T22:18:06.383  INFO --- [et.reactor-6] localstack.request.aws     : AWS sts.AssumeRole => 200
2025-05-16 17:18:06.387 | 2025-05-16T22:18:06.386  INFO --- [et.reactor-1] localstack.request.aws     : AWS s3.ListBuckets => 200
2025-05-16 17:18:06.389 | 2025-05-16T22:18:06.389  INFO --- [et.reactor-2] localstack.request.aws     : AWS sts.AssumeRole => 200
2025-05-16 17:18:06.391 | 2025-05-16T22:18:06.391  INFO --- [et.reactor-0] localstack.request.aws     : AWS s3.ListBuckets => 200
2025-05-16 17:18:06.392 | 2025-05-16T22:18:06.392  INFO --- [et.reactor-5] localstack.request.aws     : AWS s3.ListBuckets => 200
2025-05-16 17:18:06.396 | 2025-05-16T22:18:06.396  INFO --- [et.reactor-7] localstack.request.aws     : AWS s3.ListBuckets => 200
2025-05-16 17:18:06.397 | 2025-05-16T22:18:06.397  INFO --- [et.reactor-6] localstack.request.aws     : AWS s3.ListBuckets => 200
2025-05-16 17:18:06.398 | 2025-05-16T22:18:06.398  INFO --- [et.reactor-3] localstack.request.aws     : AWS s3.ListBuckets => 200
2025-05-16 17:18:06.400 | 2025-05-16T22:18:06.400  INFO --- [et.reactor-4] localstack.request.aws     : AWS sts.AssumeRole => 200
2025-05-16 17:18:06.401 | 2025-05-16T22:18:06.400  INFO --- [et.reactor-1] localstack.request.aws     : AWS s3.ListBuckets => 200
2025-05-16 17:18:06.407 | 2025-05-16T22:18:06.407  INFO --- [et.reactor-0] localstack.request.aws     : AWS s3.ListBuckets => 200
2025-05-16 17:18:06.407 | 2025-05-16T22:18:06.407  INFO --- [et.reactor-2] localstack.request.aws     : AWS s3.ListBuckets => 200
2025-05-16 17:18:06.408 | 2025-05-16T22:18:06.408  INFO --- [et.reactor-5] localstack.request.aws     : AWS s3.ListBuckets => 200
2025-05-16 17:18:06.409 | 2025-05-16T22:18:06.409  INFO --- [et.reactor-3] localstack.request.aws     : AWS s3.ListBuckets => 200
2025-05-16 17:18:06.410 | 2025-05-16T22:18:06.410  INFO --- [et.reactor-7] localstack.request.aws     : AWS s3.ListBuckets => 200
2025-05-16 17:18:06.414 | 2025-05-16T22:18:06.414  INFO --- [et.reactor-4] localstack.request.aws     : AWS s3.ListBuckets => 200
2025-05-16 17:18:06.417 | 2025-05-16T22:18:06.416  INFO --- [et.reactor-6] localstack.request.aws     : AWS s3.ListBuckets => 200
2025-05-16 17:18:06.427 | 2025-05-16T22:18:06.421 ERROR --- [et.reactor-1] l.aws.handlers.logging     : exception during call chain
2025-05-16 17:18:06.427 | Traceback (most recent call last):
2025-05-16 17:18:06.427 |   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/localstack/aws/protocol/parser.py", line 776, in _parse_xml_string_to_dom
2025-05-16 17:18:06.427 |     parser.feed(xml_string)
2025-05-16 17:18:06.427 | xml.etree.ElementTree.ParseError: not well-formed (invalid token): line 1, column 0
2025-05-16 17:18:06.427 | 
2025-05-16 17:18:06.427 | The above exception was the direct cause of the following exception:
2025-05-16 17:18:06.427 | 
2025-05-16 17:18:06.427 | Traceback (most recent call last):
2025-05-16 17:18:06.427 |   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/rolo/gateway/chain.py", line 166, in handle
2025-05-16 17:18:06.427 |     handler(self, self.context, response)
2025-05-16 17:18:06.427 |   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/localstack/aws/handlers/service.py", line 63, in __call__
2025-05-16 17:18:06.427 |     return self.parse_and_enrich(context)
2025-05-16 17:18:06.427 |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-05-16 17:18:06.427 |   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/localstack/aws/handlers/service.py", line 67, in parse_and_enrich
2025-05-16 17:18:06.427 |     operation, instance = parser.parse(context.request)
2025-05-16 17:18:06.427 |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-05-16 17:18:06.427 |   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/localstack/aws/protocol/parser.py", line 173, in wrapper
2025-05-16 17:18:06.427 |     return func(*args, **kwargs)
2025-05-16 17:18:06.427 |            ^^^^^^^^^^^^^^^^^^^^^
2025-05-16 17:18:06.427 |   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/localstack/aws/protocol/parser.py", line 1078, in parse
2025-05-16 17:18:06.427 |     return super().parse(request)
2025-05-16 17:18:06.427 |            ^^^^^^^^^^^^^^^^^^^^^^
2025-05-16 17:18:06.427 |   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/localstack/aws/protocol/parser.py", line 173, in wrapper
2025-05-16 17:18:06.427 |     return func(*args, **kwargs)
2025-05-16 17:18:06.427 |            ^^^^^^^^^^^^^^^^^^^^^
2025-05-16 17:18:06.427 |   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/localstack/aws/protocol/parser.py", line 574, in parse
2025-05-16 17:18:06.427 |     self._parse_payload(request, shape, shape.members, uri_params, final_parsed)
2025-05-16 17:18:06.427 |   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/localstack/aws/protocol/parser.py", line 610, in _parse_payload
2025-05-16 17:18:06.427 |     original_parsed = self._initial_body_parse(request)
2025-05-16 17:18:06.427 |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-05-16 17:18:06.427 |   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/localstack/aws/protocol/parser.py", line 673, in _initial_body_parse
2025-05-16 17:18:06.427 |     return self._parse_xml_string_to_dom(body)
2025-05-16 17:18:06.427 |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-05-16 17:18:06.427 |   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/localstack/aws/protocol/parser.py", line 779, in _parse_xml_string_to_dom
2025-05-16 17:18:06.427 |     raise ProtocolParserError(
2025-05-16 17:18:06.427 | localstack.aws.protocol.parser.ProtocolParserError: Unable to parse request (not well-formed (invalid token): line 1, column 0), invalid XML received:
2025-05-16 17:18:06.427 | b'{\n "Resources": {\n  "eventbusv2FED535EF": {\n   "Type": "AWS::Events::EventBus",\n   "Properties": {\n    "Name": "auth-platform-event-bus-v2-sandbox",\n    "Tags": [\n     {\n      "Key": "athian:app",\n      "Value": "auth-platform"\n     },\n     {\n      "Key": "athian:stage",\n      "Value": "sandbox"\n     }\n    ]\n   },\n   "Metadata": {\n    "aws:cdk:path": "auth-platform-stateful-stack-v2-sandbox/event-bus-v2/Resource"\n   }\n  },\n  "eventbusv2SubscriptionToPlatform5F6A76A1": {\n   "Type": "AWS::Events::Rule",\n   "Properties": {\n    "EventBusName": "default",\n    "EventPattern": {\n     "detail-type": [\n      "organization-created",\n      "organization-updated",\n      "organization-deactivated",\n      "organization-reactivated",\n      "assign-user-role",\n      "token-rotation-trigger"\n     ]\n    },\n    "Name": "auth-platform-sub2plat",\n    "State": "ENABLED",\n    "Targets": [\n     {\n      "Arn": {\n       "Fn::GetAtt": [\n        "eventbusv2FED535EF",\n        "Arn"\n       ]\n      },\n      "Id": "Target0",\n      "RoleArn": {\n       "Fn::GetAtt": [\n        "eventbusv2SubscriptionToPlatformEventsRoleDFBEB861",\n        "Arn"\n       ]\n      }\n     }\n    ]\n   },\n   "Metadata": {\n    "aws:cdk:path": "auth-platform-stateful-stack-v2-sandbox/event-bus-v2/SubscriptionToPlatform/Resource"\n   }\n  },\n  "eventbusv2SubscriptionToPlatformEventsRoleDFBEB861": {\n   "Type": "AWS::IAM::Role",\n   "Properties": {\n    "AssumeRolePolicyDocument": {\n     "Statement": [\n      {\n       "Action": "sts:AssumeRole",\n       "Effect": "Allow",\n       "Principal": {\n        "Service": "events.amazonaws.com"\n       }\n      }\n     ],\n     "Version": "2012-10-17"\n    },\n    "Tags": [\n     {\n      "Key": "athian:app",\n      "Value": "auth-platform"\n     },\n     {\n      "Key": "athian:stage",\n      "Value": "sandbox"\n     }\n    ]\n   },\n   "Metadata": {\n    "aws:cdk:path": "auth-platform-stateful-stack-v2-sandbox/event-bus-v2/SubscriptionToPlatform/EventsRole/Resource"\n   }\n  },\n  "eventbusv2SubscriptionToPlatformEventsRoleDefaultPolicyD1BEC8CC": {\n   "Type": "AWS::IAM::Policy",\n   "Properties": {\n    "PolicyDocument": {\n     "Statement": [\n      {\n       "Action": "events:PutEvents",\n       "Effect": "Allow",\n       "Resource": {\n        "Fn::GetAtt": [\n         "eventbusv2FED535EF",\n         "Arn"\n        ]\n       }\n      }\n     ],\n     "Version": "2012-10-17"\n    },\n    "PolicyName": "eventbusv2SubscriptionToPlatformEventsRoleDefaultPolicyD1BEC8CC",\n    "Roles": [\n     {\n      "Ref": "eventbusv2SubscriptionToPlatformEventsRoleDFBEB861"\n     }\n    ]\n   },\n   "Metadata": {\n    "aws:cdk:path": "auth-platform-stateful-stack-v2-sandbox/event-bus-v2/SubscriptionToPlatform/EventsRole/DefaultPolicy/Resource"\n   }\n  },\n  "identitytable76548FE3": {\n   "Type": "AWS::DynamoDB::Table",\n   "Properties": {\n    "AttributeDefinitions": [\n     {\n      "AttributeName": "pk",\n      "AttributeType": "S"\n     },\n     {\n      "AttributeName": "sk",\n      "AttributeType": "S"\n     },\n     {\n      "AttributeName": "gsi_1_pk",\n      "AttributeType": "S"\n     },\n     {\n      "AttributeName": "gsi_1_sk",\n      "AttributeType": "S"\n     },\n     {\n      "AttributeName": "gsi_2_pk",\n      "AttributeType": "S"\n     },\n     {\n      "AttributeName": "gsi_2_sk",\n      "AttributeType": "S"\n     }\n    ],\n    "BillingMode": "PAY_PER_REQUEST",\n    "ContributorInsightsSpecification": {\n     "Enabled": false\n    },\n    "GlobalSecondaryIndexes": [\n     {\n      "IndexName": "gsi_1",\n      "KeySchema": [\n       {\n        "AttributeName": "gsi_1_pk",\n        "KeyType": "HASH"\n       },\n       {\n        "AttributeName": "gsi_1_sk",\n        "KeyType": "RANGE"\n       }\n      ],\n      "Projection": {\n       "ProjectionType": "ALL"\n      }\n     },\n     {\n      "IndexName": "gsi_2",\n      "KeySchema": [\n       {\n        "AttributeName": "gsi_2_pk",\n        "KeyType": "HASH
...

Expected Behavior

Deploy should occur as expected.

How are you starting LocalStack?

With a docker-compose file:

version: "3.8"

services:
  localstack:
    container_name: localstack-main
    image: localstack/localstack-pro:4.4.0 # Use the Pro image
    ports:
      - "127.0.0.1:4566:4566" # LocalStack Edge Proxy (main port)
      - "127.0.0.1:4510-4559:4510-4559" # External service ports
      - "127.0.0.1:8080:8080" # Optional: LocalStack Web UI
      - "443:4566" # HTTP gateway (Pro) :contentReference[oaicite:0]{index=0}
      - "80:4566" # HTTPS gateway (Pro) :contentReference[oaicite:0]{index=0}
    
    environment:
      - DEBUG=1
      - LOCALSTACK_IMAGE_TAG=4.4.0 # pin a Pro version :contentReference[oaicite:1]{index=1}
      - LOCALSTACK_AUTH_TOKEN=${LOCALSTACK_AUTH_TOKEN} # this is set in the CI/CD pipeline or on the local machine
      - SERVICES=acm,apigateway,s3,ecs,ec2,elbv2,iam,sts,ssm,cloudformation,logs,ecr,route53,events # Add required services
      - ACTIVATE_PRO=1 # optional, but recommended :contentReference[oaicite:2]{index=2}
      - ECR_AUTO_CREATE_REPOSITORIES=1 # Optional: May simplify ECR interactions
      - DOCKER_HOST=unix:///var/run/docker.sock # To allow LocalStack to interact with Docker (for ECS/Lambda)
      - LOCALSTACK_HOST=localhost.localstack.cloud:4566
    volumes:
      - "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack"
      - "/var/run/docker.sock:/var/run/docker.sock" # Mount Docker socket

volumes:
  localstack_data:

Steps To Reproduce

I am using a bash script:

#!/bin/bash
set -e

export IMAGE_NAME=localstack/localstack-pro:4.4.0
export MAIN_CONTAINER_NAME=localstack-main
export AWS_ACCESS_KEY_ID=test
export AWS_SECRET_ACCESS_KEY=test
export AWS_DEFAULT_REGION=us-east-1 # Or your preferred region
export CDK_DEFAULT_ACCOUNT=000000000000
export CDK_DEFAULT_REGION=us-east-1
# Point CDK/SDK to LocalStack Edge URL
export AWS_ENDPOINT_URL=http://localhost:4566
export AWS_ENDPOINT_URL_S3=http://localhost:4566
# Required for CDK v2 with newer AWS SDK versions
export AWS_EC2_ENDPOINT=http://localhost:4566
export AWS_CLOUDFORMATION_ENDPOINT=http://localhost:4566
export AWS_ECS_ENDPOINT=http://localhost:4566
export AWS_ELBV2_ENDPOINT=http://localhost:4566
export AWS_IAM_ENDPOINT=http://localhost:4566
export AWS_STS_ENDPOINT=http://localhost:4566
export AWS_ECR_ENDPOINT=http://localhost:4566
export AWS_ROUTE53_ENDPOINT=http://localhost:4566


docker-compose down || true
docker-compose pull localstack
docker-compose up -d

echo "⏳ Waiting for LocalStack to be ready..."
localstack wait -t 60


cd ./cdk

echo "📦 Installing dependencies..."
npm install

echo "🔨 Building the project..."
npm run build

echo "🚀 Bootstrapping the CDK app..."
npx cdklocal bootstrap --endpoint-url $AWS_ENDPOINT_URL --region $AWS_DEFAULT_REGION

echo "🚢 Deploying using cdk deploy..."
npx cdklocal deploy --all \
  --require-approval never \
  --endpoint-url $AWS_ENDPOINT_URL \
  --region $AWS_DEFAULT_REGION

Environment

- OS: MacOS 15.4.1
- LocalStack: 
  LocalStack version: 4.4.0
  LocalStack Docker image sha:  
  LocalStack build date:  LOCALSTACK_BUILD_DATE=2025-05-08
  LocalStack build git hash: LOCALSTACK_BUILD_GIT_HASH=b0d9b9da1

Anything else?

If I bootstrap as scripted above, but perform a npx cdklocal synth > template.yml and then use cloudformation to deploy it as such, it succeeds:

echo "🚢 Deploying using cloudformation..."
aws cloudformation deploy \
   --template-file template.yml \
   --stack-name LocalStackFargateStaticSite \
   --capabilities CAPABILITY_IAM \
   --endpoint-url $AWS_ENDPOINT_URL \
   --region $AWS_DEFAULT_REGION

Sample project that breaks:

localstack-fargate-cdk.zip

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions