Terraform「Duplicate provider configuration」エラーをaliasなしの二重プロバイダーブロックで修正する方法

beginner🏗️ Terraform2026-07-17| Terraform CLI v1.x、任意のOS(Linux / macOS / Windows)、マルチリージョンまたはマルチアカウント構成のHCL providerブロック

Error Message

Error: Duplicate provider "aws" configuration A module may have only one "default" (non-aliased) provider configuration per provider type.
#terraform#provider#alias#設定#hcl

エラーのシナリオ

terraform plan — あるいは terraform validate を実行すると、Terraform が次のメッセージを出して突然停止します:

Error: Duplicate provider "aws" configuration

A module may have only one "default" (non-aliased) provider configuration per provider type.

プランは何も実行されず、適用も行われません。問題ないと思っていた設定が読み込みを拒否したのです。

これは主に次の3つの状況で発生します:

  • 別のファイルからプロバイダーブロックをコピー&ペーストした際、すでにそのブロックが存在するモジュールに貼り付けてしまった
  • Terraform の設定を複数の .tf ファイルに分割し、2つのファイルで同じプロバイダーを定義してしまった
  • main.tf にデフォルトのプロバイダーブロックがすでに存在することに気づかず、2つ目の AWS リージョン設定を追加してしまった

Terraform がこのエラーを出す理由

Terraform は、単一のモジュール内でプロバイダータイプごとに デフォルト のプロバイダーブロックを1つしか許可しません。デフォルトプロバイダーとは、alias 引数が設定されていない provider ブロックのことです。同じモジュール内に — どの .tf ファイルにあるかに関わらず — このようなブロックが2つ存在すると、Terraform はどちらをデフォルトとして使用すべきか判断できず、推測するのではなくエラーを出して停止します。

以下はエラーを再現する最小限の例です:

# main.tf
provider "aws" {
  region = "us-east-1"
}

# providers.tf — 同じモジュール、別のファイル
provider "aws" {
  region = "ap-southeast-1"
}

Terraform はディレクトリ内のすべての .tf ファイルを1つの論理モジュールにマージします。上記の両ブロックが aws のデフォルトプロバイダーになってしまい、それが競合を引き起こします。

クイックフィックス:2つ目のプロバイダーにエイリアスを追加する

2つの異なる AWS 設定(2つのリージョン、2つのアカウント、2セットの認証情報)が実際に必要な場合、1つのブロックをデフォルトのままにして、もう一方に alias を付与するのが解決策です。

# providers.tf
provider "aws" {
  region = "us-east-1"   # デフォルトプロバイダー — エイリアスなし
}

provider "aws" {
  alias  = "ap"
  region = "ap-southeast-1"
}

2つ目の設定を必要とするリソースは、provider 引数を使って明示的に参照します:

resource "aws_s3_bucket" "asia_logs" {
  provider = aws.ap
  bucket   = "my-asia-logs-bucket"
}

provider 引数のないリソースは、自動的にデフォルト(エイリアスなし)のブロックを使用します。エイリアス付きのプロバイダーを使用したい場合にのみ指定が必要です。

根本的な解決策:重複を削除する

AWS の設定が1つだけ必要な場合、本来の解決策は重複したブロックを完全に削除することです。まずすべての箇所を見つけます:

grep -rn 'provider "aws"' .

出力例は次のようになります:

./main.tf:1:provider "aws" {
./providers.tf:1:provider "aws" {

両方のファイルを開き、正しい設定がどちらにあるかを判断して、もう一方を削除します。そして、すべてを単一の信頼できるプロバイダーブロックに統合します — 慣例的な場所は providers.tf または versions.tf です:

# providers.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region  = "us-east-1"
  profile = "my-profile"
}

特殊ケース:子モジュール

子モジュールを呼び出す際に特定のプロバイダー設定を使用させたい場合は、providers マップを使ってルートからプロバイダーを渡します。子モジュールは独自の provider "aws" {} ブロックを定義すべきではなく、必要なものだけを宣言するようにします。

# ルートモジュール — 子を呼び出してプロバイダーを渡す
module "networking" {
  source = "./modules/networking"

  providers = {
    aws = aws.ap   # エイリアス付きプロバイダーを明示的に渡す
  }
}

# modules/networking/versions.tf — 要件のみを宣言し、完全なプロバイダーブロックは記述しない
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

子モジュール内に provider "aws" { region = ... } ブロックを追加すると、Terraform の観点からは2つ目のデフォルトプロバイダーが作成されます — サブディレクトリ内にあるため気づきにくいだけで、同じエラーが発生します。

確認手順

変更を加えた後、次の3つのコマンドを順番に実行してください:

# 1. 設定の構文と構造を検証する
terraform validate

# 2. プロバイダーの依存関係ツリーを確認する
terraform providers

# 3. プランが正常に実行されることを確認する
terraform plan

terraform validate の出力は次のようになるはずです:

Success! The configuration is valid.

terraform providers は、プロバイダーがどこから取り込まれているかを診断するのに特に役立ちます。子モジュールを含む完全なツリーが表示されるため、ネストされたモジュールに重複が隠れていても、ここで確認できます。

予防のヒント

最も効果的な習慣はひとつです:プロバイダーとバージョンの宣言をすべて1つのファイル(providers.tf または versions.tf)にまとめ、他の場所には絶対に provider ブロックを書かないことです。プロバイダーが1つのファイルにあるとチーム全員が把握していれば、誤って重複させてしまうことはほぼなくなります。

CI パイプラインに検証ステップを追加して、このエラーが誰かのローカル環境に届く前に検出できるようにしましょう:

# .github/workflows/terraform.yml (抜粋)
- name: Validate Terraform
  run: |
    terraform init -backend=false
    terraform validate

YAML と JSON 形式の変数ファイルが混在する設定を扱う場合 — 大規模な Terraform プロジェクトではよくあることですが — Terraform に渡す前に .tfvars や変数定義ファイルの構造をすばやく確認するのに、ToolCraft の YAML ↔ JSON Converter が便利です。完全にブラウザ上で動作し、何もアップロードされません。

Related Error Notes