OpenTofu Error: 'Invalid template interpolation value' Complex Type in String
Fix OpenTofu's 'Invalid template interpolation value' error: stop interpolating a list, map, or object into a string and convert it with jsonencode or join instead.
- #opentofu
- #terraform
- #iac
- #troubleshooting
- #errors
Stuck on this OpenTofu error? Get the free incident triage checklist
A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.
Exact Error Message
╷
│ Error: Invalid template interpolation value
│
│ on main.tf line 14, in resource "aws_instance" "web":
│ 14: user_data = "servers=${var.server_list}"
│ ├────────────────
│ │ var.server_list is list of string with 3 elements
│
│ Cannot include the given value in a string template: string required.
╵
The message ends with Cannot include the given value in a string template: string required and the ├── line shows the complex type (here a list of string) you tried to interpolate.
What It Means
String interpolation with ${ ... } produces a string, so the value inside must be convertible to a string. OpenTofu can convert scalars — strings, numbers, and booleans — automatically. It cannot silently convert a collection (list, set, tuple, map, or object) into a string, because there is no single obvious representation. When you place such a complex value inside a "...${...}..." template, OpenTofu refuses with Invalid template interpolation value.
The fix is to decide explicitly how the collection should become text: encode it as JSON, join its elements with a separator, or reference a single scalar element instead of the whole collection.
Common Causes
- Interpolating a whole list or set into a string, for example
"${var.subnets}". - Interpolating a map or object where a string was expected.
- Passing a complex output of one resource into a string field of another without converting it.
- Building a
user_data, tag value, or label from a variable that is a collection rather than a scalar. - Forgetting an index or key, so
var.tagsis used wherevar.tags["Name"]was intended.
Diagnostic Commands
Reproduce and locate the offending interpolation:
tofu validate
Check the actual type of the value you are interpolating:
tofu console
> type(var.server_list)
Preview how the value would look once encoded as a string:
echo 'jsonencode(["a","b","c"])' | tofu console
# "[\"a\",\"b\",\"c\"]"
Test a join instead, if a delimited string is what you want:
echo 'join(",", ["a","b","c"])' | tofu console
# "a,b,c"
Step-by-Step Resolution
-
Run
tofu validateand read the├──line to confirm the value’s type.list of string,map of ..., orobject(...)all indicate a collection that cannot be interpolated directly. -
If you want a JSON representation (common for
user_data, IAM policies, or config blobs), wrap the value withjsonencode:
user_data = jsonencode({ servers = var.server_list })
- If you want a simple delimited string, use
joinfor lists/sets:
user_data = "servers=${join(",", var.server_list)}"
- If you actually meant a single element, add the index or key so the interpolated value is a scalar:
tags = {
Name = "web-${var.server_list[0]}"
}
- For maps or objects, either
jsonencodethe whole thing or reference one attribute:
labels = jsonencode(var.tags) # whole map as JSON
env = "region=${var.tags["region"]}" # single scalar value
- Validate and plan to confirm the template now produces a valid string:
tofu validate && tofu plan
Prevention
- Never interpolate a collection directly; decide up front whether you want JSON (
jsonencode) or a delimited string (join). - Use
typeconstraints on variables so it is obvious which are scalars and which are collections before you reference them. - When a field needs structured data, prefer
jsonencode/yamlencodeover hand-built strings — they are safe and escape correctly. - Test interpolations in
tofu consolebefore wiring them into resources, especially foruser_dataand policy documents. - Reference
[index]or["key"]when you only need one element, rather than the whole collection. The prompt library has prompts that generate correctjsonencode/joinexpressions for common fields.
Related Errors
Invalid value for input variable— a variable that fails atypeconstraint before interpolation is even attempted.Call to unknown function— a typo injsonencode/joinsuch asjsonencde.Unsuitable value type— a value of the wrong type assigned to a typed argument, outside a template.Invalid index— indexing a collection with a key or position that does not exist.
Frequently Asked Questions
Why can OpenTofu interpolate a number but not a list? Numbers and booleans have a single, unambiguous string form. A list, map, or object could be rendered many ways, so OpenTofu requires you to choose one explicitly with join or jsonencode.
Should I use jsonencode or join? Use jsonencode when the consumer expects structured JSON (user_data scripts, policies, config files). Use join when you just need the elements as one delimited line, such as a,b,c.
Can I interpolate a single element of a list? Yes. var.list[0] or var.map["key"] yields a scalar, which interpolates cleanly. The error only occurs when the whole collection is placed in the template.
Does this apply to heredoc templates too? Yes. The same rule applies inside <<EOT ... EOT heredocs and templatefile() — any ${ ... } must resolve to a string-convertible value.
Where can I find more OpenTofu troubleshooting? See the OpenTofu guides for the full catalog of error walkthroughs.
Fixed it? Get 500 OpenTofu & DevOps AI prompts — free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.
Did this fix your issue?
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.