hashicorp/terraform · error

error in marshaling resource drift

Error message

error in marshaling resource drift: %s

What it means

Top-level propagation error from Marshal: MarshalResourceChanges failed on the drifted-resources subset. Drifted resources are decoded and rendered like other resource changes, so the failure is usually schema or decode related.

Solutions

  1. Read the wrapped error for the specific resource address.
  2. Ensure the provider for the drifted resource type is initialized.
  3. Regenerate the plan so drift reflects current schemas.
  4. If the resource was removed from config/provider intentionally, refresh state to clear drift.
Defensive patterns

Strategy: validation

Validate before calling

// Confirm each drifted resource has a usable schema before marshaling.
func driftedSchemasOk(drifted []*plans.ResourceInstanceChangeSrc, schemas *terraform.Schemas) error {
    for _, d := range drifted {
        s := schemas.ResourceTypeConfig(d.ProviderAddr.Provider, d.Addr.Resource.Resource.Mode, d.Addr.Resource.Resource.Type)
        if s.Body == nil {
            return fmt.Errorf("drifted resource %%s has no schema", d.Addr)
        }
    }
    return nil
}

Prevention

When it happens

Trigger: A drifted resource instance references a provider schema that is missing or incompatible at render time, or its before/after values fail to decode.

Common situations: Drift detected against resources whose provider was since changed/removed; refresh-only mode plans rendered with a different provider set.

Related errors


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

Appendix: source

Thrown at internal/command/jsonplan/plan.go:293

	// output.ResourceDrift
	if len(p.DriftedResources) > 0 {
		// In refresh-only mode, we render all resources marked as drifted,
		// including those which have moved without other changes. In other plan
		// modes, move-only changes will be included in the planned changes, so
		// we skip them here.
		var driftedResources []*plans.ResourceInstanceChangeSrc
		if p.UIMode == plans.RefreshOnlyMode {
			driftedResources = p.DriftedResources
		} else {
			for _, dr := range p.DriftedResources {
				if dr.Action != plans.NoOp {
					driftedResources = append(driftedResources, dr)
				}
			}
		}
		output.ResourceDrift, err = MarshalResourceChanges(driftedResources, schemas)
		if err != nil {
			return nil, fmt.Errorf("error in marshaling resource drift: %s", err)
		}
	}

	if err := output.marshalRelevantAttrs(p); err != nil {
		return nil, fmt.Errorf("error marshaling relevant attributes for external changes: %s", err)
	}

	// output.ResourceChanges
	if p.Changes != nil {
		output.ResourceChanges, err = MarshalResourceChanges(p.Changes.Resources, schemas)
		if err != nil {
			return nil, fmt.Errorf("error in marshaling resource changes: %s", err)
		}
	}

	if p.DeferredResources != nil {
		output.DeferredChanges, err = MarshalDeferredResourceChanges(p.DeferredResources, schemas)
		if err != nil {

View on GitHub (pinned to d32a084675)