hashicorp/terraform · error

error in marshalPlanVariables: %s

Error message

error in marshalPlanVariables: %s

What it means

Top-level wrapper: output.marshalPlanVariables failed while serializing the plan's variables section. The inner failure is either a DynamicValue decode of a variable value (v.Decode(cty.DynamicPseudoType)) or a ctyjson.Marshal of a variable value or its default.

Source

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

}

// Marshal returns the json encoding of a terraform plan.
func Marshal(
	config *configs.Config,
	p *plans.Plan,
	sf *statefile.File,
	schemas *terraform.Schemas,
) ([]byte, error) {
	output := newPlan()
	output.TerraformVersion = version.String()
	output.Timestamp = p.Timestamp.Format(time.RFC3339)
	output.Applyable = p.Applyable
	output.Complete = p.Complete
	output.Errored = p.Errored

	err := output.marshalPlanVariables(p.VariableValues, config.Module.Variables)
	if err != nil {
		return nil, fmt.Errorf("error in marshalPlanVariables: %s", err)
	}

	// output.PlannedValues
	err = output.marshalPlannedValues(p.Changes, schemas)
	if err != nil {
		return nil, fmt.Errorf("error in marshalPlannedValues: %s", err)
	}

	// 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 {

View on GitHub (pinned to c9def3e214)

Solutions

  1. Regenerate the plan with the current Terraform binary so variable encoding matches.
  2. Inspect the wrapped inner error to find which variable failed.
  3. Simplify or check unusual variable types (e.g. deeply nested object types) in the root module.
Defensive patterns

Strategy: try-catch

Try / catch

out, err := jsonplan.Marshal(config, plan, sf, schemas)
if err != nil {
    // 'error in marshalPlanVariables' wraps the variable-specific failure;
    // log err and inspect the inner message to find the offending variable.
    return err
}

Prevention

When it happens

Trigger: Reached on every full Marshal call. marshalPlanVariables iterates p.VariableValues, decoding each DynamicValue and re-marshaling to JSON; any decode/type error or non-JSON-serializable value aborts and is wrapped here.

Common situations: Plan saved by a Terraform version that encoded variables in a form the current binary cannot decode; a variable whose value is of a cty type ctyjson cannot represent; corrupted plan file.

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/ddc281b0207dd57a. Report an issue: GitHub.