hashicorp/terraform · error
%s%s: must set Optional, Required or Computed
Error message
%s%s: must set Optional, Required or Computed
What it means
Raised when an Attribute has none of Optional, Required, or Computed set. Every attribute must declare its lifecycle so Terraform knows whether the user, the provider, or both supply the value; an undeclared attribute is ambiguous. The check lives at internal_validate.go:146.
Source
Thrown at internal/configs/configschema/internal_validate.go:147
// 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, "")
}
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
- Set exactly one of Optional, Required, or Computed (or Optional+Computed for provider-overridable defaults).
- If the attribute is purely informational from the provider, use Computed: true.
- Run InternalValidate in provider unit tests so missing flags fail fast.
Example fix
// before
"name": {Type: cty.String},
// after
"name": {Type: cty.String, Optional: true, Computed: true} Defensive patterns
Strategy: validation
Validate before calling
func assertAttributeLifecycle(a *configschema.Attribute) error {
if !a.Optional && !a.Required && !a.Computed {
return fmt.Errorf("attribute must set Optional, Required, or Computed")
}
return nil
} Type guard
func hasLifecycleFlag(a *configschema.Attribute) bool {
return a.Optional || a.Required || a.Computed
} Prevention
- Always set at least one of Optional/Required/Computed when defining an attribute.
- For provider-only output, use Computed; for user input use Optional or Required.
- Validate schemas in unit tests so missing flags surface immediately.
When it happens
Trigger: An Attribute struct literal with Type set but Optional, Required, and Computed all left as zero-value false. internalValidate at line 138 reaches line 146 and the conjunction is true.
Common situations: Adding a new attribute and forgetting its lifecycle flag; relying on a helper that returns an Attribute without setting any flag; migrating from a schema DSL that inferred optionality implicitly.
Related errors
- %s%s: cannot set both Optional and Required
- %s%s: cannot set both Computed and Required
- %s%s: all attributes within computed blocks must also be com
- %s%s: all nested blocks within computed blocks must also be
- %s%s: NestingGroup blocks cannot be computed
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/df1d4dc2bc81126e.
Report an issue: GitHub.