hashicorp/terraform · error
invalid expression for variable
Error message
invalid expression for variable %q: %s
What it means
After extracting attributes, decode_tfvars evaluates each value expression with a nil EvalContext, matching Terraform CLI's .tfvars semantics which reject function calls and references to symbols. If an individual value expression references a symbol or invokes a function, this error names the offending variable.
Solutions
- Use only literal values in the tfvars string (numbers, strings, lists, objects) — no references and no function calls
- Compute derived values in Terraform first, then pass the literal result into the string
- If references are required, switch from a tfvars string to a proper module input or a different encoding
Example fix
// before
decode_tfvars("a = upper(\"x\")")
// after
decode_tfvars("a = \"X\"") Defensive patterns
Strategy: validation
Validate before calling
// Evaluate each attribute expression with a nil EvalContext to surface reference/call errors early.
// In Go (mirrors decode_tfvars semantics):
attrs, _ := f.Body.JustAttributes()
for name, attr := range attrs {
if _, diags := attr.Expr.Value(nil); diags.HasErrors() {
// variable 'name' contains an illegal reference or call; report it
}
} Prevention
- Treat tfvars values as literals only — no var., local., or function calls
- Pre-compute any derived value in Terraform and inline the literal result
- When generating tfvars strings from templates, scan for ${...} or unquoted references before use
When it happens
Trigger: decode_tfvars("a = somefunc()") with a function call in a value; decode_tfvars("a = var.other") with a reference; decode_tfvars("a = local.x") referencing a local.
Common situations: Building a tfvars string dynamically that accidentally interpolates references; assuming tfvars values can reference other variables or call functions (they cannot); migrating a config snippet into a tfvars string without stripping references.
Related errors
- invalid tfvars syntax
- cannot decode tfvars from a null value
- invalid tfvars content
- 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/7c37c8c83d0fc61a.
Report an issue: GitHub.
Appendix: source
Thrown at internal/builtin/providers/terraform/functions.go:134
// 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 language
// runtime should check them before calling, so this is just for robustness
// and completeness.
if len(args) > 1 {
return cty.NilVal, function.NewArgErrorf(1, "too many arguments; only one expected")
}
if len(args) == 0 {
return cty.NilVal, fmt.Errorf("exactly one argument is required")
}
View on GitHub (pinned to d32a084675)