hashicorp/terraform · error
top-level block: DeprecationMessage must not be set when Dep
Error message
top-level block: DeprecationMessage must not be set when Deprecated is false
What it means
At the top-level block only (prefix==""), DeprecationMessage is non-empty while Deprecated is false. The schema contract (documented on Block.DeprecationMessage) is that the message is valid only when Deprecated is true; setting the message without the flag is contradictory. Caught at lines 32-34 before recursing.
Source
Thrown at internal/configs/configschema/internal_validate.go:33
// InternalValidate returns an error if the receiving block and its child schema
// definitions have any inconsistencies with the documented rules for valid
// schema.
//
// This can be used within unit tests to detect when a given schema is invalid,
// and is run when terraform loads provider schemas during NewContext.
func (b *Block) InternalValidate() error {
if b == nil {
return fmt.Errorf("top-level block schema is nil")
}
return b.internalValidate("")
}
func (b *Block) internalValidate(prefix string) error {
var multiErr error
if prefix == "" && !b.Deprecated && b.DeprecationMessage != "" {
multiErr = errors.Join(multiErr, fmt.Errorf("top-level block: DeprecationMessage must not be set when Deprecated is false"))
}
for name, attrS := range b.Attributes {
if attrS == nil {
multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: attribute schema is nil", prefix, name))
continue
}
multiErr = errors.Join(multiErr, attrS.internalValidate(name, prefix))
// all attributes within a computed block must also be computed
if b.Computed && !attrS.Computed {
multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: all attributes within computed blocks must also be computed", prefix, name))
}
}
for name, blockS := range b.BlockTypes {
if blockS == nil {
multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: block schema is nil", prefix, name))View on GitHub (pinned to c9def3e214)
Solutions
- Set Deprecated = true alongside DeprecationMessage on the top-level Block.
- Or clear DeprecationMessage if the resource is not actually deprecated.
- Add a schema-builder helper that enforces the pairing invariant.
Example fix
// before
schema := &configschema.Block{
DeprecationMessage: "use 'foo_v2' instead",
}
// after
schema := &configschema.Block{
Deprecated: true,
DeprecationMessage: "use 'foo_v2' instead",
} Defensive patterns
Strategy: validation
Validate before calling
// In a schema builder helper, assert the invariant:
// if DeprecationMessage != "" then Deprecated must be true.
func checkDeprecation(b *configschema.Block) error {
if !b.Deprecated && b.DeprecationMessage != "" {
return errors.New("DeprecationMessage set without Deprecated=true")
}
return nil
} Prevention
- Set Deprecated and DeprecationMessage together in one edit.
- Add a unit test/linter that enforces the pairing on the root block.
When it happens
Trigger: A provider schema sets b.DeprecationMessage = "use x instead" but forgets b.Deprecated = true on the root block.
Common situations: Adding a deprecation notice incrementally, copy-paste from a deprecated block missing the flag, SDK auto-generation mismatch.
Related errors
- %s%s: DeprecationMessage must not be set when Deprecated is
- top-level block schema is nil
- %s%s: attribute schema is nil
- %s%s: all attributes within computed blocks must also be com
- %s%s: block schema is nil
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/69117209567f5c11.
Report an issue: GitHub.