hashicorp/terraform · error

failed to decode backend config

Error message

failed to decode backend config: %w

What it means

Returned by BackendConfigState.PlanData when s.Config(schema) fails to decode the stored backend config against the provided backend schema while building a plan's Backend block. The %w wraps the underlying decoder error (typically a cty/schema conformance failure on the raw config bytes).

Solutions

  1. Run `terraform init` against the current binary so the backend config is re-validated and re-written.
  2. Inspect the wrapped error for the offending argument; fix it in the `backend "<type>"` block and re-init.
  3. If the binary was downgraded, upgrade back to (or past) the version that wrote the state file.
  4. As a last resort, remove the stale .terraform/terraform.tfstate backend record and re-init from scratch.

Example fix

# before — error on plan after switching terraform versions
terraform plan

# after — re-initialise so the backend config matches the binary
terraform init
terraform plan
Defensive patterns

Strategy: validation

Validate before calling

// pre-flight before calling PlanData: confirm config decodes against current schema
if _, err := s.Config(schema); err != nil {
    return nil, fmt.Errorf("re-run `terraform init`: backend config no longer matches schema: %w", err)
}

Try / catch

configVal, err := s.Config(schema)
if err != nil {
    return nil, fmt.Errorf("failed to decode backend config: %w; run `terraform init` to reconcile", err)
}

Prevention

When it happens

Trigger: Calling BackendConfigState.PlanData during plan creation when the on-disk backend config (in .terraform/terraform.tfstate) no longer matches the compiled-in backend schema — unknown arguments, wrong types, or a backend type whose schema changed between Terraform versions.

Common situations: Downgrading Terraform/OpenTofu after a newer backend wrote config using arguments the older build doesn't know, hand-editing the backend state file, or a backend plugin schema change without `terraform init` re-running.

Understand the failure class

Related errors


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

Appendix: source

Thrown at internal/command/workdir/backend_config_state.go:86

	return nil
}

// PlanData produces an alternative representation of the receiver that is
// suitable for storing in a plan. The current workspace must additionally
// be provided, to be stored alongside the backend configuration.
//
// The backend configuration schema is required in order to properly
// encode the backend-specific configuration settings.
//
// As backends are not implemented by providers, the provider schema argument should always be nil
func (s *BackendConfigState) PlanData(schema *configschema.Block, _ *configschema.Block, workspaceName string) (*plans.Backend, error) {
	if s == nil {
		return nil, nil
	}

	configVal, err := s.Config(schema)
	if err != nil {
		return nil, fmt.Errorf("failed to decode backend config: %w", err)
	}
	return plans.NewBackend(s.Type, configVal, schema, workspaceName)
}

func (s *BackendConfigState) DeepCopy() *BackendConfigState {
	if s == nil {
		return nil
	}
	ret := &BackendConfigState{
		Type: s.Type,
		Hash: s.Hash,
	}

	if s.ConfigRaw != nil {
		ret.ConfigRaw = make([]byte, len(s.ConfigRaw))
		copy(ret.ConfigRaw, s.ConfigRaw)
	}
	return ret

View on GitHub (pinned to d32a084675)