hashicorp/terraform · error
invalid tfvars content
Error message
invalid tfvars content: %s
What it means
After a successful parse, decode_tfvars calls Body.JustAttributes(), which fails if the body contains nested blocks rather than only top-level attribute = value assignments. tfvars semantics allow only flat attribute assignments, so a structurally valid HCL body of the wrong shape is rejected here.
Solutions
- Flatten the input to top-level attribute = value pairs only, using object literal syntax (key = { a = 1 }) rather than blocks for nested values
- Use the appropriate decoder (jsondecode, yamldecode) if the input is not tfvars-shaped
- Strip any resource/provider/variable blocks from the string before passing it
Example fix
// before
decode_tfvars("nested { x = 1 }")
// after
decode_tfvars("nested = { x = 1 }") Defensive patterns
Strategy: validation
Validate before calling
// After parsing, confirm the body is attribute-only before calling decode_tfvars.
// In Go:
if _, diags := f.Body.JustAttributes(); diags.HasErrors() {
// reject the input as not tfvars-shaped; it contains blocks
return diags
} Prevention
- Distinguish .tfvars (flat attributes only) from .tf (blocks allowed); never feed a full config to decode_tfvars
- Express nested values as object literals (key = { a = 1 }), never as blocks, inside tfvars strings
- If you need to decode structured config, use jsondecode/yamldecode on a JSON/YAML representation instead
When it happens
Trigger: decode_tfvars("nested { x = 1 }") where the body declares a block; decode_tfvars with a full Terraform configuration string containing resource/provider blocks instead of tfvars content.
Common situations: Passing a complete .tf configuration to decode_tfvars by mistake; confusing decode_tfvars with jsondecode/yamldecode and feeding structured config; building a tfvars string that nests objects via blocks instead of object literal syntax.
Related errors
- cannot decode tfvars from a null value
- invalid expression for variable
- invalid tfvars syntax
- all arguments must have the same type
- argument must be a list or tuple
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/2778a7260d684342.
Report an issue: GitHub.
Appendix: source
Thrown at internal/builtin/providers/terraform/functions.go:125
// If we get here then we know that:
// - there's exactly one element in args
// - it's a string
// - it is known and non-null
// So therefore the following is guaranteed to succeed.
src := []byte(args[0].AsString())
// As usual when we wrap HCL stuff up in functions, we end up needing to
// stuff HCL diagnostics into plain string error messages. This produces
// a non-ideal result but is still better than hiding the HCL-provided
// diagnosis altogether.
f, hclDiags := hclsyntax.ParseConfig(src, "<decode_tfvars argument>", hcl.InitialPos)
if hclDiags.HasErrors() {
return cty.NilVal, fmt.Errorf("invalid tfvars syntax: %s", hclDiags.Error())
}
attrs, hclDiags := f.Body.JustAttributes()
if hclDiags.HasErrors() {
return cty.NilVal, fmt.Errorf("invalid tfvars content: %s", hclDiags.Error())
}
retAttrs := make(map[string]cty.Value, len(attrs))
for name, attr := range attrs {
// Evaluating the expression with no EvalContext achieves the same
// interpretation as Terraform CLI makes of .tfvars files, rejecting
// any function calls or references to symbols.
v, hclDiags := attr.Expr.Value(nil)
if hclDiags.HasErrors() {
return cty.NilVal, fmt.Errorf("invalid expression for variable %q: %s", name, hclDiags.Error())
}
retAttrs[name] = v
}
return cty.ObjectVal(retAttrs), nil
}
func encodeExprFunc(args []cty.Value) (cty.Value, error) {
// These error checks should not be hit in practice because the languageView on GitHub (pinned to d32a084675)