Fixing the Terraform 'Invalid template interpolation value' Error

beginner๐Ÿ—๏ธ Terraform2026-06-07| Terraform CLI (v0.12+), Linux, macOS, or Windows

Error Message

Error: Invalid template interpolation value: the template interpolation at line X requires a string value, not object.
#terraform#devops#hcl#troubleshooting

The Problem

Terraform is usually smart about types, but it draws a hard line at string interpolation. You will likely hit this error during a plan or apply when you try to shove a complex data structure where a simple string belongs:

Error: Invalid template interpolation value

on main.tf line 42, in resource "aws_instance" "example":
42:   user_data = "echo ${var.config_map}"

|----------------
| var.config_map is object with 2 attributes

Cannot include the given value in a string template: string required.

The ${...} syntax has one job: injecting strings. If you pass it a list, map, or object, Terraform won't guess how to format it. It expects a flat string, and when it sees a multi-layered object instead, the process stops.

Common Scenarios

This isn't just a syntax quirk; it's a type mismatch. You'll often run into this when:

  • Passing a map of environment variables into a user_data shell script.
  • Trying to print a list of 5 private IP addresses into a configuration file.
  • Injecting an entire resource object into a tag or metadata field.

Three Ways to Fix It

The solution depends on how you want your data to look once it's converted. Here are the standard approaches.

1. Use jsonencode() for Maps and Objects

If your destination (like an SSM parameter or a config file) expects structured data, use jsonencode(). This turns your HCL object into a valid JSON string automatically.

The Wrong Way:

resource "aws_ssm_parameter" "config" {
  name  = "app_settings"
  type  = "String"
  value = "settings = ${var.my_map}" # This triggers the error
}

The Right Way:

resource "aws_ssm_parameter" "config" {
  name  = "app_settings"
  type  = "String"
  value = jsonencode(var.my_map) # Returns "{\"key\":\"value\"}"
}

2. Use join() for Lists

Lists are tricky. If you have a list of strings, you usually want to merge them with a separator like a comma or a space.

Example:

resource "aws_instance" "web" {
  # Join a list of 3 CIDR blocks into a single comma-separated string
  user_data = <<-EOT
    #!/bin/bash
    echo "Allowed Sources: ${join(", ", var.external_ips)}"
  EOT
}

3. Use HCL Directives for Complex Formatting

Sometimes jsonencode is too messy. If you are using templatefile() to generate a custom config (like an Nginx or HaProxy config), use a for loop directive inside the template itself.

Your template (config.tftpl):

%{ for name, ip in servers ~}
server ${name} ${ip}:8080
%{ endfor ~}

Your Terraform code:

content = templatefile("config.tftpl", { 
  servers = { "web01" = "10.0.1.5", "web02" = "10.0.1.6" }
})

Test Without Deploying

Don't wait for a slow terraform plan to see if your fix works. Use the built-in console for instant feedback:

  • Run terraform console in your terminal.
  • Type your logic: join(" | ", ["prod", "staging"]).
  • If it outputs "prod | staging", your interpolation is safe.

Expert Tips

  • Strict Typing: Define your variables clearly. Using type = map(string) catches errors at the input stage rather than failing mid-deployment.
  • YAML Support: If JSON is too bulky for your logs, yamlencode() works exactly like its JSON counterpart but outputs cleaner YAML.
  • Security: Be careful with jsonencode on objects containing secrets. If a variable is marked sensitive = true, Terraform will redact the entire string in your CLI output to keep passwords safe.

Related Error Notes