hashicorp/terraform · error

: Type and NestedType cannot both be set

Error message

%s: Type and NestedType cannot both be set

What it means

Thrown by Attribute.internalValidate when a provider/schema attribute defines both a Type (a primitive/collection cty type) and a NestedType (a block-style nested object). The schema model is mutually exclusive: an attribute is either a flat value of Type or a nested block described by NestedType, never both. Note this specific call uses errors.Join without the prior err accumulator, so on this branch earlier collected errors are dropped (likely a latent bug), but the trigger condition itself is genuine.

Solutions

  1. Inspect the offending attribute named in the error and pick one representation: keep Type for a scalar/list/map/set value OR keep NestedType for a nested block — not both.
  2. If you intended a nested block, set Attribute.Type = cty.NilType (leave it unset) and populate only Attribute.NestedType.
  3. If you intended a typed collection value (e.g. list of objects as a single value), drop NestedType and express the element shape inside Type, e.g. cty.List(cty.Object(...)).
  4. Add a unit test that calls schema.InternalValidate() / block.InternalValidate() right after construction so this fails at build time instead of runtime.

Example fix

// before
attr := &configschema.Attribute{
    Type: cty.List(cty.String),
    NestedType: &configschema.Object{
        Nesting: configschema.NestingList,
        Attributes: map[string]*configschema.Attribute{...},
    },
    Optional: true,
}

// after — choose nested block form
attr := &configschema.Attribute{
    NestedType: &configschema.Object{
        Nesting: configschema.NestingList,
        Attributes: map[string]*configschema.Attribute{...},
    },
    Optional: true,
}
Defensive patterns

Strategy: validation

Validate before calling

// Run before InternalValidate on any hand-built schema.
func assertTypeXORNestedType(a *configschema.Attribute) error {
    if a.Type != cty.NilType && a.NestedType != nil {
        return fmt.Errorf("attribute cannot set both Type and NestedType")
    }
    if a.Type == cty.NilType && a.NestedType == nil {
        return fmt.Errorf("attribute must set either Type or NestedType")
    }
    return nil
}

Type guard

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

Prevention

When it happens

Trigger: Building a *configschema.Attribute where both Attribute.Type is set (e.g. cty.String) and Attribute.NestedType is non-nil, then calling InternalValidate() on the containing Block/Object (which recurses into internalValidate). Typical in Terraform plugin SDK/terraform-plugin-framework schema conversion or hand-built schemas in tests.

Common situations: Migrating a provider schema between SDK v1 (Type) and terraform-plugin-framework (NestedType/Blocks) and forgetting to clear the old field; copy-pasting an attribute definition and adding a NestedType while leaving Type populated; converting a list-of-objects attribute represented as Type=cty.List(...) into a NestedType=NestingList block without removing Type.

Related errors


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

Appendix: source

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

		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
					// properly hash them, and so can't support mixed types.
					err = errors.Join(err, fmt.Errorf("%s%s: NestingSet attributes may not contain attributes of cty.DynamicPseudoType", prefix, name))
				}
				if a.NestedType.ContainsWriteOnly() {
					// This is not permitted because any marks within sets will

View on GitHub (pinned to d32a084675)