hashicorp/terraform · error

%s%s: invalid nesting mode %s

Error message

%s%s: invalid nesting mode %s

What it means

Raised for a NestedBlock whose Nesting field is not one of the defined NestingMode constants (NestingSingle, NestingGroup, NestingList, NestingSet, NestingMap). This usually means the zero value nestingModeInvalid (0) was left in place, or a custom/integer value was assigned incorrectly. The default branch at internal_validate.go:117 catches it and prints the offending value.

Source

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

				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.
func (a *Attribute) InternalValidate(name string) error {
	if a == nil {
		return fmt.Errorf("attribute schema is nil")
	}
	return a.internalValidate(name, "")
}

View on GitHub (pinned to c9def3e214)

Solutions

  1. Set Nesting to an explicit valid NestingMode constant (NestingSingle, NestingGroup, NestingList, NestingSet, or NestingMap).
  2. If the schema is deserialized, validate the incoming nesting value against the known constants before constructing the NestedBlock.
  3. Add a go vet / linter rule or unit test asserting every BlockTypes entry has a non-zero, valid Nesting.

Example fix

// before
BlockTypes: map[string]*NestedBlock{
    "thing": {Block: Block{Attributes: ...}}, // Nesting omitted -> 0
}

// after
BlockTypes: map[string]*NestedBlock{
    "thing": {Nesting: NestingList, Block: Block{Attributes: ...}},
}
Defensive patterns

Strategy: validation

Validate before calling

func assertValidNesting(nb *configschema.NestedBlock) error {
    switch nb.Nesting {
    case configschema.NestingSingle, configschema.NestingGroup,
        configschema.NestingList, configschema.NestingSet, configschema.NestingMap:
        return nil
    default:
        return fmt.Errorf("invalid nesting mode %d", nb.Nesting)
    }
}

Type guard

func hasValidNesting(nb *configschema.NestedBlock) bool {
    switch nb.Nesting {
    case configschema.NestingSingle, configschema.NestingGroup,
        configschema.NestingList, configschema.NestingSet, configschema.NestingMap:
        return true
    }
    return false
}

Prevention

When it happens

Trigger: A NestedBlock struct constructed without setting Nesting, leaving it as the zero value (nestingModeInvalid == 0), or assigned an out-of-range integer cast to NestingMode. The switch at line 73 falls through to default at line 117.

Common situations: Initializing a NestedBlock with a struct literal that omits the Nesting field; partially unmarshalling a schema from JSON/YAML where the nesting key was absent; copying a constant from a different fork whose iota ordering differs.

Related errors


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