{"record":{"id":"8434b7a421be6bc2","repo":"hashicorp/terraform","slug":"s-s-nestingset-blocks-may-not-contain-writeonly","errorCode":null,"errorMessage":"%s%s: NestingSet blocks may not contain WriteOnly attributes","messagePattern":"(.+?)(.+?): NestingSet blocks may not contain WriteOnly attributes","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/configs/configschema/internal_validate.go","lineNumber":104,"sourceCode":"\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}\n\t\tdefault:\n\t\t\tmultiErr = errors.Join(multiErr, fmt.Errorf(\"%s%s: invalid nesting mode %s\", prefix, name, blockS.Nesting))\n\t\t}\n\n\t\tsubPrefix := prefix + name + \".\"\n\t\tmultiErr = errors.Join(multiErr, blockS.Block.internalValidate(subPrefix))","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/configs/configschema/internal_validate.go#L86-L122","documentation":"Raised when a NestingSet block transitively contains a WriteOnly attribute. WriteOnly marks are hoisted by cty up to the enclosing set value, so per-element WriteOnly flags would be lost or misapplied; only the set-level attribute itself may be WriteOnly. The check at internal_validate.go:100 calls blockS.Block.ContainsWriteOnly() and rejects the schema.","triggerScenarios":"A NestedBlock with Nesting=NestingSet whose descendant Attributes include one with WriteOnly: true. The NestingSet branch at line 92 evaluates ContainsWriteOnly() at line 100 and it returns true.","commonSituations":"Adding a sensitive ephemeral credential field (WriteOnly) to a set-valued block such as a list of upstream peers; converting a NestingList of credentials to NestingSet without removing inner WriteOnly flags; schema generation that marks all secret-looking fields WriteOnly by default.","solutions":["Move the WriteOnly flag off the inner attribute and onto the enclosing set attribute, or remove it entirely if the data is persisted.","Change the block from NestingSet to NestingList, which permits inner WriteOnly attributes.","If individual elements must remain ephemeral, model the collection as a NestingList of single-field objects rather than a set."],"exampleFix":"// before\nBlockTypes: map[string]*NestedBlock{\n    \"peer\": {Nesting: NestingSet, Block: Block{Attributes: map[string]*Attribute{\n        \"token\": {Type: cty.String, Optional: true, WriteOnly: true},\n    }}},\n}\n\n// after\nBlockTypes: map[string]*NestedBlock{\n    \"peer\": {Nesting: NestingList, Block: Block{Attributes: map[string]*Attribute{\n        \"token\": {Type: cty.String, Optional: true, WriteOnly: true},\n    }}},\n}","handlingStrategy":"validation","validationCode":"func assertSetBlockNoWriteOnly(nb *configschema.NestedBlock) error {\n    if nb.Nesting != configschema.NestingSet { return nil }\n    if nb.Block.ContainsWriteOnly() {\n        return fmt.Errorf(\"NestingSet block may not contain WriteOnly attributes\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only the outer set-level attribute may carry WriteOnly; never inner elements.","Use NestingList when individual elements must be ephemeral.","Audit secret-bearing fields whenever converting a list to a set."],"tags":["configschema","nesting-set","write-only","sensitive","validation"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}