Cfn-python-lint: unhashable type: 'dict_node'

Created on 22 Apr 2018  路  21Comments  路  Source: aws-cloudformation/cfn-python-lint

I'm getting this:

2018-04-22 00:46:35,869 - cfnlint - DEBUG - Get resources from template...
Traceback (most recent call last):
  File "/usr/local/bin/cfn-lint", line 11, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.6/dist-packages/cfnlint/__main__.py", line 157, in main
    matches.extend(runner.run())
  File "/usr/local/lib/python3.6/dist-packages/cfnlint/__init__.py", line 560, in run
    self.filename, self.cfn, self.ignore_checks))
  File "/usr/local/lib/python3.6/dist-packages/cfnlint/__init__.py", line 107, in run
    matches.extend(rule.matchall(filename, cfn))
  File "/usr/local/lib/python3.6/dist-packages/cfnlint/__init__.py", line 55, in matchall
    results = self.match(cfn)  # pylint: disable=E1102
  File "/usr/local/lib/python3.6/dist-packages/cfnlint/rules/resources/properties/Properties.py", line 195, in match
    resourcetype, resourcename, path, True))
  File "/usr/local/lib/python3.6/dist-packages/cfnlint/rules/resources/properties/Properties.py", line 131, in propertycheck
    parenttype, resourcename, arrproppath, False))
  File "/usr/local/lib/python3.6/dist-packages/cfnlint/rules/resources/properties/Properties.py", line 172, in propertycheck
    resourcename, proppath, False))
  File "/usr/local/lib/python3.6/dist-packages/cfnlint/rules/resources/properties/Properties.py", line 111, in propertycheck
    if prop not in resourcespec:
TypeError: unhashable type: 'dict_node'

The template deploys just fine.

spec bug

All 21 comments

Thanks @trondhindenes . Looking into it. I may need a few more details if I hit a wall.

My current theory is we are running into a list/array when we weren't expecting one. Could be a list of lists. The result is that when we do the for loop we are doing it on an array instead of a dict. If I switch it to items to be specific we will still get an error. Not sure how we are getting an array there thinking through some additional scenarios.

Let me know if you want me to post the template!

@trondhindenes that would be fantastic.

No problem, here's the unmodified one:

Parameters:
  VpcId:
    Type: String
  RdsSubnets:
    Type: "List<AWS::EC2::Subnet::Id>"
  DbIdentifier:
    Type: String
  MasterUserName:
    Type: String
  MasterPassword:
    Type: String
  BackupRestoreIamRole:
    Type: String
  DoUseMultiAz:
    Description: Use multi-AZ
    Default: "false"
    Type: String
    AllowedValues: ["true", "false"]
  Environment:
    Type: String
  EnvironmentId:
    Type: String
  StorageSize:
    Type: Number
  DBInstanceClass:
    Type: String
  SourceAllowedCidr:
    Type: String
Conditions:
  BoolDoUseMultiAz:
    !Equals [true, !Ref DoUseMultiAz]
Resources:
  DBEC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription:
        Ref: DbIdentifier
      VpcId:
        Ref: VpcId
      SecurityGroupIngress:
      -
        CidrIp:
          Ref: SourceAllowedCidr
        Description: Allow traffic from current aws network
        IpProtocol: tcp
        FromPort: 1433
        ToPort: 1433
      -
        CidrIp: "10.40.0.0/16"
        Description: Allow traffic from in-clients1 and in-clients2
        IpProtocol: tcp
        FromPort: 1433
        ToPort: 1433
      -
        CidrIp: "10.60.24.0/24"
        Description: Allow traffic from in-clients3
        IpProtocol: tcp
        FromPort: 1433
        ToPort: 1433
      -
        CidrIp: "10.140.103.0/24"
        Description: Allow traffic from in-vpn
        IpProtocol: tcp
        FromPort: 1433
        ToPort: 1433
      -
        CidrIp: "10.65.109.0/24"
        Description: Allow traffic from tc-vpn
        IpProtocol: tcp
        FromPort: 1433
        ToPort: 1433
      -
        CidrIp: "10.245.8.0/21"
        Description: Allow traffic from aws-euw1-prod1
        IpProtocol: tcp
        FromPort: 1433
        ToPort: 1433
  RdsSubnetGroup:
    Type: "AWS::RDS::DBSubnetGroup"
    Properties:
      DBSubnetGroupDescription:
        Ref: DbIdentifier
      DBSubnetGroupName:
        Ref: DbIdentifier
      SubnetIds:
        Ref: RdsSubnets
  OptionGroup:
    Type: "AWS::RDS::OptionGroup"
    Properties: 
      EngineName: sqlserver-se
      MajorEngineVersion: '14.00'
      OptionGroupDescription:
        Ref: DbIdentifier
      OptionConfigurations:
      - OptionName: SQLSERVER_BACKUP_RESTORE
        OptionSettings:
        - Name: IAM_ROLE_ARN
          Value:
            Ref: BackupRestoreIamRole
  DBInstance:
    Type: AWS::RDS::DBInstance
    DependsOn: OptionGroup
    Properties:
      DBInstanceIdentifier:
        Ref: DbIdentifier
      DBSubnetGroupName:
        Ref: DbIdentifier
      OptionGroupName: 
        Ref: OptionGroup
      Engine: sqlserver-se
      EngineVersion: '14.00.3015.40.v1'
      MultiAZ: !If [BoolDoUseMultiAz, true, false]
      StorageEncrypted: true
      StorageType: gp2
      MasterUsername:
        Ref: MasterUserName
      DBInstanceClass:
        Ref: DBInstanceClass
      AllocatedStorage:
        Ref: StorageSize
      MasterUserPassword:
        Ref: MasterPassword
      LicenseModel: license-included
      VPCSecurityGroups:
      - !GetAtt DBEC2SecurityGroup.GroupId
      PreferredBackupWindow: 02:00-03:00
      PreferredMaintenanceWindow: Tue:03:00-Tue:05:00
      AutoMinorVersionUpgrade: false
      Tags:
      - Key: environment
        Value:
          Ref: Environment
      - Key: environmentid
        Value:
          Ref: EnvironmentId

ok this helps a lot. It looks like to me the spec file doesn't match the documentation. Let me see what I can do on my side.

Documentation: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-optiongroup-optionconfigurations.html

Spec File:

"OptionSettings": {
  "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-optiongroup-optionconfigurations.html#cfn-rds-optiongroup-optionconfigurations-optionsettings",
  "Required": false,
  "Type": "OptionSetting",
  "UpdateType": "Mutable"
},

I think this should be

"OptionSettings": {
  "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-optiongroup-optionconfigurations.html#cfn-rds-optiongroup-optionconfigurations-optionsettings",
  "Required": false,
  "Type": "List",
  "ItemType": "OptionSetting",
  "UpdateType": "Mutable"
},

At the very least I'm working on a change now to more gracefully catch this issue going forward.

awesome!

Release 0.0.8 should capture this error and not fail. I'm torn on closing this issue until the CloudFormation Spec is updated to fix it because part of this issue still does exist.

I'd prefer keeping the issue open untill the "core" issue is solved.

Minor off-track: Do the Spec file actually do something under the hood? Or is it an automated (documentation) feature?

Got this issue with version 0.0.10 now:

  RDSOptionGroup:
    Type: "AWS::RDS::OptionGroup"
    Properties:
      EngineName: "oracle-se2"
      MajorEngineVersion: "12.1"
      OptionGroupDescription: "SSL and Timezone options"
      OptionConfigurations:
        - OptionName: "SSL"
          VpcSecurityGroupMemberships:
            - !Ref "PrivateSecurityGroup"
        - OptionName: "Timezone"
          OptionSettings:
            - Name: "TIME_ZONE"
              Value: "Europe/Amsterdam"

Error:

E3002 Expecting an object at Resources/RDSOptionGroup/Properties/OptionConfigurations/1/OptionSettings

@cmmeyer looks like the spec is off on this one too.

OptionSettings
The settings for this option.

Required: No

Type: List of Amazon RDS OptionGroup OptionSetting

Looks like it doesn't match.

"OptionSettings": {
          "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-optiongroup-optionconfigurations.html#cfn-rds-optiongroup-optionconfigurations-optionsettings",
          "Required": false,
          "Type": "OptionSetting",
          "UpdateType": "Mutable"
        },

Wait, I'm confused -- it's not required, the spec shows it as not required, but the linter is throwing an error because it's missing? The spec says it's not required, so how is it wrong? Could it be a processing issues in the rule engine? I may need someone to talk me through this...

The issue is that the documentation says it lists, looks like the API probably asks for a list but the CloudFormation Spec doesn't specify it is a list.

Got it. I'll file another internal ticket.

As a workaround I changed this setting in spec override file we already pass along, like

{
  "PropertyTypes": {
    "AWS::RDS::OptionGroup.OptionConfiguration": {
      "Properties": {
        "OptionSettings": {
          "ItemType": "OptionSetting",
          "Type": "List"
        }
      }
    }
  }
}

This indeed solved the issue... So I can confirm that this indeed is the issue... So for now we've got a workaround.

This is resolved in the 2.8.0 resource specification:

        "OptionSettings": {
          "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-optiongroup-optionconfigurations.html#cfn-rds-optiongroup-optionconfigurations-optionsettings",
          "DuplicatesAllowed": false,
          "ItemType": "OptionSetting",
          "Required": false,
          "Type": "List",
          "UpdateType": "Mutable"
        },

You can either update to cfn-lint 0.7.3 or update to the latest specification manually in your current version using cfn-lint --update-spec

I got unhashable type: 'dict_node' error when I add !IF condition in my template.
PersonServiceApi:
Type: AWS::Serverless::Api
Properties:
Name: !Sub ${StageName}-PersonAPI
StageName: !Ref StageName
Auth:
DefaultAuthorizer:
!If
- IsMaster
- !Sub 'None'
- !Ref CustomAuthorizer

Authorizers:
CustomAuthorizer:
FunctionPayloadType: REQUEST
FunctionArn: !GetAtt ApiGatewayAuthorizerLambda.Arn
FunctionInvokeRole: !Ref ApiGatewayLambdaExecutionRole
Identity:
Headers:
- cookie
ReauthorizeEvery: 0
DefinitionBody:
openapi: 3.0.0
info:

sorry for bad indentation

This looks to be something related to sam translator that was added to prevent re-deploys of APIs.

It seems to happen when you reference an existing AWS::Serverless::Api in a lambda Event using Ref
I've made a PR on the SAM repo #1396 for a fix.

I got unhashable type: 'dict_node' error when I add !IF condition in my template.
PersonServiceApi:
Type: AWS::Serverless::Api
Properties:
Name: !Sub ${StageName}-PersonAPI
StageName: !Ref StageName
Auth:
DefaultAuthorizer:
!If - IsMaster - !Sub 'None' - !Ref CustomAuthorizer
Authorizers:
CustomAuthorizer:
FunctionPayloadType: REQUEST
FunctionArn: !GetAtt ApiGatewayAuthorizerLambda.Arn
FunctionInvokeRole: !Ref ApiGatewayLambdaExecutionRole
Identity:
Headers:

  • cookie
    ReauthorizeEvery: 0
    DefinitionBody:
    openapi: 3.0.0
    info:

I have the same error if i add a condition. How did you resolve?
Conditions:
UseSSLCert: !Not [!Equals [!Ref 'SSLCertificateId', '']]

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Dunedan picture Dunedan  路  3Comments

KarthickEmis picture KarthickEmis  路  4Comments

kddejong picture kddejong  路  5Comments

adamchainz picture adamchainz  路  5Comments

LukasMusebrink picture LukasMusebrink  路  3Comments