Terraform「Error: Reference to undeclared output value」の修正方法 — モジュール出力が見つからない

intermediate🏗️ Terraform2026-03-22| Terraform CLI 1.x、任意のプロバイダー、Linux/macOS/Windows

Error Message

Error: Reference to undeclared output value
#terraform#output#参照#変数#構文

状況

深夜の作業中、新しいモジュールのVPC IDやARNを別のリソースに渡すよう設定して terraform plan を実行したところ、こんなエラーが出た:

Error: Reference to undeclared output value

  on main.tf line 14, in resource "aws_instance" "app":
  14:   subnet_id = module.network.subnet_id

An output value with the name "subnet_id" has not been declared in module.network.

モジュールは存在する。リソースも存在する。それでもTerraformは動かない — 参照しようとしているoutputが見つからないのだ。

なぜこのエラーが起きるのか

Terraformのモジュールはブラックボックスだ。外部に公開できる値は、モジュール内で明示的に output ブロックとして宣言されたものだけだ。 module.network.subnet_id を参照すると、TerraformはNetworkモジュールのディレクトリ内で output "subnet_id" ブロックを探す。ブロックがなければ値もなく、このエラーだけが残る。

主な原因はいくつかある:

  • 呼び出し元モジュールに参照を追加したが、子モジュールに output ブロックを宣言し忘れた。
  • outputブロックの名前を変更したが、それを参照しているすべての箇所を更新しなかった。
  • 別の場所からモジュールをコピーしたが、このバージョンには期待していたoutputが存在しない。
  • 名前が微妙に違う — たとえば subnet_ids(複数形)と subnet_id(単数形)のような違い。
  • terraform_remote_state でワークスペースをまたいでoutputを取得しようとしているが、そのoutputがソーススタックで宣言されていない。

ステップ1 — モジュールが実際に宣言しているoutputを確認する

まずモジュールの場所を特定する。ローカルモジュールの場合、エラーメッセージにヒントがある — module.network なら modules/network/ を確認する:

ls modules/network/
grep -r 'output' modules/network/

レジストリやGitから取得したモジュールの場合、キャッシュされたダウンロード先を確認する:

find .terraform/modules -name '*.tf' | xargs grep '^output'

モジュールが実際に持つすべての output ブロックが表示される。そのリストと参照している名前を比較すれば、不一致がすぐにわかるはずだ。

不足しているoutputブロックを追加する

モジュールを自分で管理している場合、修正は簡単だ。モジュールディレクトリ内にoutputを追加する — 通常は modules/network/outputs.tf

output "subnet_id" {
  description = "The ID of the primary subnet"
  value       = aws_subnet.main.id
}

再度 terraform plan を実行すれば、エラーは消える。

複数のサブネットを公開したい場合は、リスト形式のoutputを使う:

output "subnet_ids" {
  description = "List of all subnet IDs"
  value       = aws_subnet.main[*].id
}

呼び出し元の設定からインデックスで参照する:

subnet_id = module.network.subnet_ids[0]

outputは存在するが名前が違う場合

何かを編集する前に、モジュールが実際に公開している値を確認しよう。Terraformコンソールが便利だ:

terraform console
> module.network

モジュールの利用可能なoutputがすべて表示される。ほとんどの場合、名前の不一致がすぐに見つかる — あとは参照を修正するだけだ:

# 誤り
subnet_id = module.network.subnet_id

# 正しい — outputブロックは "private_subnet_id" という名前
subnet_id = module.network.private_subnet_id

リモートステート:ソーススタックにoutputが存在しない場合

terraform_remote_state を使って別のワークスペースからoutputを読み込もうとしている場合、そのoutputはソーススタックで宣言され、かつapply済みである必要がある。

data "terraform_remote_state" "vpc" {
  backend = "s3"
  config = {
    bucket = "my-tf-state"
    key    = "vpc/terraform.tfstate"
    region = "us-east-1"
  }
}

resource "aws_instance" "app" {
  subnet_id = data.terraform_remote_state.vpc.outputs.subnet_id
}

VPCスタックの outputs.tf にこれが必要だ:

output "subnet_id" {
  value = aws_subnet.main.id
}

まずVPCスタックをデプロイすること。Terraformはステートファイルから読み込むため、outputがapplyされていなければ存在しない。 .tf ファイルに記述するだけでは不十分だ。

パブリックレジストリのモジュール:そのバージョンにoutputが存在しない場合

古いバージョンのモジュールを固定している場合、目的のoutputがまだ存在しないことがある。 terraform-aws-modules でよくある問題で、バージョン3.xと5.xでは公開されているoutputが異なる。

module "network" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "3.0.0"  # 必要なoutputが存在しないバージョン
}

モジュールのchangelogを確認するか、GitHubで該当タグの outputs.tf を参照しよう。必要なoutputが新しいバージョンに存在するなら、バージョンを上げる:

module "network" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.1.0"
}

そして更新を取得する:

terraform init -upgrade

修正を確認する

以下の3つのコマンドを順番に実行する:

# まず構文エラーを確認
terraform validate

# エラーなしで完了するはず
terraform plan

# apply後にルートレベルのoutputをすべて確認
terraform output

applyする前に特定のモジュール参照を確認したい場合は、コンソールを使う:

terraform console
> module.network.subnet_id

値(または既知のプレースホルダー)が返ってくれば、参照は正しく接続されている。

クイックリファレンス

  • outputが別のファイルに宣言されている — モジュールディレクトリ内のどの .tf ファイルに output ブロックがあっても問題ない。モジュールディレクトリ内のどこかに存在していればよい。
  • センシティブなoutputsensitive = true を付けてもoutputの参照は壊れない。Terraformはplanの出力で値を非表示にするだけだ。
  • countまたはfor_eachを使うモジュール — outputの形式が変わる。 module.network.subnet_id の代わりに module.network[0].subnet_id として参照すること。

Related Error Notes