{"record":{"id":"f292515c2ea29041","repo":"hashicorp/terraform","slug":"s-s-nestingset-blocks-may-not-contain-attributes","errorCode":null,"errorMessage":"%s%s: NestingSet blocks may not contain attributes of cty.DynamicPseudoType","messagePattern":"(.+?)(.+?): NestingSet blocks may not contain attributes of cty\\.DynamicPseudoType","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/configs/configschema/internal_validate.go","lineNumber":98,"sourceCode":"\t\t\t}\n\t\tcase NestingGroup:\n\t\t\tif blockS.MinItems != 0 || blockS.MaxItems != 0 {\n\t\t\t\tmultiErr = errors.Join(multiErr, fmt.Errorf(\"%s%s: MinItems and MaxItems cannot be used in NestingGroup mode\", prefix, name))\n\t\t\t}\n\t\t\tif blockS.Computed {\n\t\t\t\tmultiErr = errors.Join(multiErr, fmt.Errorf(\"%s%s: NestingGroup blocks cannot be computed\", prefix, name))\n\t\t\t}\n\t\tcase NestingList, NestingSet:\n\t\t\tif blockS.MinItems > blockS.MaxItems && blockS.MaxItems != 0 {\n\t\t\t\tmultiErr = errors.Join(multiErr, fmt.Errorf(\"%s%s: MinItems must be less than or equal to MaxItems in %s mode\", prefix, name, blockS.Nesting))\n\t\t\t}\n\t\t\tif blockS.Nesting == NestingSet {\n\t\t\t\tety := blockS.Block.ImpliedType()\n\t\t\t\tif ety.HasDynamicTypes() {\n\t\t\t\t\t// This is not permitted because the HCL (cty) set implementation\n\t\t\t\t\t// needs to know the exact type of set elements in order to\n\t\t\t\t\t// properly hash them, and so can't support mixed types.\n\t\t\t\t\tmultiErr = errors.Join(multiErr, fmt.Errorf(\"%s%s: NestingSet blocks may not contain attributes of cty.DynamicPseudoType\", prefix, name))\n\t\t\t\t}\n\t\t\t\tif blockS.Block.ContainsWriteOnly() {\n\t\t\t\t\t// This is not permitted because any marks within sets will\n\t\t\t\t\t// be hoisted up the outer set value, so only the set itself\n\t\t\t\t\t// can be WriteOnly.\n\t\t\t\t\tmultiErr = errors.Join(multiErr, fmt.Errorf(\"%s%s: NestingSet blocks may not contain WriteOnly attributes\", prefix, name))\n\t\t\t\t}\n\t\t\t}\n\t\t\tif blockS.MinItems > 0 && blockS.Computed {\n\t\t\t\tmultiErr = errors.Join(multiErr, fmt.Errorf(\"%s%s: Computed cannot be used when MinItems > 0\", prefix, name))\n\t\t\t}\n\t\tcase NestingMap:\n\t\t\tif blockS.MinItems != 0 || blockS.MaxItems != 0 {\n\t\t\t\tmultiErr = errors.Join(multiErr, fmt.Errorf(\"%s%s: MinItems and MaxItems must both be 0 in NestingMap mode\", prefix, name))\n\t\t\t}\n\t\t\tif blockS.MinItems > 0 && blockS.Computed {\n\t\t\t\tmultiErr = errors.Join(multiErr, fmt.Errorf(\"%s%s: Computed cannot be used when MinItems > 0\", prefix, name))\n\t\t\t}","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/configs/configschema/internal_validate.go#L80-L116","documentation":"Raised when a NestingSet block's implied type contains cty.DynamicPseudoType anywhere in its structure. cty sets require a concrete, hashable element type to compute set membership; DynamicPseudoType defers typing until value time, so set elements could not be reliably hashed. The validator calls blockS.Block.ImpliedType().HasDynamicTypes() at internal_validate.go:94 and rejects the schema outright.","triggerScenarios":"A NestedBlock with Nesting=NestingSet whose Block (or any descendant attribute) has Type=cty.DynamicPseudoType, or a nested attribute whose NestedType ultimately resolves to a dynamic type. The NestingSet branch at line 92 computes ety and HasDynamicTypes() returns true at line 94.","commonSituations":"Porting a NestingList block to NestingSet to dedupe entries while the element schema still allows arbitrary JSON (dynamic); using a generic 'tags' or 'metadata' attribute of type cty.DynamicPseudoType inside a set; framework-generated schemas that default unknown fields to dynamic.","solutions":["Switch the block back to NestingList if dynamic-typed elements are genuinely required.","Constrain the dynamic attribute to a concrete type (e.g. cty.String, cty.Map(cty.String)) so set elements are hashable.","If arbitrary key/value data is needed, model it as a map attribute (cty.Map) rather than a set of dynamic objects."],"exampleFix":"// before\nBlockTypes: map[string]*NestedBlock{\n    \"item\": {Nesting: NestingSet, Block: Block{Attributes: map[string]*Attribute{\n        \"data\": {Type: cty.DynamicPseudoType, Optional: true},\n    }}},\n}\n\n// after\nBlockTypes: map[string]*NestedBlock{\n    \"item\": {Nesting: NestingSet, Block: Block{Attributes: map[string]*Attribute{\n        \"data\": {Type: cty.Map(cty.String), Optional: true},\n    }}},\n}","handlingStrategy":"validation","validationCode":"func assertSetBlockNotDynamic(nb *configschema.NestedBlock) error {\n    if nb.Nesting != configschema.NestingSet { return nil }\n    if nb.Block.ImpliedType().HasDynamicTypes() {\n        return fmt.Errorf(\"NestingSet block may not contain cty.DynamicPseudoType\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never use cty.DynamicPseudoType inside a set; sets need concrete hashable element types.","Prefer cty.Map(cty.String) or a concrete object type for arbitrary key/value data in a set.","Switch to NestingList if dynamic typing is genuinely required."],"tags":["configschema","nesting-set","dynamic-type","cty","validation"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T20:17:04.800Z"}