Repository: aws-cloudformation/cfn-lint

Issue:
Error transforming template when using !GetAtt
### CloudFormation Lint Version

0.85.0

### What operating system are you using?

Ubuntu

### Describe the bug

When I try to validate the template i get following error:

> E0001 Error transforming template: __init__() missing 2 required positional arguments: 'start_mark' and 'end_mark'
aws/template.yml:1:1

When AuthorizeUri is hardcoded the problem disappears.


### Expected behavior

No error is thrown and template is validated.

### Reproduction template

```AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31

Resources:
  Api:
    Type: "AWS::Serverless::GraphQLApi"
    Properties:
      Name: SomeApi
      SchemaUri: ./schema.graphql
      Auth:
        Type: AWS_LAMBDA
        LambdaAuthorizer:
          AuthorizerUri: !GetAtt AppSyncAuthorizerFunction.Arn

  AppSyncAuthorizerFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: ./lambda/
      Handler: lambda_authorizer.handle
      Runtime: python3.8



Discussion:

Resolving patch:
diff --git a/src/cfnlint/decode/node.py b/src/cfnlint/decode/node.py
--- a/src/cfnlint/decode/node.py
+++ b/src/cfnlint/decode/node.py
@@ -3,8 +3,12 @@
 SPDX-License-Identifier: MIT-0
 """
 
+from __future__ import annotations
+
 import logging
+from collections import namedtuple
 from copy import deepcopy
+from typing import Any, Dict, Protocol, Set
 
 import regex as re
 
@@ -15,6 +19,14 @@ class TemplateAttributeError(AttributeError):
     """Custom error to capture Attribute Errors in the Template"""
 
 
+class Mark(Protocol):
+    line: int
+    column: int
+
+
+_mark = namedtuple("_mark", ["line", "column"])
+
+
 def create_str_node_class(cls):
     """
     Create string node class
@@ -23,13 +35,16 @@ def create_str_node_class(cls):
     class node_class(cls):
         """Node class created based on the input class"""
 
-        def __init__(self, x, start_mark, end_mark):
+        def __init__(
+            self, x, start_mark: Mark | None = None, end_mark: Mark | None = None
+        ):
             try:
                 cls.__init__(self, x)
             except TypeError:
                 cls.__init__(self)
-            self.start_mark = start_mark
-            self.end_mark = end_mark
+
+            self.start_mark = start_mark or _mark(0, 0)
+            self.end_mark = end_mark or _mark(0, 0)
 
         # pylint: disable=bad-classmethod-argument, unused-argument
         def __new__(self, x, start_mark, end_mark):
@@ -58,13 +73,16 @@ def create_dict_node_class(cls):
     class node_class(cls):
         """Node class created based on the input class"""
 
-        def __init__(self, x, start_mark, end_mark):
+        def __init__(
+            self, x, start_mark: Mark | None = None, end_mark: Mark | None = None
+        ):
+            LOGGER.debug(type(start_mark))
             try:
                 cls.__init__(self, x)
             except TypeError:
                 cls.__init__(self)
-            self.start_mark = start_mark
-            self.end_mark = end_mark
+            self.start_mark = start_mark or _mark(0, 0)
+            self.end_mark = end_mark or _mark(0, 0)
             self.condition_functions = ["Fn::If"]
 
         def __deepcopy__(self, memo):
@@ -207,12 +225,14 @@ def create_sub_node_class(cls):
     class sub_class(cls):
         """Node class created based on the input class"""
 
-        def __init__(self, x, start_mark, end_mark):
+        def __init__(
+            self, x, start_mark: Mark | None = None, end_mark: Mark | None = None
+        ):
             cls.__init__(self, x, start_mark, end_mark)
             self.__cache_is_valid = False
             self.__cache_sub_string = ""
-            self.__cache_sub_string_vars = set()
-            self.__cache_sub_vars = {}
+            self.__cache_sub_string_vars: Set[str] = set()
+            self.__cache_sub_vars: Dict[str, Any] = {}
             self.__setup()
 
         def __setup_list_sub_string(self, s):
@@ -280,13 +300,15 @@ def create_dict_list_class(cls):
     class node_class(cls):
         """Node class created based on the input class"""
 
-        def __init__(self, x, start_mark, end_mark):
+        def __init__(
+            self, x, start_mark: Mark | None = None, end_mark: Mark | None = None
+        ):
             try:
                 cls.__init__(self, x)
             except TypeError:
                 cls.__init__(self)
-            self.start_mark = start_mark
-            self.end_mark = end_mark
+            self.start_mark = start_mark or _mark(0, 0)
+            self.end_mark = end_mark or _mark(0, 0)
             self.condition_functions = ["Fn::If"]
 
         def __deepcopy__(self, memo):


Test patch: