hashicorp/terraform · error

%s%s: cannot set both Optional and Required

Error message

%s%s: cannot set both Optional and Required

What it means

Raised when an Attribute has both Optional and Required set to true. These flags are mutually exclusive: Optional permits omission, Required forbids it — together they are contradictory. The validator at internal_validate.go:149 enforces exclusivity.

Source

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

	if a == nil {
		return fmt.Errorf("attribute schema is nil")
	}
	return a.internalValidate(name, "")
}

func (a *Attribute) internalValidate(name, prefix string) error {
	var err error

	/* FIXME: this validation breaks certain existing providers and cannot be enforced without coordination.
	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))
		}
	}

View on GitHub (pinned to c9def3e214)

Solutions

  1. Decide whether the user may omit the value: keep Optional (drop Required) or keep Required (drop Optional).
  2. If you want 'user may override a provider default', use Optional+Computed, not Optional+Required.
  3. Add a schema linter rule that rejects simultaneous Optional and Required.

Example fix

// before
"name": {Type: cty.String, Optional: true, Required: true}

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

Strategy: validation

Validate before calling

func assertNotOptionalAndRequired(a *configschema.Attribute) error {
    if a.Optional && a.Required {
        return fmt.Errorf("cannot set both Optional and Required")
    }
    return nil
}

Type guard

func isMutuallyConsistent(a *configschema.Attribute) bool {
    return !(a.Optional && a.Required)
}

Prevention

When it happens

Trigger: An Attribute struct literal with both Optional: true and Required: true. internalValidate reaches line 149 and the condition holds.

Common situations: Copy-pasting an Optional attribute and adding Required without removing Optional; merging two schema fragments each setting a different flag; confusing 'Optional but with a default' with 'Required'.

Related errors


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