hashicorp/terraform · error

%s%s: MinItems and MaxItems must both be 0 in NestingMap mod

Error message

%s%s: MinItems and MaxItems must both be 0 in NestingMap mode

What it means

Raised for NestingMap blocks when MinItems or MaxItems is non-zero. NestingMap derives its cardinality from the map keys the user supplies, so explicit item counts are meaningless and ignored by the decoder; the validator at internal_validate.go:111 enforces that both are zero.

Source

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

				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))
	}

	return multiErr
}

// InternalValidate returns an error if the receiving attribute and its child
// schema definitions have any inconsistencies with the documented rules for
// valid schema.

View on GitHub (pinned to c9def3e214)

Solutions

  1. Set both MinItems and MaxItems to 0 for the NestingMap block.
  2. If you truly need a minimum number of named entries, enforce it in plan-time resource logic rather than schema cardinality.
  3. Lint schemas in CI with InternalValidate so stray counts fail the build, not runtime.

Example fix

// before
&NestedBlock{Nesting: NestingMap, MinItems: 1, MaxItems: 5}

// after
&NestedBlock{Nesting: NestingMap, MinItems: 0, MaxItems: 0}
Defensive patterns

Strategy: validation

Validate before calling

func assertMapZeroCardinality(nb *configschema.NestedBlock) error {
    if nb.Nesting == configschema.NestingMap && (nb.MinItems != 0 || nb.MaxItems != 0) {
        return fmt.Errorf("NestingMap requires MinItems==0 and MaxItems==0")
    }
    return nil
}

Prevention

When it happens

Trigger: A NestedBlock with Nesting=NestingMap and MinItems != 0 or MaxItems != 0. The NestingMap case at line 110 reaches line 111 and the inequality holds.

Common situations: Changing a NestingList to NestingMap without clearing inherited MinItems/MaxItems; schema generators that populate cardinality for every block uniformly; copy-pasting a list block and only flipping the Nesting constant.

Related errors


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