hashicorp/terraform · error

%s%s: either Type or NestedType must be defined

Error message

%s%s: either Type or NestedType must be defined

What it means

Raised when an Attribute has neither Type nor NestedType set. Every attribute must carry a type — either a flat cty.Type or a structural *Object via NestedType; an attribute with neither has no representable value. The check at internal_validate.go:159 tests for Type==cty.NilType && NestedType==nil.

Source

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

	if !validName.MatchString(name) {
		err = errors.Join(err, fmt.Errorf("%s%s: name may contain only lowercase letters, digits and underscores", prefix, name))
	}
	*/
	if !a.Optional && !a.Required && !a.Computed {
		err = errors.Join(err, fmt.Errorf("%s%s: must set Optional, Required or Computed", prefix, name))
	}
	if a.Optional && a.Required {
		err = errors.Join(err, fmt.Errorf("%s%s: cannot set both Optional and Required", prefix, name))
	}
	if a.Computed && a.Required {
		err = errors.Join(err, fmt.Errorf("%s%s: cannot set both Computed and Required", prefix, name))
	}
	if !a.Deprecated && a.DeprecationMessage != "" {
		err = errors.Join(err, fmt.Errorf("%s%s: DeprecationMessage must not be set when Deprecated is false", prefix, name))
	}

	if a.Type == cty.NilType && a.NestedType == nil {
		err = errors.Join(err, fmt.Errorf("%s%s: either Type or NestedType must be defined", prefix, name))
	}

	if a.Type != cty.NilType {
		if a.NestedType != nil {
			err = errors.Join(fmt.Errorf("%s: Type and NestedType cannot both be set", name))
		}
	}

	if a.NestedType != nil {
		switch a.NestedType.Nesting {
		case NestingSingle, NestingMap, NestingGroup:
			// no validations to perform
		case NestingList, NestingSet:
			if a.NestedType.Nesting == NestingSet {
				ety := a.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

View on GitHub (pinned to c9def3e214)

Solutions

  1. Set Type to a concrete cty type (e.g. cty.String, cty.List(cty.Number)).
  2. If the attribute is a structural object, set NestedType to a populated *Object with a NestingMode.
  3. Validate schemas in unit tests so untyped attributes fail immediately.

Example fix

// before
"name": {Optional: true},

// after
"name": {Type: cty.String, Optional: true}
Defensive patterns

Strategy: validation

Validate before calling

func assertHasType(a *configschema.Attribute) error {
    if a.Type == cty.NilType && a.NestedType == nil {
        return fmt.Errorf("attribute must define Type or NestedType")
    }
    return nil
}

Type guard

func hasTypeOrNestedType(a *configschema.Attribute) bool {
    return a.Type != cty.NilType || a.NestedType != nil
}

Prevention

When it happens

Trigger: An Attribute struct literal with Optional: true but no Type or NestedType field. internalValidate reaches line 159 and the conjunction is true.

Common situations: Adding an attribute and forgetting its type; refactoring that moved the type into a helper returning the zero Type; copy-pasting a placeholder attribute that was never filled in.

Related errors


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