hashicorp/terraform · error

top-level block: DeprecationMessage must not be set when…

Error message

top-level block: DeprecationMessage must not be set when Deprecated is false

What it means

During schema validation, the top-level Block has a non-empty DeprecationMessage but Deprecated is false. These two fields must be consistent: DeprecationMessage is only meaningful when Deprecated is true. This is a provider-developer error caught when the provider schema is loaded and validated by Terraform core.

Solutions

  1. If using terraform-plugin-framework, set both DeprecationMessage and the deprecated flag consistently in your schema definition.
  2. If maintaining a custom schema struct, set b.Deprecated = true whenever b.DeprecationMessage != "".
  3. Review the provider code for the resource/data source whose schema triggers this and fix the field combination.

Example fix

// before — DeprecationMessage without Deprecated
&configschema.Block{
    DeprecationMessage: "Use 'new_resource' instead",
    // Deprecated not set → defaults to false
}

// after — both set consistently
&configschema.Block{
    Deprecated:         true,
    DeprecationMessage: "Use 'new_resource' instead",
}
Defensive patterns

Strategy: validation

Validate before calling

// Provider developers: validate deprecation field consistency
func validateDeprecationFields(b *configschema.Block) error {
    if !b.Deprecated && b.DeprecationMessage != "" {
        return errors.New("DeprecationMessage set but Deprecated is false")
    }
    return b.InternalValidate()
}

// Unit test gate:
func TestSchemaDeprecationConsistency(t *testing.T) {
    if err := myResourceSchema().InternalValidate(); err != nil {
        t.Fatal(err)
    }
}

Prevention

When it happens

Trigger: A provider schema defines DeprecationMessage on the root block without setting Deprecated: true. The internalValidate check at the top level (prefix == "") catches this inconsistency. Triggered during NewContext when provider schemas are loaded.

Common situations: A provider developer sets DeprecationMessage expecting it to work standalone, not realizing Deprecated must also be true. Copy-paste from a nested block where the combination was valid. Framework abstraction that auto-populates one field but not the other. Schema migration from terraform-plugin-sdk to terraform-plugin-framework where field semantics differ.

Related errors


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

Appendix: 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 d32a084675)