We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Incorrect rule: "E1019: Sub parameter should be an object of 1 or string for..."
*cfn-lint version: 0.40.0*

I am getting an incorrect error that [`E1019`](https://github.com/aws-cloudformation/cfn-python-lint/blob/master/docs/rules.md#E1019)` Sub parameter should be an object of 1 or string for...` when using YAML:

```
        - Fn::Sub:
            - 'example-${Var}-${Var2}'
            - Var: 123
              Var2: 456
```

Official docs: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.html

Official docs sample:
```
Fn::Sub:
  - String
  - Var1Name: Var1Value
    Var2Name: Var2Value
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/cfnlint/rules/functions/Sub.py`
Content:
```
1 """
2 Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 SPDX-License-Identifier: MIT-0
4 """
5 import six
6 from cfnlint.helpers import PSEUDOPARAMS, VALID_PARAMETER_TYPES_LIST
7 from cfnlint.rules import CloudFormationLintRule
8 from cfnlint.rules import RuleMatch
9 
10 
11 class Sub(CloudFormationLintRule):
12     """Check if Sub values are correct"""
13     id = 'E1019'
14     shortdesc = 'Sub validation of parameters'
15     description = 'Making sure the sub function is properly configured'
16     source_url = 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.html'
17     tags = ['functions', 'sub']
18 
19     def _test_string(self, cfn, sub_string, parameters, tree):
20         """Test if a string has appropriate parameters"""
21 
22         matches = []
23         string_params = cfn.get_sub_parameters(sub_string)
24 
25         for string_param in string_params:
26             if isinstance(string_param, (six.string_types)):
27                 matches.extend(self._test_parameter(string_param, cfn, parameters, tree))
28 
29         return matches
30 
31     def _get_parameters(self, cfn):
32         """Get all Parameter Names"""
33         results = {}
34         parameters = cfn.template.get('Parameters', {})
35         if isinstance(parameters, dict):
36             for param_name, param_values in parameters.items():
37                 # This rule isn't here to check the Types but we need
38                 # something valid if it doesn't exist
39                 results[param_name] = param_values.get('Type', 'String')
40 
41         return results
42 
43     def _test_parameters(self, parameters, cfn, tree):
44         """Check parameters for appropriate configuration"""
45 
46         supported_functions = [
47             'Fn::Base64',
48             'Fn::FindInMap',
49             'Fn::GetAZs',
50             'Fn::GetAtt',
51             'Fn::If',
52             'Fn::ImportValue',
53             'Fn::Join',
54             'Fn::Select',
55             'Fn::Sub',
56             'Ref',
57         ]
58 
59         matches = []
60         for parameter_name, parameter_value_obj in parameters.items():
61             param_tree = tree[:] + [parameter_name]
62             if isinstance(parameter_value_obj, dict):
63                 if len(parameter_value_obj) == 1:
64                     for key, value in parameter_value_obj.items():
65                         if key not in supported_functions:
66                             message = 'Sub parameter should use a valid function for {0}'
67                             matches.append(RuleMatch(
68                                 param_tree, message.format('/'.join(map(str, tree)))))
69                         elif key in ['Ref']:
70                             matches.extend(self._test_parameter(value, cfn, {}, tree))
71                         elif key in ['Fn::GetAtt']:
72                             if isinstance(value, list):
73                                 # Only test this if all the items are a string
74                                 if_all_strings = True
75                                 for v in value:
76                                     if not isinstance(v, six.string_types):
77                                         # skip things got too complex
78                                         if_all_strings = False
79                                 if if_all_strings:
80                                     matches.extend(self._test_parameter(
81                                         '.'.join(value), cfn, {}, tree))
82                             elif isinstance(value, six.string_types):
83                                 matches.extend(self._test_parameter(value, cfn, {}, tree))
84                 else:
85                     message = 'Sub parameter should be an object of 1 for {0}'
86                     matches.append(RuleMatch(
87                         param_tree, message.format('/'.join(map(str, tree)))))
88             elif not isinstance(parameter_value_obj, six.string_types):
89                 message = 'Sub parameter should be an object of 1 or string for {0}'
90                 matches.append(RuleMatch(
91                     param_tree, message.format('/'.join(map(str, tree)))))
92 
93         return matches
94 
95     def _test_parameter(self, parameter, cfn, parameters, tree):
96         """ Test a parameter """
97 
98         matches = []
99         get_atts = cfn.get_valid_getatts()
100 
101         valid_params = list(PSEUDOPARAMS)
102         valid_params.extend(cfn.get_resource_names())
103         template_parameters = self._get_parameters(cfn)
104 
105         for key, _ in parameters.items():
106             valid_params.append(key)
107 
108         if parameter not in valid_params:
109             found = False
110             if parameter in template_parameters:
111                 found = True
112                 if template_parameters.get(parameter) in VALID_PARAMETER_TYPES_LIST:
113                     message = 'Fn::Sub cannot use list {0} at {1}'
114                     matches.append(RuleMatch(
115                         tree, message.format(parameter, '/'.join(map(str, tree)))))
116             for resource, attributes in get_atts.items():
117                 for attribute_name, attribute_values in attributes.items():
118                     if resource == parameter.split('.')[0]:
119                         if attribute_name == '*':
120                             found = True
121                         elif attribute_name == '.'.join(parameter.split('.')[1:]):
122                             if attribute_values.get('Type') == 'List':
123                                 message = 'Fn::Sub cannot use list {0} at {1}'
124                                 matches.append(RuleMatch(
125                                     tree, message.format(parameter, '/'.join(map(str, tree)))))
126                             found = True
127                         else:
128                             if attribute_name == parameter.split('.')[1] and attribute_values.get('Type') == 'Map':
129                                 found = True
130 
131             if not found:
132                 message = 'Parameter {0} for Fn::Sub not found at {1}'
133                 matches.append(RuleMatch(
134                     tree, message.format(parameter, '/'.join(map(str, tree)))))
135 
136         return matches
137 
138     def match(self, cfn):
139         matches = []
140 
141         sub_objs = cfn.search_deep_keys('Fn::Sub')
142 
143         for sub_obj in sub_objs:
144             sub_value_obj = sub_obj[-1]
145             tree = sub_obj[:-1]
146             if isinstance(sub_value_obj, six.string_types):
147                 matches.extend(self._test_string(cfn, sub_value_obj, {}, tree))
148             elif isinstance(sub_value_obj, list):
149                 if len(sub_value_obj) == 2:
150                     sub_string = sub_value_obj[0]
151                     parameters = sub_value_obj[1]
152                     if not isinstance(sub_string, six.string_types):
153                         message = 'Subs first element should be of type string for {0}'
154                         matches.append(RuleMatch(
155                             tree + [0], message.format('/'.join(map(str, tree)))))
156                     if not isinstance(parameters, dict):
157                         message = 'Subs second element should be an object for {0}'
158                         matches.append(RuleMatch(
159                             tree + [1], message.format('/'.join(map(str, tree)))))
160                     else:
161                         matches.extend(self._test_string(cfn, sub_string, parameters, tree + [0]))
162                         matches.extend(self._test_parameters(parameters, cfn, tree))
163                 else:
164                     message = 'Sub should be an array of 2 for {0}'
165                     matches.append(RuleMatch(
166                         tree, message.format('/'.join(map(str, tree)))))
167             elif isinstance(sub_value_obj, dict):
168                 if len(sub_value_obj) == 1:
169                     for key, _ in sub_value_obj.items():
170                         if not key == 'Fn::Transform':
171                             message = 'Sub should be a string or array of 2 items for {0}'
172                             matches.append(RuleMatch(
173                                 tree, message.format('/'.join(map(str, tree)))))
174                 else:
175                     message = 'Sub should be a string or array of 2 items for {0}'
176                     matches.append(RuleMatch(
177                         tree, message.format('/'.join(map(str, tree)))))
178             else:
179                 message = 'Sub should be a string or array of 2 items for {0}'
180                 matches.append(RuleMatch(
181                     tree, message.format('/'.join(map(str, tree)))))
182 
183         return matches
184
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/cfnlint/rules/functions/Sub.py b/src/cfnlint/rules/functions/Sub.py
--- a/src/cfnlint/rules/functions/Sub.py
+++ b/src/cfnlint/rules/functions/Sub.py
@@ -85,8 +85,8 @@
                     message = 'Sub parameter should be an object of 1 for {0}'
                     matches.append(RuleMatch(
                         param_tree, message.format('/'.join(map(str, tree)))))
-            elif not isinstance(parameter_value_obj, six.string_types):
-                message = 'Sub parameter should be an object of 1 or string for {0}'
+            elif isinstance(parameter_value_obj, list):
+                message = 'Sub parameter value should be a string for {0}'
                 matches.append(RuleMatch(
                     param_tree, message.format('/'.join(map(str, tree)))))

{"golden_diff": "diff --git a/src/cfnlint/rules/functions/Sub.py b/src/cfnlint/rules/functions/Sub.py\n--- a/src/cfnlint/rules/functions/Sub.py\n+++ b/src/cfnlint/rules/functions/Sub.py\n@@ -85,8 +85,8 @@\n                     message = 'Sub parameter should be an object of 1 for {0}'\n                     matches.append(RuleMatch(\n                         param_tree, message.format('/'.join(map(str, tree)))))\n-            elif not isinstance(parameter_value_obj, six.string_types):\n-                message = 'Sub parameter should be an object of 1 or string for {0}'\n+            elif isinstance(parameter_value_obj, list):\n+                message = 'Sub parameter value should be a string for {0}'\n                 matches.append(RuleMatch(\n                     param_tree, message.format('/'.join(map(str, tree)))))\n", "issue": "Incorrect rule: \"E1019: Sub parameter should be an object of 1 or string for...\"\n*cfn-lint version: 0.40.0*\r\n\r\nI am getting an incorrect error that [`E1019`](https://github.com/aws-cloudformation/cfn-python-lint/blob/master/docs/rules.md#E1019)` Sub parameter should be an object of 1 or string for...` when using YAML:\r\n\r\n```\r\n        - Fn::Sub:\r\n            - 'example-${Var}-${Var2}'\r\n            - Var: 123\r\n              Var2: 456\r\n```\r\n\r\nOfficial docs: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.html\r\n\r\nOfficial docs sample:\r\n```\r\nFn::Sub:\r\n  - String\r\n  - Var1Name: Var1Value\r\n    Var2Name: Var2Value\r\n```\r\n\n", "before_files": [{"content": "\"\"\"\nCopyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\nSPDX-License-Identifier: MIT-0\n\"\"\"\nimport six\nfrom cfnlint.helpers import PSEUDOPARAMS, VALID_PARAMETER_TYPES_LIST\nfrom cfnlint.rules import CloudFormationLintRule\nfrom cfnlint.rules import RuleMatch\n\n\nclass Sub(CloudFormationLintRule):\n    \"\"\"Check if Sub values are correct\"\"\"\n    id = 'E1019'\n    shortdesc = 'Sub validation of parameters'\n    description = 'Making sure the sub function is properly configured'\n    source_url = 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.html'\n    tags = ['functions', 'sub']\n\n    def _test_string(self, cfn, sub_string, parameters, tree):\n        \"\"\"Test if a string has appropriate parameters\"\"\"\n\n        matches = []\n        string_params = cfn.get_sub_parameters(sub_string)\n\n        for string_param in string_params:\n            if isinstance(string_param, (six.string_types)):\n                matches.extend(self._test_parameter(string_param, cfn, parameters, tree))\n\n        return matches\n\n    def _get_parameters(self, cfn):\n        \"\"\"Get all Parameter Names\"\"\"\n        results = {}\n        parameters = cfn.template.get('Parameters', {})\n        if isinstance(parameters, dict):\n            for param_name, param_values in parameters.items():\n                # This rule isn't here to check the Types but we need\n                # something valid if it doesn't exist\n                results[param_name] = param_values.get('Type', 'String')\n\n        return results\n\n    def _test_parameters(self, parameters, cfn, tree):\n        \"\"\"Check parameters for appropriate configuration\"\"\"\n\n        supported_functions = [\n            'Fn::Base64',\n            'Fn::FindInMap',\n            'Fn::GetAZs',\n            'Fn::GetAtt',\n            'Fn::If',\n            'Fn::ImportValue',\n            'Fn::Join',\n            'Fn::Select',\n            'Fn::Sub',\n            'Ref',\n        ]\n\n        matches = []\n        for parameter_name, parameter_value_obj in parameters.items():\n            param_tree = tree[:] + [parameter_name]\n            if isinstance(parameter_value_obj, dict):\n                if len(parameter_value_obj) == 1:\n                    for key, value in parameter_value_obj.items():\n                        if key not in supported_functions:\n                            message = 'Sub parameter should use a valid function for {0}'\n                            matches.append(RuleMatch(\n                                param_tree, message.format('/'.join(map(str, tree)))))\n                        elif key in ['Ref']:\n                            matches.extend(self._test_parameter(value, cfn, {}, tree))\n                        elif key in ['Fn::GetAtt']:\n                            if isinstance(value, list):\n                                # Only test this if all the items are a string\n                                if_all_strings = True\n                                for v in value:\n                                    if not isinstance(v, six.string_types):\n                                        # skip things got too complex\n                                        if_all_strings = False\n                                if if_all_strings:\n                                    matches.extend(self._test_parameter(\n                                        '.'.join(value), cfn, {}, tree))\n                            elif isinstance(value, six.string_types):\n                                matches.extend(self._test_parameter(value, cfn, {}, tree))\n                else:\n                    message = 'Sub parameter should be an object of 1 for {0}'\n                    matches.append(RuleMatch(\n                        param_tree, message.format('/'.join(map(str, tree)))))\n            elif not isinstance(parameter_value_obj, six.string_types):\n                message = 'Sub parameter should be an object of 1 or string for {0}'\n                matches.append(RuleMatch(\n                    param_tree, message.format('/'.join(map(str, tree)))))\n\n        return matches\n\n    def _test_parameter(self, parameter, cfn, parameters, tree):\n        \"\"\" Test a parameter \"\"\"\n\n        matches = []\n        get_atts = cfn.get_valid_getatts()\n\n        valid_params = list(PSEUDOPARAMS)\n        valid_params.extend(cfn.get_resource_names())\n        template_parameters = self._get_parameters(cfn)\n\n        for key, _ in parameters.items():\n            valid_params.append(key)\n\n        if parameter not in valid_params:\n            found = False\n            if parameter in template_parameters:\n                found = True\n                if template_parameters.get(parameter) in VALID_PARAMETER_TYPES_LIST:\n                    message = 'Fn::Sub cannot use list {0} at {1}'\n                    matches.append(RuleMatch(\n                        tree, message.format(parameter, '/'.join(map(str, tree)))))\n            for resource, attributes in get_atts.items():\n                for attribute_name, attribute_values in attributes.items():\n                    if resource == parameter.split('.')[0]:\n                        if attribute_name == '*':\n                            found = True\n                        elif attribute_name == '.'.join(parameter.split('.')[1:]):\n                            if attribute_values.get('Type') == 'List':\n                                message = 'Fn::Sub cannot use list {0} at {1}'\n                                matches.append(RuleMatch(\n                                    tree, message.format(parameter, '/'.join(map(str, tree)))))\n                            found = True\n                        else:\n                            if attribute_name == parameter.split('.')[1] and attribute_values.get('Type') == 'Map':\n                                found = True\n\n            if not found:\n                message = 'Parameter {0} for Fn::Sub not found at {1}'\n                matches.append(RuleMatch(\n                    tree, message.format(parameter, '/'.join(map(str, tree)))))\n\n        return matches\n\n    def match(self, cfn):\n        matches = []\n\n        sub_objs = cfn.search_deep_keys('Fn::Sub')\n\n        for sub_obj in sub_objs:\n            sub_value_obj = sub_obj[-1]\n            tree = sub_obj[:-1]\n            if isinstance(sub_value_obj, six.string_types):\n                matches.extend(self._test_string(cfn, sub_value_obj, {}, tree))\n            elif isinstance(sub_value_obj, list):\n                if len(sub_value_obj) == 2:\n                    sub_string = sub_value_obj[0]\n                    parameters = sub_value_obj[1]\n                    if not isinstance(sub_string, six.string_types):\n                        message = 'Subs first element should be of type string for {0}'\n                        matches.append(RuleMatch(\n                            tree + [0], message.format('/'.join(map(str, tree)))))\n                    if not isinstance(parameters, dict):\n                        message = 'Subs second element should be an object for {0}'\n                        matches.append(RuleMatch(\n                            tree + [1], message.format('/'.join(map(str, tree)))))\n                    else:\n                        matches.extend(self._test_string(cfn, sub_string, parameters, tree + [0]))\n                        matches.extend(self._test_parameters(parameters, cfn, tree))\n                else:\n                    message = 'Sub should be an array of 2 for {0}'\n                    matches.append(RuleMatch(\n                        tree, message.format('/'.join(map(str, tree)))))\n            elif isinstance(sub_value_obj, dict):\n                if len(sub_value_obj) == 1:\n                    for key, _ in sub_value_obj.items():\n                        if not key == 'Fn::Transform':\n                            message = 'Sub should be a string or array of 2 items for {0}'\n                            matches.append(RuleMatch(\n                                tree, message.format('/'.join(map(str, tree)))))\n                else:\n                    message = 'Sub should be a string or array of 2 items for {0}'\n                    matches.append(RuleMatch(\n                        tree, message.format('/'.join(map(str, tree)))))\n            else:\n                message = 'Sub should be a string or array of 2 items for {0}'\n                matches.append(RuleMatch(\n                    tree, message.format('/'.join(map(str, tree)))))\n\n        return matches\n", "path": "src/cfnlint/rules/functions/Sub.py"}], "after_files": [{"content": "\"\"\"\nCopyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\nSPDX-License-Identifier: MIT-0\n\"\"\"\nimport six\nfrom cfnlint.helpers import PSEUDOPARAMS, VALID_PARAMETER_TYPES_LIST\nfrom cfnlint.rules import CloudFormationLintRule\nfrom cfnlint.rules import RuleMatch\n\n\nclass Sub(CloudFormationLintRule):\n    \"\"\"Check if Sub values are correct\"\"\"\n    id = 'E1019'\n    shortdesc = 'Sub validation of parameters'\n    description = 'Making sure the sub function is properly configured'\n    source_url = 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.html'\n    tags = ['functions', 'sub']\n\n    def _test_string(self, cfn, sub_string, parameters, tree):\n        \"\"\"Test if a string has appropriate parameters\"\"\"\n\n        matches = []\n        string_params = cfn.get_sub_parameters(sub_string)\n\n        for string_param in string_params:\n            if isinstance(string_param, (six.string_types)):\n                matches.extend(self._test_parameter(string_param, cfn, parameters, tree))\n\n        return matches\n\n    def _get_parameters(self, cfn):\n        \"\"\"Get all Parameter Names\"\"\"\n        results = {}\n        parameters = cfn.template.get('Parameters', {})\n        if isinstance(parameters, dict):\n            for param_name, param_values in parameters.items():\n                # This rule isn't here to check the Types but we need\n                # something valid if it doesn't exist\n                results[param_name] = param_values.get('Type', 'String')\n\n        return results\n\n    def _test_parameters(self, parameters, cfn, tree):\n        \"\"\"Check parameters for appropriate configuration\"\"\"\n\n        supported_functions = [\n            'Fn::Base64',\n            'Fn::FindInMap',\n            'Fn::GetAZs',\n            'Fn::GetAtt',\n            'Fn::If',\n            'Fn::ImportValue',\n            'Fn::Join',\n            'Fn::Select',\n            'Fn::Sub',\n            'Ref',\n        ]\n\n        matches = []\n        for parameter_name, parameter_value_obj in parameters.items():\n            param_tree = tree[:] + [parameter_name]\n            if isinstance(parameter_value_obj, dict):\n                if len(parameter_value_obj) == 1:\n                    for key, value in parameter_value_obj.items():\n                        if key not in supported_functions:\n                            message = 'Sub parameter should use a valid function for {0}'\n                            matches.append(RuleMatch(\n                                param_tree, message.format('/'.join(map(str, tree)))))\n                        elif key in ['Ref']:\n                            matches.extend(self._test_parameter(value, cfn, {}, tree))\n                        elif key in ['Fn::GetAtt']:\n                            if isinstance(value, list):\n                                # Only test this if all the items are a string\n                                if_all_strings = True\n                                for v in value:\n                                    if not isinstance(v, six.string_types):\n                                        # skip things got too complex\n                                        if_all_strings = False\n                                if if_all_strings:\n                                    matches.extend(self._test_parameter(\n                                        '.'.join(value), cfn, {}, tree))\n                            elif isinstance(value, six.string_types):\n                                matches.extend(self._test_parameter(value, cfn, {}, tree))\n                else:\n                    message = 'Sub parameter should be an object of 1 for {0}'\n                    matches.append(RuleMatch(\n                        param_tree, message.format('/'.join(map(str, tree)))))\n            elif isinstance(parameter_value_obj, list):\n                message = 'Sub parameter value should be a string for {0}'\n                matches.append(RuleMatch(\n                    param_tree, message.format('/'.join(map(str, tree)))))\n\n        return matches\n\n    def _test_parameter(self, parameter, cfn, parameters, tree):\n        \"\"\" Test a parameter \"\"\"\n\n        matches = []\n        get_atts = cfn.get_valid_getatts()\n\n        valid_params = list(PSEUDOPARAMS)\n        valid_params.extend(cfn.get_resource_names())\n        template_parameters = self._get_parameters(cfn)\n\n        for key, _ in parameters.items():\n            valid_params.append(key)\n\n        if parameter not in valid_params:\n            found = False\n            if parameter in template_parameters:\n                found = True\n                if template_parameters.get(parameter) in VALID_PARAMETER_TYPES_LIST:\n                    message = 'Fn::Sub cannot use list {0} at {1}'\n                    matches.append(RuleMatch(\n                        tree, message.format(parameter, '/'.join(map(str, tree)))))\n            for resource, attributes in get_atts.items():\n                for attribute_name, attribute_values in attributes.items():\n                    if resource == parameter.split('.')[0]:\n                        if attribute_name == '*':\n                            found = True\n                        elif attribute_name == '.'.join(parameter.split('.')[1:]):\n                            if attribute_values.get('Type') == 'List':\n                                message = 'Fn::Sub cannot use list {0} at {1}'\n                                matches.append(RuleMatch(\n                                    tree, message.format(parameter, '/'.join(map(str, tree)))))\n                            found = True\n                        else:\n                            if attribute_name == parameter.split('.')[1] and attribute_values.get('Type') == 'Map':\n                                found = True\n\n            if not found:\n                message = 'Parameter {0} for Fn::Sub not found at {1}'\n                matches.append(RuleMatch(\n                    tree, message.format(parameter, '/'.join(map(str, tree)))))\n\n        return matches\n\n    def match(self, cfn):\n        matches = []\n\n        sub_objs = cfn.search_deep_keys('Fn::Sub')\n\n        for sub_obj in sub_objs:\n            sub_value_obj = sub_obj[-1]\n            tree = sub_obj[:-1]\n            if isinstance(sub_value_obj, six.string_types):\n                matches.extend(self._test_string(cfn, sub_value_obj, {}, tree))\n            elif isinstance(sub_value_obj, list):\n                if len(sub_value_obj) == 2:\n                    sub_string = sub_value_obj[0]\n                    parameters = sub_value_obj[1]\n                    if not isinstance(sub_string, six.string_types):\n                        message = 'Subs first element should be of type string for {0}'\n                        matches.append(RuleMatch(\n                            tree + [0], message.format('/'.join(map(str, tree)))))\n                    if not isinstance(parameters, dict):\n                        message = 'Subs second element should be an object for {0}'\n                        matches.append(RuleMatch(\n                            tree + [1], message.format('/'.join(map(str, tree)))))\n                    else:\n                        matches.extend(self._test_string(cfn, sub_string, parameters, tree + [0]))\n                        matches.extend(self._test_parameters(parameters, cfn, tree))\n                else:\n                    message = 'Sub should be an array of 2 for {0}'\n                    matches.append(RuleMatch(\n                        tree, message.format('/'.join(map(str, tree)))))\n            elif isinstance(sub_value_obj, dict):\n                if len(sub_value_obj) == 1:\n                    for key, _ in sub_value_obj.items():\n                        if not key == 'Fn::Transform':\n                            message = 'Sub should be a string or array of 2 items for {0}'\n                            matches.append(RuleMatch(\n                                tree, message.format('/'.join(map(str, tree)))))\n                else:\n                    message = 'Sub should be a string or array of 2 items for {0}'\n                    matches.append(RuleMatch(\n                        tree, message.format('/'.join(map(str, tree)))))\n            else:\n                message = 'Sub should be a string or array of 2 items for {0}'\n                matches.append(RuleMatch(\n                    tree, message.format('/'.join(map(str, tree)))))\n\n        return matches\n", "path": "src/cfnlint/rules/functions/Sub.py"}]}