Quick Answer
# 1. Check the module name matches
module "networking" { source = "./modules/vpc" }
# Use: module.networking.vpc_id (NOT module.vpc.vpc_id)
# 2. Check the output is declared in the module
# modules/vpc/outputs.tf must have:
output "vpc_id" { value = aws_vpc.main.id }
The Error
Error: Reference to undeclared module
on main.tf line 20:
20: vpc_id = module.vpc.vpc_id
No module call named "vpc" is declared in the root module.
Or:
Error: Unsupported attribute
on main.tf line 20:
20: vpc_id = module.networking.vpc_id
This object has no argument, nested block, or exported attribute named "vpc_id".
What Causes This
- Module name mismatch — calling it
module "networking"but referencingmodule.vpc - Output not declared — the module doesn’t have that output in
outputs.tf - Typo in output name —
vpc_idvsvpcIdvsVPC_id - Module not initialized — haven’t run
terraform init - count/for_each module — need
module.vpc[0]ormodule.vpc["key"]
Solution 1: Match Module Name to Reference
# The module block name is what you reference
module "networking" { # ← This is the name
source = "./modules/vpc"
}
# Reference uses the block name, NOT the source directory
resource "aws_instance" "web" {
subnet_id = module.networking.public_subnet_ids[0] # ✅
# NOT: module.vpc.public_subnet_ids[0] ❌
}
Solution 2: Declare the Output in the Module
If the output doesn’t exist in the module, add it:
# modules/vpc/outputs.tf
output "vpc_id" {
description = "ID of the VPC"
value = aws_vpc.main.id
}
output "public_subnet_ids" {
description = "List of public subnet IDs"
value = aws_subnet.public[*].id
}
output "private_subnet_ids" {
description = "List of private subnet IDs"
value = aws_subnet.private[*].id
}
Then re-init:
terraform init
terraform plan
Solution 3: Handle count/for_each Modules
module "vpc" {
count = var.create_vpc ? 1 : 0
source = "./modules/vpc"
}
# Must use index
resource "aws_instance" "web" {
subnet_id = module.vpc[0].public_subnet_ids[0] # ✅ with count
# NOT: module.vpc.public_subnet_ids[0] ❌
}
# Safe access
locals {
vpc_id = try(module.vpc[0].vpc_id, null)
}
module "vpc" {
for_each = var.vpcs
source = "./modules/vpc"
vpc_cidr = each.value.cidr
}
# Reference by key
resource "aws_instance" "web" {
subnet_id = module.vpc["production"].public_subnet_ids[0] # ✅ with for_each
}
Solution 4: Debug with terraform console
terraform console
# List all module outputs
> module.networking
# Check specific output
> module.networking.vpc_id
# List available outputs
> keys(module.networking)
Solution 5: Check Available Outputs
# List what the module exposes
grep -n "^output" modules/vpc/outputs.tf
3: output "vpc_id" {
8: output "vpc_cidr" {
13: output "public_subnet_ids" {
18: output "private_subnet_ids" {
If the output you need isn’t listed, add it.
Common Mistakes
# ❌ Using source path as module name
module "app" { source = "./modules/vpc" }
vpc_id = module.vpc.vpc_id # Wrong — name is "app"
# ❌ Missing outputs.tf in module
# The module has resources but no output blocks
# ❌ Output references non-existent resource
output "vpc_id" {
value = aws_vpc.this.id # But resource is named aws_vpc.main
}
# ❌ Referencing module before init
# terraform plan without terraform init
Hands-On Courses
- Terraform for Beginners on CopyPasteLearn
- Terraform By Example — practical code examples
Conclusion
Module output errors come from three places: wrong module name in the reference (use the module "name" block name, not the source path), missing output declaration in the module’s outputs.tf, or missing index on count/for_each modules. Debug with terraform console to inspect available outputs.
