This error occurs when you try to reference a list, tuple, or set value directly without specifying which element you want to access. Terraform requires an explicit index (like [0]) to access individual list elements.
In Terraform's HCL language, lists and tuples are ordered collections that must be accessed by index using bracket notation. When you reference a list variable or attribute without an index, Terraform cannot determine which element you want and throws this error. Additionally, sets (unordered collections) cannot be indexed at all - they must be converted to lists first using tolist() before accessing individual elements.
Use bracket notation with the element index (starting at 0) to access list values:
# ❌ Wrong - accessing list without index
variable "servers" {
type = list(string)
default = ["web-1", "web-2", "web-3"]
}
output "server_name" {
value = var.servers # Error: Cannot access without index
}
# ✓ Correct - specify which element to access
output "server_name" {
value = var.servers[0] # Returns "web-1"
}If accessing a set attribute, use tolist() to convert it to a list first:
# ❌ Wrong - trying to index a set
resource "aws_security_group" "example" {
# ...
}
output "first_tag" {
value = aws_security_group.example.tags[0] # Error: sets can't be indexed
}
# ✓ Correct - convert set to list then index
output "first_tag" {
value = tolist(aws_security_group.example.tags)[0]
}When you have multiple resources created with count and need to extract an attribute from all of them, use splat syntax:
# ❌ Wrong - trying to access list without index
resource "aws_instance" "servers" {
count = 3
# ...
}
output "all_ips" {
value = aws_instance.servers.private_ip # Error
}
# ✓ Correct - use splat syntax to get all values
output "all_ips" {
value = aws_instance.servers[*].private_ip # Returns ["10.0.1.1", "10.0.1.2", "10.0.1.3"]
}
# Or access a specific instance
output "first_ip" {
value = aws_instance.servers[0].private_ip
}When using data sources that return lists, verify the list isn't empty before accessing elements:
# ❌ Wrong - assuming list has elements
data "aws_subnets" "available" {
filter {
name = "vpc-id"
values = [aws_vpc.example.id]
}
}
output "subnet_id" {
value = data.aws_subnets.available.ids[0] # Fails if no subnets found
}
# ✓ Correct - verify with length() or use try()
output "subnet_id" {
value = length(data.aws_subnets.available.ids) > 0 ? data.aws_subnets.available.ids[0] : null
}
# Or use try() for graceful fallback
output "subnet_id" {
value = try(data.aws_subnets.available.ids[0], null)
}When passing list elements to resources that don't accept list types, use for_each to iterate:
variable "availability_zones" {
type = list(string)
default = ["us-east-1a", "us-east-1b", "us-east-1c"]
}
# ❌ Wrong - resource expects single AZ, not list
resource "aws_subnet" "example" {
availability_zone = var.availability_zones # Error
}
# ✓ Correct - use for_each to create one subnet per AZ
resource "aws_subnet" "example" {
for_each = toset(var.availability_zones)
availability_zone = each.value # References current AZ
# ...
}When using count to create multiple resources, use count.index to access the corresponding list element:
variable "instance_names" {
type = list(string)
default = ["web-1", "web-2", "web-3"]
}
# ❌ Wrong - passing entire list
resource "aws_instance" "servers" {
count = length(var.instance_names)
tags = {
Name = var.instance_names # Error: expects string, not list
}
}
# ✓ Correct - use count.index to access specific element
resource "aws_instance" "servers" {
count = length(var.instance_names)
tags = {
Name = var.instance_names[count.index] # Returns one name per instance
}
}Lists in Terraform are zero-indexed, meaning the first element is at index [0], the second at [1], etc. Sets are unordered collections that don't support indexing at all - always convert sets to lists with tolist() before accessing by index. The splat syntax [*] is particularly powerful for extracting attributes from multiple resources created with count. When working with dynamic blocks, remember that dynamic blocks create nested blocks within a resource, not new resources, so they follow different syntax rules. Use the element() function as an alternative way to access list items: element(var.my_list, 0) is equivalent to var.my_list[0].
Error: Error rendering template: template not found
How to fix "template not found" error in Terraform
Error: Error generating private key
How to fix 'Error generating private key' in Terraform
Error creating Kubernetes Service: field is immutable
How to fix "field is immutable" errors in Terraform
Error: Error creating local file: open: permission denied
How to fix "Error creating local file: permission denied" in Terraform
Error: line endings have changed from CRLF to LF
Line endings have changed from CRLF to LF in Terraform