Repository: aws-cloudformation/cfn-lint

Issue:
"null" as Parameter Name Throws Incorrect Error
### CloudFormation Lint Version

0.85.2_1

### What operating system are you using?

Mac

### Describe the bug

Setting a Parameter name to "null" produces incorrect or misleading errors:
"E0002 Unknown exception while processing rule E2011: object of type 'NoneType' has no len()"
"E0002 Unknown exception while processing rule E2003: expected string or buffer"
(further, the document line reference is 1:1; which is not correct)

The Cloudformation service itself returns the following more specific error message:
"Template format error: [/Parameters] encountered malformed key"

### Expected behavior

cfn-lint returns correct line number and a more accurate error message, such as:
"E000X Parameters encountered malformed key"

### Reproduction template

```yaml
AWSTemplateFormatVersion: 2010-09-09

Parameters:
  null:
    Description: anything
    Type: String

#...
```


Discussion:

Resolving patch:
diff --git a/src/cfnlint/decode/cfn_yaml.py b/src/cfnlint/decode/cfn_yaml.py
--- a/src/cfnlint/decode/cfn_yaml.py
+++ b/src/cfnlint/decode/cfn_yaml.py
@@ -88,6 +88,19 @@ def construct_yaml_map(self, node):
             key = self.construct_object(key_node, False)
             value = self.construct_object(value_node, False)
 
+            if key is None:
+                raise CfnParseError(
+                    self.filename,
+                    [
+                        build_match(
+                            filename=self.filename,
+                            message=f"Null key {key_node.value!r} not supported (line {key_node.start_mark.line + 1})",
+                            line_number=key_node.start_mark.line,
+                            column_number=key_node.start_mark.column,
+                            key=key_node.value,
+                        ),
+                    ],
+                )
             for key_dup in mapping:
                 if key_dup == key:
                     if not matches:


Test patch:
diff --git a/test/unit/module/decode/test_decode.py b/test/unit/module/decode/test_decode.py
--- a/test/unit/module/decode/test_decode.py
+++ b/test/unit/module/decode/test_decode.py
@@ -11,7 +11,9 @@
 import yaml
 from yaml.scanner import ScannerError
 
-import cfnlint.decode.decode  # pylint: disable=E0401
+import cfnlint.decode.cfn_json
+import cfnlint.decode.cfn_yaml
+import cfnlint.decode.decode
 
 
 class TestDecode(BaseTestCase):
@@ -125,3 +127,14 @@ def test_decode_yaml_error(self, mock_cfn_yaml):
         self.assertEqual(len(matches), 1)
         self.assertEqual(matches[0].rule.id, "E0000")
         self.assertEqual(matches[0].message, err_msg)
+
+    def test_decode_yaml_null_key(self):
+        err_msg = "Null key 'null' not supported (line 3)"
+        with self.assertRaises(cfnlint.decode.cfn_yaml.CfnParseError) as e:
+            cfnlint.decode.cfn_yaml.loads(
+                """
+                Parameters:
+                    null: test
+            """
+            )
+        self.assertEqual(str(e.exception), err_msg)
diff --git a/test/unit/module/decode/test_nod_sub.py b/test/unit/module/decode/test_node_sub.py
similarity index 100%
rename from test/unit/module/decode/test_nod_sub.py
rename to test/unit/module/decode/test_node_sub.py