Fix Terraform Error - Invalid Function Argument
Fix the Terraform invalid function argument error. Covers type mismatches for join, lookup, cidrsubnet, file, and other built-in functions with examples.
Troubleshooting
Fix the Terraform invalid template interpolation error when embedding complex types in strings. Covers jsonencode, join, format, and type conversion patterns.
You're trying to interpolate a complex type (list, map, or object) directly into a string template. Terraform can only interpolate scalar values (strings, numbers, booleans) into strings. Use jsonencode() to serialize complex types, join() for lists, or access individual elements.
When running terraform plan or terraform validate:
Error: Invalid template interpolation value
on main.tf line 5, in resource "aws_instance" "web":
5: user_data = "Subnets: ${var.subnet_ids}"
Cannot include the given value in a string template: string required.Error: Invalid template interpolation value
Cannot include the given value in a string template:
the value is list of string, which does not have a single
string representation.Terraform string templates ("${...}") only accept values that can be represented as a single string. Lists, maps, sets, and objects can't be directly embedded.
# BAD — list in string template
output "subnets" {
value = "Subnets: ${var.subnet_ids}" # var.subnet_ids is a list
}
# BAD — map in string template
output "config" {
value = "Config: ${var.tags}" # var.tags is a map
}
# BAD — object in string template
output "server" {
value = "Server: ${aws_instance.web}" # resource reference is an object
}Convert any complex type to a JSON string:
# Lists
output "subnets" {
value = "Subnets: ${jsonencode(var.subnet_ids)}"
}
# Output: Subnets: ["subnet-abc","subnet-def","subnet-ghi"]
# Maps
output "tags" {
value = "Tags: ${jsonencode(var.tags)}"
}
# Output: Tags: {"Environment":"prod","Project":"myapp"}
# Objects
output "instance" {
value = "Instance ID: ${jsonencode(aws_instance.web.id)}"
}Create a human-readable string from a list:
variable "subnet_ids" {
type = list(string)
default = ["subnet-abc", "subnet-def", "subnet-ghi"]
}
# Comma-separated
output "subnets_csv" {
value = "Subnets: ${join(", ", var.subnet_ids)}"
}
# Output: Subnets: subnet-abc, subnet-def, subnet-ghi
# Newline-separated
output "subnets_list" {
value = "Subnets:\n${join("\n", var.subnet_ids)}"
}
# Custom delimiter
output "subnets_pipe" {
value = join(" | ", var.subnet_ids)
}Reference specific items instead of the whole collection:
# Access list elements by index
output "first_subnet" {
value = "Primary subnet: ${var.subnet_ids[0]}"
}
# Access map values by key
output "env_tag" {
value = "Environment: ${var.tags["Environment"]}"
}
# Access resource attributes
output "instance_info" {
value = "Instance ${aws_instance.web.id} at ${aws_instance.web.private_ip}"
}# format() for printf-style strings
output "server_info" {
value = format("Server %s: type=%s, ip=%s",
aws_instance.web.id,
aws_instance.web.instance_type,
aws_instance.web.private_ip
)
}
# formatlist() for lists
output "tagged_subnets" {
value = formatlist("subnet: %s", var.subnet_ids)
}
# Output: ["subnet: subnet-abc", "subnet: subnet-def"]For longer templates with embedded logic:
# templates/config.tftpl
%{ for subnet in subnets ~}
subnet ${subnet}
%{ endfor ~}
# main.tf
resource "aws_instance" "web" {
user_data = templatefile("${path.module}/templates/config.tftpl", {
subnets = var.subnet_ids
tags = var.tags
})
}Template file syntax supports loops and conditionals:
# templates/hosts.tftpl
%{ for name, ip in servers ~}
${ip} ${name}
%{ endfor ~}
# Variables:
# servers = {"web" = "10.0.1.10", "db" = "10.0.2.20"}
# Output:
# 10.0.1.10 web
# 10.0.2.20 dbIf you're just passing a value, don't wrap it in a string template:
# BAD — unnecessary interpolation
output "subnet_id" {
value = "${var.subnet_ids[0]}"
}
# GOOD — direct reference
output "subnet_id" {
value = var.subnet_ids[0]
}
# BAD — interpolating a list into a list context
resource "aws_instance" "web" {
vpc_security_group_ids = ["${var.security_group_ids}"] # ERROR
}
# GOOD — direct reference
resource "aws_instance" "web" {
vpc_security_group_ids = var.security_group_ids
}| Source Type | To String | Function |
|---|---|---|
list(string) | "a, b, c" | join(", ", list) |
list(any) | '["a","b"]' | jsonencode(list) |
map(string) | '{"k":"v"}' | jsonencode(map) |
number | "42" | tostring(42) or just "${42}" |
bool | "true" | tostring(true) or just "${true}" |
object | JSON string | jsonencode(object) |
| Specific element | String | list[0] or map["key"] |
# User data script with list values
resource "aws_instance" "web" {
user_data = <<-EOF
#!/bin/bash
# Install packages
apt-get install -y ${join(" ", var.packages)}
# Set environment variables
%{ for key, value in var.env_vars ~}
export ${key}="${value}"
%{ endfor ~}
EOF
}
# Tags from a map
resource "aws_instance" "web" {
tags = merge(var.common_tags, {
Name = "web-server"
})
# Don't interpolate the map — pass it directly to tags
}
# Log output with multiple values
output "summary" {
value = format(
"Deployed %d instances in %s (VPC: %s)",
length(aws_instance.web),
var.region,
aws_vpc.main.id
)
}join() for a list?jsonencode() for a complex type?format() or templatefile() be cleaner?"${...}" — Terraform allows direct referencesjsonencode() as default for any complex type in a string contexttemplatefile() over heredoc for complex user data scriptsterraform validate — catches type errors without cloud API callsTerraform strings can only embed scalar values — not lists, maps, or objects. Use join() for lists, jsonencode() for complex types, format() for structured output, and templatefile() for scripts. Better yet, avoid unnecessary interpolation and pass values directly when the receiving argument accepts the correct type.
Fix the Terraform invalid function argument error. Covers type mismatches for join, lookup, cidrsubnet, file, and other built-in functions with examples.
Fix the Terraform inconsistent conditional result types error. Covers type conversion, null handling, tostring, tolist, and splitting complex conditionals.
Fix the Terraform 'Backend configuration changed' error. Migrate state between backends (local to S3, S3 to S3), resolve lock conflicts
Fix Terraform provider version conflicts between modules, lock files, and constraint mismatches. Resolve dependency lock errors, upgrade providers safely