hashicorp/terraform · error
error in marshalPlanVariables
Error message
error in marshalPlanVariables: %s
What it means
Top-level propagation error from Marshal: marshalPlanVariables returned an error while decoding the plan's VariableValues against the module's variable declarations. The wrapped error identifies which variable failed.
Solutions
- Inspect the chained %s error for the specific variable and decode failure.
- Regenerate the plan with the current config so variable types match.
- Ensure the same config revision and Terraform version are used for plan and render.
- Check for recently changed/removed input variables in variables.tf.
Defensive patterns
Strategy: validation
Validate before calling
// Ensure every plan variable decodes against its declared type before marshaling.
func varsDecodeOK(vars map[string]plans.DynamicValue, decls map[string]*configs.Variable) error {
for k, v := range vars {
decl, ok := decls[k]
if !ok {
return fmt.Errorf("variable %%s in plan but not in config", k)
}
if _, err := v.Decode(decl.Type); err != nil {
return fmt.Errorf("variable %%s: %%w", k, err)
}
}
return nil
} Prevention
- Keep config revisions identical between plan and render.
- Re-plan after changing variable types or removing variables.
- Validate variable inputs against declared types before planning.
When it happens
Trigger: A variable value stored in the plan cannot be decoded to the type declared in the module (type drift between plan and config), or a variable present in the plan is missing from the config declarations.
Common situations: Config edited (variable type changed, variable removed/renamed) after the plan was created; cross-version plan rendering; CI using a different config revision than the planner.
Related errors
- error in marshaling deferred action invocations
- error in marshaling deferred resource changes
- error in marshaling output changes
- error in marshaling resource changes
- error in marshaling resource drift
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/ddc281b0207dd57a.
Report an issue: GitHub.
Appendix: 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 d32a084675)