hashicorp/terraform · error

%s%s: NestingSet blocks may not contain WriteOnly attributes

Error message

%s%s: NestingSet blocks may not contain WriteOnly attributes

What it means

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.

Source

Thrown at internal/configs/configschema/internal_validate.go:104

				multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: NestingGroup blocks cannot be computed", prefix, name))
			}
		case NestingList, NestingSet:
			if blockS.MinItems > blockS.MaxItems && blockS.MaxItems != 0 {
				multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: MinItems must be less than or equal to MaxItems in %s mode", prefix, name, blockS.Nesting))
			}
			if blockS.Nesting == NestingSet {
				ety := blockS.Block.ImpliedType()
				if ety.HasDynamicTypes() {
					// This is not permitted because the HCL (cty) set implementation
					// needs to know the exact type of set elements in order to
					// properly hash them, and so can't support mixed types.
					multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: NestingSet blocks may not contain attributes of cty.DynamicPseudoType", prefix, name))
				}
				if blockS.Block.ContainsWriteOnly() {
					// This is not permitted because any marks within sets will
					// be hoisted up the outer set value, so only the set itself
					// can be WriteOnly.
					multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: NestingSet blocks may not contain WriteOnly attributes", prefix, name))
				}
			}
			if blockS.MinItems > 0 && blockS.Computed {
				multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: Computed cannot be used when MinItems > 0", prefix, name))
			}
		case NestingMap:
			if blockS.MinItems != 0 || blockS.MaxItems != 0 {
				multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: MinItems and MaxItems must both be 0 in NestingMap mode", prefix, name))
			}
			if blockS.MinItems > 0 && blockS.Computed {
				multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: Computed cannot be used when MinItems > 0", prefix, name))
			}
		default:
			multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: invalid nesting mode %s", prefix, name, blockS.Nesting))
		}

		subPrefix := prefix + name + "."
		multiErr = errors.Join(multiErr, blockS.Block.internalValidate(subPrefix))

View on GitHub (pinned to c9def3e214)

Solutions

  1. Move the WriteOnly flag off the inner attribute and onto the enclosing set attribute, or remove it entirely if the data is persisted.
  2. Change the block from NestingSet to NestingList, which permits inner WriteOnly attributes.
  3. If individual elements must remain ephemeral, model the collection as a NestingList of single-field objects rather than a set.

Example fix

// before
BlockTypes: map[string]*NestedBlock{
    "peer": {Nesting: NestingSet, Block: Block{Attributes: map[string]*Attribute{
        "token": {Type: cty.String, Optional: true, WriteOnly: true},
    }}},
}

// after
BlockTypes: map[string]*NestedBlock{
    "peer": {Nesting: NestingList, Block: Block{Attributes: map[string]*Attribute{
        "token": {Type: cty.String, Optional: true, WriteOnly: true},
    }}},
}
Defensive patterns

Strategy: validation

Validate before calling

func assertSetBlockNoWriteOnly(nb *configschema.NestedBlock) error {
    if nb.Nesting != configschema.NestingSet { return nil }
    if nb.Block.ContainsWriteOnly() {
        return fmt.Errorf("NestingSet block may not contain WriteOnly attributes")
    }
    return nil
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/8434b7a421be6bc2. Report an issue: GitHub.