Environment
- moto: 5.2.2 (installed via
moto[server])
- Python: 3.12.3
- boto3: 1.40.49
- Reproduced with
moto_server (HTTP server mode). NOT reproducible with the @mock_aws decorator — see below.
How to reproduce
Against a running moto_server (default settings, MOTO_ACCOUNT_ID unset or set, doesn't matter):
import boto3
ENDPOINT = "http://localhost:4566"
REGION = "us-east-1"
sns = boto3.client("sns", endpoint_url=ENDPOINT, region_name=REGION)
rgt = boto3.client("resourcegroupstaggingapi", endpoint_url=ENDPOINT, region_name=REGION)
topic_arn = sns.create_topic(Name="repro-topic")["TopicArn"]
sns.tag_resource(ResourceArn=topic_arn, Tags=[{"Key": "instance", "Value": "test-instance"}])
result = rgt.get_resources(
ResourceTypeFilters=["sns"],
TagFilters=[{"Key": "instance", "Values": ["test-instance"]}],
)
for entry in result["ResourceTagMappingList"]:
print(entry["ResourceARN"])
print(len(result["ResourceTagMappingList"]), "entries")
Actual output (server mode):
arn:aws:sns:us-east-1:000000000000:repro-topic
arn:aws:sns:us-east-1:000000000000:repro-topic
2 entries
Expected: 1 entry — the topic was only created/tagged once.
Notably, this does NOT reproduce with the decorator
The same create → tag → get_resources sequence, run in-process with @mock_aws instead of against moto_server, returns exactly one clean entry:
import boto3
from moto import mock_aws
with mock_aws():
sns = boto3.client("sns", region_name="us-east-1")
topic_arn = sns.create_topic(Name="repro-topic")["TopicArn"]
sns.tag_resource(ResourceArn=topic_arn, Tags=[{"Key": "instance", "Value": "test-instance"}])
rgt = boto3.client("resourcegroupstaggingapi", region_name="us-east-1")
result = rgt.get_resources(
ResourceTypeFilters=["sns"],
TagFilters=[{"Key": "instance", "Values": ["test-instance"]}],
)
print(len(result["ResourceTagMappingList"]), "entries") # -> 1
I also checked iter_taggable_backends()/iter_tagged_resources() directly in-process under @mock_aws and got exactly one backend and one topic back, so the core resource-tagging logic (moto/core/resource_tagging.py) looks correct — the duplication seems to be introduced somewhere in the server-mode request dispatch path specifically, not in the shared model/generator logic.
This isn't specific to having 2 TagFilters — a single filter is enough to trigger it, which rules out a per-filter-yield bug in make_tag_matcher/_get_resources_generator.
Impact
Any consumer using moto_server (Docker image, CI, etc.) with a workflow that creates a tagged resource and then queries it back via resourcegroupstaggingapi.get_resources() gets duplicate ResourceTagMappingList entries for that resource.
Environment
moto[server])moto_server(HTTP server mode). NOT reproducible with the@mock_awsdecorator — see below.How to reproduce
Against a running
moto_server(default settings,MOTO_ACCOUNT_IDunset or set, doesn't matter):Actual output (server mode):
Expected: 1 entry — the topic was only created/tagged once.
Notably, this does NOT reproduce with the decorator
The same create → tag → get_resources sequence, run in-process with @mock_aws instead of against moto_server, returns exactly one clean entry:
I also checked iter_taggable_backends()/iter_tagged_resources() directly in-process under @mock_aws and got exactly one backend and one topic back, so the core resource-tagging logic (moto/core/resource_tagging.py) looks correct — the duplication seems to be introduced somewhere in the server-mode request dispatch path specifically, not in the shared model/generator logic.
This isn't specific to having 2 TagFilters — a single filter is enough to trigger it, which rules out a per-filter-yield bug in make_tag_matcher/_get_resources_generator.
Impact
Any consumer using moto_server (Docker image, CI, etc.) with a workflow that creates a tagged resource and then queries it back via resourcegroupstaggingapi.get_resources() gets duplicate ResourceTagMappingList entries for that resource.