Skip to content

Failure to load and dump template which has FindInMap inside GetAtt #120

Description

@pnickerson-cashstar

Here is a valid CloudFormation template, which can be used to successfully create a stack, and the resources and tag show up as expected:

AWSTemplateFormatVersion: "2010-09-09"

Mappings:
  S3Domains:
    Bucket1:
      DomainResource: S3Bucket1
      DomainAttribute: DomainName

Transform: AWS::LanguageExtensions

Resources:
  S3Bucket1:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: my-bucket-one

  S3Bucket2:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: my-bucket-two
      Tags:
        - Key: Bucket1Domain
          Value:
            Fn::GetAtt:
              - Fn::FindInMap:
                - S3Domains
                - Bucket1
                - DomainResource
              - Fn::FindInMap:
                - S3Domains
                - Bucket1
                - DomainAttribute

AWS documentation says that FindInMap can be used inside of GetAtt here: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getatt.html#getatt-supported-functions

However, when I try to parse this template in a Python 3.13.3 script using cfn-flip 1.3.0, I get an error:

import cfn_flip
file = open("template1.yaml", "r")
file_content = file.read()
loaded_yaml = cfn_flip.load_yaml(file_content)
cfn_flip.dump_yaml(loaded_yaml)
Traceback (most recent call last):
  File "<python-input-5>", line 1, in <module>
    cfn_flip.dump_yaml(loaded_yaml)
    ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
  File "/home/pnickerson/.local/lib/python3.13/site-packages/cfn_flip/__init__.py", line 42, in dump_yaml
    return yaml.dump(
           ~~~~~~~~~^
        data,
        ^^^^^
    ...<3 lines>...
        width=config.max_col_width
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/usr/lib64/python3.13/site-packages/yaml/__init__.py", line 253, in dump
    return dump_all([data], stream, Dumper=Dumper, **kwds)
  File "/usr/lib64/python3.13/site-packages/yaml/__init__.py", line 241, in dump_all
    dumper.represent(data)
    ~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 27, in represent
    node = self.represent_data(data)
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 48, in represent_data
    node = self.yaml_representers[data_types[0]](self, data)
  File "/home/pnickerson/.local/lib/python3.13/site-packages/cfn_flip/yaml_dumper.py", line 107, in map_representer
    return dumper.represent_mapping(TAG_MAP, value, flow_style=False)
           ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 118, in represent_mapping
    node_value = self.represent_data(item_value)
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 48, in represent_data
    node = self.yaml_representers[data_types[0]](self, data)
  File "/home/pnickerson/.local/lib/python3.13/site-packages/cfn_flip/yaml_dumper.py", line 107, in map_representer
    return dumper.represent_mapping(TAG_MAP, value, flow_style=False)
           ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 118, in represent_mapping
    node_value = self.represent_data(item_value)
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 48, in represent_data
    node = self.yaml_representers[data_types[0]](self, data)
  File "/home/pnickerson/.local/lib/python3.13/site-packages/cfn_flip/yaml_dumper.py", line 107, in map_representer
    return dumper.represent_mapping(TAG_MAP, value, flow_style=False)
           ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 118, in represent_mapping
    node_value = self.represent_data(item_value)
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 48, in represent_data
    node = self.yaml_representers[data_types[0]](self, data)
  File "/home/pnickerson/.local/lib/python3.13/site-packages/cfn_flip/yaml_dumper.py", line 107, in map_representer
    return dumper.represent_mapping(TAG_MAP, value, flow_style=False)
           ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 118, in represent_mapping
    node_value = self.represent_data(item_value)
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 48, in represent_data
    node = self.yaml_representers[data_types[0]](self, data)
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 199, in represent_list
    return self.represent_sequence('tag:yaml.org,2002:seq', data)
           ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 92, in represent_sequence
    node_item = self.represent_data(item)
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 48, in represent_data
    node = self.yaml_representers[data_types[0]](self, data)
  File "/home/pnickerson/.local/lib/python3.13/site-packages/cfn_flip/yaml_dumper.py", line 107, in map_representer
    return dumper.represent_mapping(TAG_MAP, value, flow_style=False)
           ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 118, in represent_mapping
    node_value = self.represent_data(item_value)
  File "/usr/lib64/python3.13/site-packages/yaml/representer.py", line 48, in represent_data
    node = self.yaml_representers[data_types[0]](self, data)
  File "/home/pnickerson/.local/lib/python3.13/site-packages/cfn_flip/yaml_dumper.py", line 105, in map_representer
    return fn_representer(dumper, key[4:], value[key])
  File "/home/pnickerson/.local/lib/python3.13/site-packages/cfn_flip/yaml_dumper.py", line 80, in fn_representer
    value = ".".join(value)
TypeError: sequence item 0: expected str instance, ODict found

If I alter the template to no longer have FindInMap in GetAtt, I can run the Python fine.

AWSTemplateFormatVersion: "2010-09-09"

Mappings:
  S3Domains:
    Bucket1:
      DomainResource: S3Bucket1
      DomainAttribute: DomainName

Transform: AWS::LanguageExtensions

Resources:
  S3Bucket1:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: my-bucket-one

  S3Bucket2:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: my-bucket-two
      Tags:
        - Key: Bucket1Domain
          Value:
            Fn::GetAtt:
              - S3Bucket1
              - DomainName
"AWSTemplateFormatVersion: '2010-09-09'\nMappings:\n  S3Domains:\n    Bucket1:\n      DomainResource: S3Bucket1\n      DomainAttribute: DomainName\nTransform: AWS::LanguageExtensions\nResources:\n  S3Bucket1:\n    Type: AWS::S3::Bucket\n    Properties:\n      BucketName: my-bucket-one\n  S3Bucket2:\n    Type: AWS::S3::Bucket\n    Properties:\n      BucketName: my-bucket-two\n      Tags:\n        - Key: Bucket1Domain\n          Value: !GetAtt 'S3Bucket1.DomainName'\n"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions