hashicorp/terraform · error

Apply discarded.

Error message

Apply discarded.

What it means

An Attribute has a non-empty DeprecationMessage while Deprecated is false. As with nested blocks, DeprecationMessage is only valid alongside Deprecated=true, so the schema is inconsistent. The attribute-level check mirrors the block-level one.

Solutions

  1. Set Deprecated: true so the DeprecationMessage is honored.
  2. Remove the DeprecationMessage if the attribute is not actually deprecated.

Example fix

// before
"old_attr": { Type: cty.String, Optional: true, DeprecationMessage: "use new_attr" },
// after
"old_attr": { Type: cty.String, Optional: true, Deprecated: true, DeprecationMessage: "use new_attr" },
Defensive patterns

Strategy: validation

Validate before calling

// Attribute deprecation fields must agree.
func attrDeprecationConsistent(a *configschema.Attribute) bool {
    return a == nil || a.Deprecated || a.DeprecationMessage == ""
}

Type guard

func deprecationConsistent(deprecated bool, msg string) bool { return msg == "" || deprecated }

Prevention

When it happens

Trigger: An Attribute with DeprecationMessage: "use new_attr" but Deprecated left false. Guard at internal_validate.go:155 is `!a.Deprecated && a.DeprecationMessage != ""`.

Common situations: Authoring a deprecation message and forgetting the Deprecated flag; clearing Deprecated during un-deprecation but leaving the message string behind.

Related errors


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

Appendix: source

Thrown at internal/backend/remote/backend_common.go:26

	"context"
	"errors"
	"fmt"
	"io"
	"math"
	"strconv"
	"strings"
	"time"

	tfe "github.com/hashicorp/go-tfe"

	"github.com/hashicorp/terraform/internal/backend/backendrun"
	"github.com/hashicorp/terraform/internal/logging"
	"github.com/hashicorp/terraform/internal/plans"
	"github.com/hashicorp/terraform/internal/terraform"
)

var (
	errApplyDiscarded   = errors.New("Apply discarded.")
	errDestroyDiscarded = errors.New("Destroy discarded.")
	errRunApproved      = errors.New("approved using the UI or API")
	errRunDiscarded     = errors.New("discarded using the UI or API")
	errRunOverridden    = errors.New("overridden using the UI or API")
)

var (
	backoffMin = 1000.0
	backoffMax = 3000.0

	runPollInterval = 3 * time.Second
)

// backoff will perform exponential backoff based on the iteration and
// limited by the provided min and max (in milliseconds) durations.
func backoff(min, max float64, iter int) time.Duration {
	backoff := math.Pow(2, float64(iter)/5) * min
	if backoff > max {

View on GitHub (pinned to d32a084675)