{"record":{"id":"ddc281b0207dd57a","repo":"hashicorp/terraform","slug":"error-in-marshalplanvariables-s","errorCode":null,"errorMessage":"error in marshalPlanVariables: %s","messagePattern":"error in marshalPlanVariables: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/command/jsonplan/plan.go","lineNumber":266,"sourceCode":"}\n\n// Marshal returns the json encoding of a terraform plan.\nfunc Marshal(\n\tconfig *configs.Config,\n\tp *plans.Plan,\n\tsf *statefile.File,\n\tschemas *terraform.Schemas,\n) ([]byte, error) {\n\toutput := newPlan()\n\toutput.TerraformVersion = version.String()\n\toutput.Timestamp = p.Timestamp.Format(time.RFC3339)\n\toutput.Applyable = p.Applyable\n\toutput.Complete = p.Complete\n\toutput.Errored = p.Errored\n\n\terr := output.marshalPlanVariables(p.VariableValues, config.Module.Variables)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error in marshalPlanVariables: %s\", err)\n\t}\n\n\t// output.PlannedValues\n\terr = output.marshalPlannedValues(p.Changes, schemas)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error in marshalPlannedValues: %s\", err)\n\t}\n\n\t// output.ResourceDrift\n\tif len(p.DriftedResources) > 0 {\n\t\t// In refresh-only mode, we render all resources marked as drifted,\n\t\t// including those which have moved without other changes. In other plan\n\t\t// modes, move-only changes will be included in the planned changes, so\n\t\t// we skip them here.\n\t\tvar driftedResources []*plans.ResourceInstanceChangeSrc\n\t\tif p.UIMode == plans.RefreshOnlyMode {\n\t\t\tdriftedResources = p.DriftedResources\n\t\t} else {","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/command/jsonplan/plan.go#L248-L284","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Ensure every plan variable decodes against its declared type before marshaling.\nfunc varsDecodeOK(vars map[string]plans.DynamicValue, decls map[string]*configs.Variable) error {\n    for k, v := range vars {\n        decl, ok := decls[k]\n        if !ok {\n            return fmt.Errorf(\"variable %%s in plan but not in config\", k)\n        }\n        if _, err := v.Decode(decl.Type); err != nil {\n            return fmt.Errorf(\"variable %%s: %%w\", k, err)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["go","terraform","plan","variables","decode","error-wrapping","jsonplan"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}