Fix lỗi Terraform 'Attempt to get attribute from null value' khi truy cập Resource hoặc Module Output

intermediate🏗️ Terraform2026-07-07| Terraform 0.14+, mọi cloud provider (AWS/GCP/Azure), Linux/macOS/Windows

Error Message

Error: Attempt to get attribute from null value This value is null, so it does not have any attributes.
#terraform#null#attribute#output#module#depends_on

Lỗi gặp phải

Error: Attempt to get attribute from null value

  on main.tf line 15, in resource "aws_route53_record" "api":
  15:   zone_id = module.dns.zone_id

This value is null, so it does not have any attributes.

Lỗi này xảy ra khi Terraform cố đọc một thuộc tính từ giá trị đã được tính toán thành null. Chín trong mười trường hợp, nguyên nhân là do resource có điều kiện được kiểm soát bởi count = 0 hoặc for_each = {}. Nguồn gốc phổ biến còn lại: một output của module trả về null vì resource bên trong không được tạo ra do điều kiện biến không thỏa mãn.

Nguyên nhân

1. Resource có điều kiện dùng count

resource "aws_eip" "nat" {
  count = var.enable_nat ? 1 : 0
}

resource "aws_nat_gateway" "main" {
  allocation_id = aws_eip.nat.id  # fails when count = 0
}

Khi count = 0, aws_eip.nat trở thành một danh sách rỗng, không phải một object đơn lẻ. Truy cập .id trực tiếp trên một danh sách sẽ trả về null. Giá trị null đó sau đó gây ra lỗi ở lần truy cập thuộc tính tiếp theo.

2. Module trả về output null

module "ssl" {
  source  = "./modules/ssl"
  enabled = var.use_ssl
}

resource "aws_lb_listener" "https" {
  certificate_arn = module.ssl.certificate_arn  # null when ssl not enabled
}

Nếu module tạo certificate có điều kiện thông qua count bên trong, output của nó sẽ là null khi bị tắt. Nơi gọi không biết điều này — nó chỉ thấy null.

3. Data source không có kết quả phù hợp

data "aws_vpc" "existing" {
  filter {
    name   = "tag:Name"
    values = ["my-vpc"]
  }
}

resource "aws_subnet" "main" {
  vpc_id = data.aws_vpc.existing.id  # null if VPC tag doesn't exist
}

Một số data source trả về null cho các thuộc tính cụ thể khi không có resource phù hợp. Một số khác thì báo lỗi hoàn toàn. Dù trong trường hợp nào, việc đọc .id từ một object null đều kích hoạt chính xác lỗi này.

Các cách sửa lỗi

Cách 1: Dùng one() cho resource dựa trên count

one() chuyển đổi một danh sách có không hoặc một phần tử thành một giá trị hoặc null. Không có lỗi truy cập index, không có bất ngờ:

# Thay vì:
allocation_id = aws_eip.nat.id

# Dùng:
allocation_id = one(aws_eip.nat[*].id)

# Với giá trị dự phòng:
allocation_id = one(aws_eip.nat[*].id) != null ? one(aws_eip.nat[*].id) : ""

Cách 2: Bọc bằng try()

try() đánh giá biểu thức và trả về giá trị dự phòng nếu bất kỳ phần nào trong chuỗi gây lỗi — rất phù hợp cho các output module tùy chọn:

certificate_arn = try(module.ssl.certificate_arn, null)

# Cũng hoạt động cho các chuỗi lồng nhau sâu:
subnet_id = try(module.network.subnets["private-a"].id, null)

Chọn null làm giá trị dự phòng khi thuộc tính là tùy chọn. Cần giá trị cụ thể hơn? Dùng một giá trị mặc định thực — chuỗi rỗng, ID placeholder, bất cứ thứ gì resource chấp nhận.

Cách 3: Kiểm tra null tường minh bằng điều kiện

# Mẫu: condition ? value : fallback
vpc_id = var.existing_vpc_id != null ? var.existing_vpc_id : aws_vpc.new.id

# Cho module outputs:
certificate_arn = module.ssl.certificate_arn != null ? module.ssl.certificate_arn : ""

Cách 4: Sửa output của module trực tiếp

Khi null xuất phát từ bên trong module, hãy sửa định nghĩa output. Đừng chỉ vá víu ở nơi gọi:

# modules/ssl/outputs.tf

# Trước — gây lỗi khi count = 0:
output "certificate_arn" {
  value = aws_acm_certificate.cert[0].arn
}

# Sau — an toàn với mọi giá trị count:
output "certificate_arn" {
  value = length(aws_acm_certificate.cert) > 0 ? aws_acm_certificate.cert[0].arn : null
}

Lúc này nơi gọi dùng try(module.ssl.certificate_arn, null) và cả hai phía đều rõ ràng về những gì chúng xử lý.

Cách 5: Thêm depends_on cho vấn đề thứ tự giữa các module

Trong các chuỗi module phức tạp, đôi khi Terraform đánh giá một tham chiếu trước khi resource upstream hoàn toàn được giải quyết. Cách này không sửa được null mang tính cấu trúc từ count = 0, nhưng giúp xử lý vấn đề thứ tự trong đồ thị nhiều module:

resource "aws_nat_gateway" "main" {
  allocation_id = one(aws_eip.nat[*].id)
  subnet_id     = aws_subnet.public.id

  depends_on = [aws_eip.nat]
}

Kiểm tra sau khi sửa

Chạy lại terraform plan với đúng tổ hợp biến đã gây ra lỗi:

# Kích hoạt với flag đã gây lỗi:
terraform plan -var="enable_nat=false"

# Hoặc với file tfvars:
terraform plan -var-file="prod.tfvars"

Nếu không còn Error: Attempt to get attribute trong output — bạn đã xong. Muốn kiểm tra kỹ hơn biểu thức? Mở terraform console:

terraform console
> try(module.ssl.certificate_arn, "fallback")
# Trả về "fallback" hoặc ARN thực — không bao giờ báo lỗi

Lưu ý

  • try() vs điều kiện: Dùng try() khi toàn bộ biểu thức có thể gây lỗi — chuỗi thuộc tính lồng nhau, biểu thức splat trên các kiểu không xác định. Dùng condition ? a : b khi bạn kiểm tra một biến cụ thể có null hay không.
  • one() thay vì [0]: resource.example[0].id gây lỗi với danh sách rỗng. one(resource.example[*].id) trả về null an toàn — luôn ưu tiên dùng cách này cho resource dựa trên count.
  • Đừng che giấu lỗi thực sự: Nếu resource đó đáng lẽ phải tồn tại, thì null là lỗi cấu hình. Hãy tìm nguyên nhân gốc rễ thay vì bọc mọi thứ trong try().
  • Ghi chú các output có thể null: Thêm comment vào outputs.tf ghi rõ output nào có thể là null. Điều này sẽ giúp người tiếp theo tiết kiệm 20 phút debug.
  • Kiểm tra terraform.tfvars: Lỗi này phụ thuộc vào môi trường. Một plan chạy được ở dev lại bị lỗi ở prod khi chỉ một flag khác nhau. Luôn tái hiện lỗi với đúng tổ hợp biến từ môi trường đang gặp lỗi.

Related Error Notes